Skip to content

docs: cover three user-visible reliability fixes from PraisonAI PR #3960 (async cascade, tool executor recycling, doom-loop recency) #2960

Description

@MervinPraison

Summary

PraisonAI PR #3960 landed three focused correctness fixes in praisonaiagents on 2026-08-15. Each is user-visible (behaviour that changes what an agent does at runtime), and none is currently reflected in the docs. This issue is a single, well-scoped ask so the docs agent can update the right pages in one pass.

Every SDK claim below has been verified against merged source at commit 4c202929717a34838d3eb3f86d2448f21020bd9d on main. All target pages live under docs/features/ or docs/configuration/ — nothing in docs/concepts/ should be touched (per repo AGENTS.md).

Upstream source of truth:


Fix 1 · asequential() failure-cascade parity (async processes)

What changed (verified against praisonaiagents/process/process.py):
The sync sequential() already skips a task whose upstream dependency permanently failed (dependency-cascade check). Before this PR, the async equivalent asequential() — used by astart(), the default async entry point — did not, so a task could try to run against context data its upstream had never produced. Now asequential() mirrors sequential(): it short-circuits failed tasks and cascades a "skipped: upstream failed" outcome down the dependency chain.

User impact. An astart() run with a failing early task now stops the cascade cleanly instead of letting downstream tasks run with empty / missing context. Users who saw async runs producing garbage outputs after an upstream failure will see clean skip outcomes instead.

Docs to update. The one existing page that explicitly names asequential / astart is:

  • docs/concepts/process.mdx — search results show it mentions asequential in a CardGroup with astart(). DO NOT edit this file (concepts folder is human-approved only). Instead:
  • Create docs/features/async-process-cascade.mdx — a short user-facing page explaining that asequential() / astart() now match the sync path's failure-cascade behaviour. Add a Note linking back from the concepts page in a follow-up human review.
  • Alternatively, update an existing async-focused page under docs/features/ (e.g. docs/features/async.mdx if it exists — check first) to add a ## Failure cascade in asequential()`` section.

Content the page must contain:

  • One-sentence lead: "asequential() now skips downstream tasks whose upstream dependency permanently failed, matching what sequential() already did."
  • A tiny agent-centric example: three tasks (A → B → C), A fails, show that with the fix B and C are marked as "skipped: upstream failed" instead of running against empty context.
  • A sequenceDiagram mermaid showing: astart → task A (fails) → check cascade → skip B → skip C.
  • Link back to PR #3960 for provenance.

Fix 2 · Tool executor pool recycling on tool_timeout

What changed (verified against praisonaiagents/agent/tool_execution.py):
Before this PR, when a tool call hung past tool_timeout, future.cancel() could not stop a thread that had already started, so the hung worker permanently occupied one of the pool's 2 worker slots. Two consecutive hangs would deadlock the pool. Now, on timeout, the executor is shutdown(wait=False) and dropped; the next tool call spins up a fresh executor with a fresh worker.

User impact. Any long-running agent that occasionally hits tool_timeout (network stalls, misbehaving APIs, unresponsive shells) is now self-healing at the pool level rather than progressively degrading toward a deadlock. This directly affects users who set aggressive tool_timeout values on flaky third-party tools.

Docs to update:

  • docs/configuration/tool-config.mdx — the existing tool_timeout documentation. Add a short <Note> (or a "Reliability after a timeout" subsection) explaining pool recycling.
  • docs/features/yaml-configuration-reference.mdx — the tool_timeout row already documents behaviour extensively. Append one sentence: "When a tool call exceeds the timeout the executor pool is recycled — the next call gets a fresh worker so a hung tool cannot progressively degrade throughput. See PR #3960."
  • docs/features/concurrency.mdx (if present — check first, this is referenced from yaml-configuration-reference.mdx) — add a short callout to the timeout-precedence table.

Content the note must contain:

  • One-sentence lead: "A tool that hangs past tool_timeout no longer holds its worker slot — the pool is recycled and the next call starts on a fresh worker."
  • Explicit statement: "The pool has 2 workers by default; before this fix, two consecutive hangs would deadlock the pool."
  • Link back to PR #3960 for provenance.

Fix 3 · Doom-loop NO_PROGRESS recency filter

What changed (verified against praisonaiagents/escalation/doom_loop.py):
Before this PR, _check_no_progress() counted every progress marker for the whole session (there was a literal # Could add timestamp filtering TODO). So one early successful tool call disabled NO_PROGRESS detection for the rest of the run, no matter how long the agent then spun on unproductive work. Now markers are stored as (marker, timestamp) tuples and only markers within the current no-progress window (the boundary is the timestamp of the action immediately preceding the window) are counted.

User impact. NO_PROGRESS doom-loop detection actually fires now on runs where one early success previously suppressed it forever. Long-running autonomous agents will exit stuck states via the recovery path instead of burning the full iteration budget silently.

Important context for the docs agent: There are two separate loop-detection subsystems in this codebase, and they are easy to confuse:

Subsystem Module Docs page
Result-aware tool-loop detection (per-Agent, always-on, checks tool call fingerprints) praisonaiagents/agent/loop_detection.pyLoopDetectionConfig, LoopDetector docs/features/doom-loop-detection.mdx (existing)
Escalation doom-loop detection (session-level, records actions + progress markers, recommends RecoveryAction) praisonaiagents/escalation/doom_loop.pyDoomLoopConfig, DoomLoopDetector, DoomLoopType.NO_PROGRESS No user-facing page — only auto-generated SDK reference at docs/sdk/reference/praisonaiagents/{classes,modules,functions}/DoomLoop*

PR #3960's fix is on the escalation subsystem — the one that currently has no user-facing page. docs/features/autonomy-loop.mdx references doom_loop_threshold (via AutonomyConfig) and the doom_loop completion reason, but does not explain the escalation DoomLoopDetector itself.

Docs to update:

  • Create docs/features/escalation-doom-loop.mdx — a new page that finally covers the escalation subsystem end-to-end (the six DoomLoopType values, the RecoveryAction ladder CONTINUE → RETRY_DIFFERENT → ESCALATE_MODEL → REQUEST_HELP → ABORT, the DoomLoopConfig thresholds). This gives Fix 3 a natural home. Place under docs/features/, not docs/concepts/.
  • Update docs/features/autonomy-loop.mdx — the doom_loop_threshold row and doom_loop completion-reason accordion. Add a one-line note that NO_PROGRESS now uses a recency window (early markers no longer suppress it) and link to the new escalation page.
  • Cross-link from docs/features/doom-loop-detection.mdx — add a <Note> at the top disambiguating the two subsystems and linking to the new escalation page, so users landing on the wrong page get redirected.

Content the new escalation page must contain:

  • Frontmatter: title: "Escalation Doom-Loop Detection", sidebarTitle: "Escalation Doom-Loop", icon: "shield-halved".
  • Hero mermaid diagram (LR) showing: Actions/markers → DoomLoopDetector → DoomLoopType → RecoveryAction.
  • Quick Start (<Steps>): (1) construct with defaults, (2) record actions + progress markers, (3) check is_doom_loop() / get_recovery_action().
  • Table of the six DoomLoopType enum values (REPEATED_ACTION, REPEATED_FAILURE, NO_PROGRESS, CIRCULAR_PLAN, RESOURCE_EXHAUSTION, REPEATED_OUTPUT) with what each detects.
  • Table of the five RecoveryAction enum values (CONTINUE, RETRY_DIFFERENT, ESCALATE_MODEL, REQUEST_HELP, ABORT) with when each is chosen (verified from _determine_recovery_action: first attempt → RETRY_DIFFERENT; second attempt with escalate_on_loop=TrueESCALATE_MODEL; then REQUEST_HELP; RESOURCE_EXHAUSTION always → ABORT; _recovery_attempts >= max_recovery_attemptsABORT).
  • Configuration table for DoomLoopConfig (verified from source):
    • max_identical_actions: int = 3
    • max_similar_actions: int = 5
    • max_consecutive_failures: int = 3
    • max_no_progress_steps: int = 5
    • max_time_per_action: float = 60.0
    • max_total_time: float = 300.0
    • enable_auto_recovery: bool = True
    • max_recovery_attempts: int = 2
    • escalate_on_loop: bool = True
    • initial_backoff: float = 1.0
    • backoff_multiplier: float = 2.0
    • max_backoff: float = 30.0
    • max_repeated_chunks: int = 8
    • content_chunk_size: int = 50
    • Note that similarity_threshold: float = 0.85 is kept for backward compatibility only and is not consulted (the docstring in source is explicit about this).
  • A "How progress markers work" section covering the PR #3960 recency-filter fix explicitly. Include the concrete example: an early mark_progress("read config.yaml") no longer suppresses NO_PROGRESS for the rest of the run — markers older than the current window boundary are filtered out.
  • Best-practices <AccordionGroup> (call mark_progress() on real progress, not just any log line; keep max_no_progress_steps small enough to catch stalls quickly).

Placement checklist (per repo AGENTS.md)

  • Any new file goes under docs/features/ (or docs/configuration/ for Fix 2's tool-config sibling). Nothing under docs/concepts/.
  • Update docs.json to add new pages under the Features group, never under Concepts.
  • Every page follows the standard template: frontmatter → hero mermaid → Quick Start (<Steps>) → How It Works → Configuration Options table → Common Patterns → Best Practices (<AccordionGroup>) → Related (<CardGroup>).
  • Mermaid diagrams use the standard palette (#8B0000, #189AB4, #10B981, #F59E0B, #6366F1) with white text and #7C90A0 stroke.
  • Every code example is copy-paste runnable with real imports (from praisonaiagents import Agent etc.). No placeholder values.
  • Every SDK claim in the docs matches merged source at mervinpraison/praisonai@main. Re-verify by reading the linked source files above before writing.

Out of scope

  • Do not rework docs/features/doom-loop-detection.mdx beyond adding the disambiguation <Note> — that page correctly documents the result-aware subsystem and its content is accurate as of PR #3005 / #3877.
  • Do not modify the auto-generated SDK reference under docs/sdk/reference/** — those pages are regenerated from source.
  • Do not touch the TypeScript (docs/js/) or Rust (docs/rust/) trees — those are managed by the parity system.

Filed by the docs-triage scheduled routine on 2026-08-16. Verified against upstream commit 4c202929717a34838d3eb3f86d2448f21020bd9d.

Metadata

Metadata

Assignees

No one assigned

    Labels

    claudeTrigger Claude Code analysisdocumentationImprovements or additions to documentation

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions