Skip to content

fix: enforce hierarchical id send-back, async tool timeout, and policy-string guardrails - #3790

Open
praisonai-triage-agent[bot] wants to merge 2 commits into
mainfrom
claude/issue-3789-20260808-0713
Open

fix: enforce hierarchical id send-back, async tool timeout, and policy-string guardrails#3790
praisonai-triage-agent[bot] wants to merge 2 commits into
mainfrom
claude/issue-3789-20260808-0713

Conversation

@praisonai-triage-agent

@praisonai-triage-agent praisonai-triage-agent Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #3789

Summary

Three distinct, independently-verified defects in praisonaiagents core, each reachable via documented first-class usage. All fixes are minimal and backward-compatible.

1. process="hierarchical" — manager id never sent back into the generator

ahierarchical()/hierarchical() use the two-way generator protocol (manager_task_id = yield manager_task) but both consumers in agents/agents.py drove them with plain for/async for, which only calls __next__()/send(None). So manager_task_id was permanently None, defeating the manager-task exclusion filter and the anti-self-delegation guard.
Fix: drive both generators manually with next()/gen.send(task_id) (sync) and __anext__()/gen.asend(task_id) (async), sending the real id back on the first yield.

2. execute_tool_async ignored the tool timeout

The sync path enforces ToolConfig.timeout, but _execute_tool_async_impl never read _tool_timeout, so a hung tool under achat()/async workflows hung the coroutine forever.
Fix: wrap the invocation in asyncio.wait_for(..., timeout=self._tool_timeout) and return the same {"error": ..., "timeout": True} shape on timeout.

3. GuardrailConfig.policy/.policies were silently unenforced

The documented guardrails=["policy:strict", "pii:redact"] shorthand and GuardrailConfig.policy/.policies fields have no enforcement path — construction succeeded with zero enforcement.
Fix (minimal, no new subsystem): raise a clear ValueError pointing users to the working Agent(policy=PolicyEngine(...)) param, so silent no-enforcement is never the default. Also corrected the misleading GuardrailConfig docstring. Non-policy presets ("strict", ["strict", {...}], validator/llm_validator configs) are unaffected.

Test plan

  • tests/unit/config/test_agent_centric_enhancements.py — 27 passed
  • tests/unit/config/test_param_resolver_comprehensive.py + test_precedence_ladder.py — 65 passed
  • tests/unit/workflows/test_workflow_hierarchical.py — 12 passed
  • tests/test_tool_timeout.py — passed (1 unrelated failure requires litellm, not installed in CI sandbox)
  • Functional checks: async timeout cuts off after configured seconds; generator two-way protocol sends real id back; all three guardrail policy cases raise ValueError while valid presets still build

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Asynchronous tools now stop after the configured timeout and return a clear timeout error.
    • Hierarchical task execution now correctly tracks delegated tasks and prevents invalid self-delegation.
    • Guardrail configuration now clearly rejects unsupported policy-string formats with actionable guidance.
  • Documentation

    • Updated guardrail examples to show supported validator and policy configuration options.

@MervinPraison

Copy link
Copy Markdown
Owner

@coderabbitai review

@MervinPraison

Copy link
Copy Markdown
Owner

/review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2cae66fb-c60d-44b5-972a-6c8f794d5c76

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR validates unsupported guardrail policy configurations, adds timeout handling for asynchronous tools, and updates synchronous and asynchronous hierarchical task execution to send assigned task IDs back into process generators.

Changes

Agent execution controls

Layer / File(s) Summary
Guardrail policy validation
src/praisonai-agents/praisonaiagents/agent/agent.py, src/praisonai-agents/praisonaiagents/config/feature_configs.py
Policy-string guardrails and GuardrailConfig.policy or .policies now raise clear ValueErrors. Documentation directs tool policy enforcement to the dedicated policy parameter.
Async tool timeout enforcement
src/praisonai-agents/praisonaiagents/agent/execution_mixin.py
Async and synchronous tools use a shared coroutine. Configured timeouts return structured errors with timeout=True.
Hierarchical task ID feedback
src/praisonai-agents/praisonaiagents/agents/agents.py
AgentTeam.run_all_tasks and arun_all_tasks manually drive process generators, register yielded tasks, execute them, and send assigned task IDs back into the generators.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Agent
  participant ExecutionMixin
  participant Tool
  Agent->>ExecutionMixin: invoke tool
  ExecutionMixin->>Tool: execute through shared coroutine
  ExecutionMixin-->>Agent: return result or timeout error
Loading
sequenceDiagram
  participant AgentTeam
  participant ProcessGenerator
  participant TaskRegistry
  participant TaskExecutor
  AgentTeam->>ProcessGenerator: request next task
  ProcessGenerator-->>AgentTeam: yield task
  AgentTeam->>TaskRegistry: register task
  AgentTeam->>TaskExecutor: execute task
  TaskExecutor-->>AgentTeam: assigned task ID
  AgentTeam->>ProcessGenerator: send task ID
Loading

Possibly related PRs

Suggested labels: pipeline/awaiting-merge-gate, pipeline/reviews-pending

Suggested reviewers: mervinpraison

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR fixes hierarchical ID handling, async timeouts, and clear guardrail failures, but does not show circuit-breaker or loop-guard enforcement and does not wire supported policies. Implement async-safe circuit-breaker and loop-guard protections, and wire supported GuardrailConfig.policy/policies and documented policy guardrails into enforcement.
Out of Scope Changes check ⚠️ Warning The PR changes feature documentation, but issue #3789 explicitly limits scope to the core SDK and excludes documentation changes. Remove the documentation changes from this PR or update the linked issue scope to include the required GuardrailConfig documentation clarification.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the three primary fixes: hierarchical ID send-back, async tool timeouts, and policy-string guardrails.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/issue-3789-20260808-0713

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR fixes hierarchical generator ID send-back, makes async tool timeouts non-retryable, and rejects unsupported policy-string guardrail configurations.

  • Manually drives hierarchical generators so assigned manager-task IDs are sent back.
  • Applies configured timeouts to async tool execution and prevents retries after uncancellable executor timeouts.
  • Fails loudly when callers provide policy guardrail forms that have no enforcement path.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/praisonai-agents/praisonaiagents/agent/agent.py Rejects unsupported policy-string and GuardrailConfig policy configurations instead of silently accepting unenforced policies.
src/praisonai-agents/praisonaiagents/agent/execution_mixin.py Enforces async tool timeouts and marks uncancellable timeout results non-retryable, resolving the previously reported duplicate-execution path.
src/praisonai-agents/praisonaiagents/agents/agents.py Manually drives synchronous and asynchronous hierarchical generators so generated task IDs are returned through the two-way protocol.
src/praisonai-agents/praisonaiagents/config/feature_configs.py Updates guardrail documentation to direct tool-policy enforcement through the supported policy parameter.

Reviews (3): Last reviewed commit: "fix: make async tool timeout non-retryab..." | Re-trigger Greptile

Comment thread src/praisonai-agents/praisonaiagents/agent/execution_mixin.py Outdated
@MervinPraison

Copy link
Copy Markdown
Owner

@claude You are the FINAL architecture reviewer. If the branch is under MervinPraison/PraisonAI (not a fork), you are able to make modifications to this branch and push directly. SCOPE: Focus ONLY on Python packages (praisonaiagents, praisonai). Do NOT modify praisonai-rust or praisonai-ts. Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.

Phase 1: Review per AGENTS.md

  1. Protocol-driven: check heavy implementations vs core SDK
  2. Backward compatible: ensure zero feature regressions
  3. Performance: no hot-path regressions
  4. SDK value: review in depth whether the change genuinely adds value to the SDK — never add features for the sake of adding them. It must strengthen the SDK (simpler, more user-friendly, robust, world-class, secure). If it does not clearly add value, request changes or recommend rejecting/closing rather than merging scope creep
  5. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params.
  6. Repo routing: agent-callable tools → PraisonAI-Tools; lifecycle plugins → PraisonAI-Plugins; optional sandbox backends → PraisonAI-Plugins (praisonai.sandbox entry point) — request changes if wrongly added to praisonaiagents/

Phase 2: FIX Valid Issues
7. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix
8. Also independently identify and fix any gaps or issues you find in the changed code — do not rely only on prior reviewer feedback
9. Push all code fixes directly to THIS branch (do NOT create a new PR)
10. Comment a summary of exact files modified and what you skipped

Phase 3: Final Verdict
11. If all issues are resolved, approve the PR / close the Issue
12. If blocking issues remain, request changes / leave clear action items

@MervinPraison MervinPraison added pipeline/awaiting-merge-gate FINAL done; waiting for merge gate / CI pipeline/blocked:cooldown Blocked: post-push or @claude cooldown and removed pipeline/final-claude-pending Reviews done; waiting for FINAL @claude pipeline/blocked:no-final Blocked: no FINAL @claude trigger yet labels Aug 8, 2026
@praisonai-triage-agent

praisonai-triage-agent Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

Claude finished @MervinPraison's task —— View job


Final Architecture Review — PR #3790

  • Read AGENTS.md & CLAUDE.md guidelines
  • Review all 4 changed files
  • Evaluate Greptile P1: async timeout retry duplicate execution → VALID
  • Fix: make async tool timeout non-retryable to prevent duplicate side effects
  • Run tests (7/8 timeout, 12/12 hierarchical, 27/27 config; only pre-existing litellm skip)
  • Push & post verdict

Phase 1 — Architecture Review (per AGENTS.md)

All three fixes are protocol-respecting, minimal, backward-compatible, add no new Agent params, deps, or exports, and touch only praisonaiagents/ core (correct routing — these are core-behavior bugs, not tools/plugins). No scope creep; each fix closes a real "silent failure" and genuinely strengthens the SDK.

Fix Verdict
1. Hierarchical id send-back (agents.py) ✅ Correct. Driving the two-way generator with next()/gen.send(id) (sync) and __anext__()/gen.asend(id) (async) is the right protocol; a plain for/async for only ever sends None, so manager_task_id stayed None and the self-delegation guard was dead. Verified by 12/12 hierarchical tests.
2. Async tool timeout (execution_mixin.py) ✅ Correct after this review's fix (see below). Brings achat()/async parity with the sync path's ToolConfig.timeout.
3. Policy-string guardrails (agent.py, feature_configs.py) ✅ Correct. Fail-loud ValueError for unenforced guardrails=["policy:..."] / GuardrailConfig.policy/.policies is a "safe-by-default" win — no new subsystem, valid presets/validators unaffected. 27/27 config tests pass.

Phase 2 — Valid issue found & fixed

Greptile P1 (async timeout retries duplicate tool execution) — CONFIRMED & FIXED.
The async retry loop _execute_tool_async_with_retry classifies {"timeout": True} as "timeout", and the default RetryPolicy.retry_on includes "timeout" (max_attempts=3). Since asyncio.wait_for cannot cancel a sync tool already running in the executor, each retry launched a duplicate invocation while the original kept running → duplicate DB writes / API calls / file mutations.

Fix (execution_mixin.py, 1331d3657):

  • Tag the async timeout result with "retryable": False.
  • Short-circuit it in the retry loop alongside approval_denied / circuit_open.

Verified with a targeted harness:

  • Before (no marker, control): impl invoked on timeout.
  • After: impl invoked exactly 1×, result surfaced once. ✅

This is strictly safer than — and independent of — the pre-existing sync path, whose identical future.cancel() caveat is out of scope for this PR.

Skipped (intentionally)

  • Sync path timeout-retry behavior — pre-existing, unchanged by this PR, not in scope.
  • No new params/modules — kept lightweight per AGENTS.md.
  • praisonai-rust / praisonai-ts — out of scope.

Files modified this review

  • src/praisonai-agents/praisonaiagents/agent/execution_mixin.py (+15/−3) — non-retryable async timeout.

Phase 3 — Verdict

APPROVE. All three original fixes are sound and the one valid blocking issue (Greptile P1) is resolved and verified. No remaining blocking issues. Ready to merge once CI is green.
• Branch: claude/issue-3789-20260808-0713

@MervinPraison MervinPraison added pipeline/blocked:stale-final Blocked: FINAL stale after new commits and removed pipeline/blocked:stale-final Blocked: FINAL stale after new commits labels Aug 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/praisonai-agents/praisonaiagents/agent/execution_mixin.py (1)

1510-1510: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use structured timeout logging with correlation fields.

Line 1510 uses a formatted logging.warning() message. Use the module logger with structured fields for function_name, tool_timeout, and available agent, run, and session identifiers.

As per coding guidelines, src/praisonai-agents/praisonaiagents/agent/**/*.py must use structured logging with correlation IDs.

Suggested logging change
-                        logging.warning(f"Tool {function_name} timed out after {tool_timeout}s")
+                        logger.warning(
+                            "Tool execution timed out",
+                            extra={
+                                "tool_name": function_name,
+                                "timeout_s": tool_timeout,
+                                "agent_name": self.name,
+                                "run_id": getattr(self, "_current_run_id", None),
+                                "session_id": getattr(self, "_session_id", None),
+                            },
+                        )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/praisonai-agents/praisonaiagents/agent/execution_mixin.py` at line 1510,
Replace the formatted logging.warning call in the timeout-handling path with the
module logger’s structured warning API. Record function_name and tool_timeout as
structured fields, and include any available agent, run, and session correlation
identifiers from the surrounding execution context.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/praisonai-agents/praisonaiagents/agent/agent.py`:
- Around line 1446-1449: Provide a working policy migration path before
publishing these messages: update the Agent policy guidance at
src/praisonai-agents/praisonaiagents/agent/agent.py:1446-1449 and the
GuardrailConfig guidance at
src/praisonai-agents/praisonaiagents/agent/agent.py:1475-1478 to reference an
existing supported API, or add a valid policy entry point to Agent.__init__.
Align the policy-related example and field documentation at
src/praisonai-agents/praisonaiagents/config/feature_configs.py:508-509 with the
same supported API.

In `@src/praisonai-agents/praisonaiagents/agent/execution_mixin.py`:
- Around line 1508-1511: Update _execute_tool_async_with_retry() to distinguish
its own deadline from asyncio.TimeoutError raised by the tool: create and retain
an owned task for _invoke(), enforce the timeout using an explicit deadline
pattern matching _astart_with_outcome(), then call task.result() after
completion so tool-raised exceptions flow through normal error handling. Only
return the timeout response when the locally enforced deadline expires.

---

Nitpick comments:
In `@src/praisonai-agents/praisonaiagents/agent/execution_mixin.py`:
- Line 1510: Replace the formatted logging.warning call in the timeout-handling
path with the module logger’s structured warning API. Record function_name and
tool_timeout as structured fields, and include any available agent, run, and
session correlation identifiers from the surrounding execution context.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1168dbc3-4b92-4fab-9784-83da435afcee

📥 Commits

Reviewing files that changed from the base of the PR and between 2aa2348 and 4ded0eb.

📒 Files selected for processing (4)
  • src/praisonai-agents/praisonaiagents/agent/agent.py
  • src/praisonai-agents/praisonaiagents/agent/execution_mixin.py
  • src/praisonai-agents/praisonaiagents/agents/agents.py
  • src/praisonai-agents/praisonaiagents/config/feature_configs.py

Comment on lines +1446 to +1449
raise ValueError(
f"Policy-string guardrails {_policy_strs} are not enforced. "
"Use Agent(policy=PolicyEngine(...)) for tool policy enforcement, "
"or pass a validator via guardrails=... / GuardrailConfig(validator=...)."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Expose or replace the policy API before publishing this guidance.

The new errors and documentation direct callers to Agent(policy=PolicyEngine(...)), but the reviewed Agent.__init__ does not accept policy. Following this guidance raises TypeError, so users have no working migration path from rejected guardrail policy settings.

  • src/praisonai-agents/praisonaiagents/agent/agent.py#L1446-L1449: point to an existing supported API or wire a policy entry point.
  • src/praisonai-agents/praisonaiagents/agent/agent.py#L1475-L1478: apply the same correction to the GuardrailConfig error.
  • src/praisonai-agents/praisonaiagents/config/feature_configs.py#L508-L509: align the example and policy-related field documentation with the supported API.
📍 Affects 2 files
  • src/praisonai-agents/praisonaiagents/agent/agent.py#L1446-L1449 (this comment)
  • src/praisonai-agents/praisonaiagents/agent/agent.py#L1475-L1478
  • src/praisonai-agents/praisonaiagents/config/feature_configs.py#L508-L509
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/praisonai-agents/praisonaiagents/agent/agent.py` around lines 1446 -
1449, Provide a working policy migration path before publishing these messages:
update the Agent policy guidance at
src/praisonai-agents/praisonaiagents/agent/agent.py:1446-1449 and the
GuardrailConfig guidance at
src/praisonai-agents/praisonaiagents/agent/agent.py:1475-1478 to reference an
existing supported API, or add a valid policy entry point to Agent.__init__.
Align the policy-related example and field documentation at
src/praisonai-agents/praisonaiagents/config/feature_configs.py:508-509 with the
same supported API.

Comment on lines +1508 to +1511
result = await asyncio.wait_for(_invoke(), timeout=tool_timeout)
except asyncio.TimeoutError:
logging.warning(f"Tool {function_name} timed out after {tool_timeout}s")
return {"error": f"Tool timed out after {tool_timeout}s", "timeout": True}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
file="src/praisonai-agents/praisonaiagents/agent/execution_mixin.py"

rg -n -C 10 'asyncio\.wait_for|asyncio\.TimeoutError|asyncio\.wait\(|_astart_with_outcome|timeout=True' "$file"
rg -n -C 8 'timeout=True|Tool timed out|asyncio\.TimeoutError' --glob '*.py'

Repository: MervinPraison/PraisonAI

Length of output: 6077


🏁 Script executed:

#!/bin/bash
set -euo pipefail
file="src/praisonai-agents/praisonaiagents/agent/execution_mixin.py"

echo "== function outline =="
ast-grep outline "$file" --match '_execute_tool_async_with_retry' --view expanded || true

echo "== retry/timeout handling section =="
sed -n '1524,1585p' "$file" | cat -n

echo "== _tool_timeout occurrences =="
rg -n "_tool_timeout|tool_timeout|timeout=True|retryable" "$file"

echo "== Python asyncio TimeoutError behavior =="
python3 - <<'PY'
import asyncio
import sys

print("python", sys.version)

async def inner_timeout():
    raise asyncio.TimeoutError("inner")

async def budget_timeout():
    await asyncio.sleep(2)

print("inner TimeoutError is TimeoutError:", issubclass(asyncio.TimeoutError, TimeoutError))
print("TimeoutError is alias:", asyncio.TimeoutError is TimeoutError)

async def main():
    for coro_name, coro in [("inner", inner_timeout()), ("budget", budget_timeout())]:
        try:
            try:
                await asyncio.wait_for(coro, timeout=0.01)
            except asyncio.TimeoutError:
                print(coro_name, "caught by except asyncio.TimeoutError")
            else:
                print(coro_name, "no exception")
        finally:
            pass

asyncio.run(main())
PY

Repository: MervinPraison/PraisonAI

Length of output: 4951


🌐 Web query:

Python 3.11 asyncio.TimeoutError is alias of TimeoutError asyncio.wait_for documentation

💡 Result:

In Python 3.11, asyncio.TimeoutError was made a deprecated alias of the built-in TimeoutError [1][2]. Furthermore, starting in Python 3.11, the asyncio.wait_for function was updated to raise the built-in TimeoutError instead of asyncio.TimeoutError [3][4][5]. Because asyncio.TimeoutError is now an alias for the built-in exception, existing code that catches asyncio.TimeoutError will continue to function correctly in Python 3.11 and later, but it is recommended to use the built-in TimeoutError.

Citations:


Distinguish the local tool timeout from tool-raised timeouts.

_execute_tool_async_with_retry() currently catches every inner asyncio.TimeoutError and returns {"timeout": True, "retryable": False} before the tool timeout can expire. A tool can raise that exception as a normal failure, so the caller then treats it as a non-retryable tool timeout. Use an owned task with an explicit deadline as _astart_with_outcome() does, call task.result() after the task completes, and let inner exceptions follow normal error handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/praisonai-agents/praisonaiagents/agent/execution_mixin.py` around lines
1508 - 1511, Update _execute_tool_async_with_retry() to distinguish its own
deadline from asyncio.TimeoutError raised by the tool: create and retain an
owned task for _invoke(), enforce the timeout using an explicit deadline pattern
matching _astart_with_outcome(), then call task.result() after completion so
tool-raised exceptions flow through normal error handling. Only return the
timeout response when the locally enforced deadline expires.

Source: MCP tools

@praisonai-triage-agent praisonai-triage-agent Bot removed pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:cooldown Blocked: post-push or @claude cooldown labels Aug 8, 2026
@MervinPraison

Copy link
Copy Markdown
Owner

@claude this PR has merge conflicts with main. Please rebase onto latest main, resolve conflicts (keep this PR's intent, merge in newer main logic), run targeted tests, and force-push with --force-with-lease. Comment which files you resolved. Do not bloat the Agent class with additional params — only if absolutely required; we already support many params. Keep the resolution minimal — the aim is a lightweight and powerful package; do not introduce scope creep while resolving conflicts.

@praisonai-triage-agent

praisonai-triage-agent Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Claude finished @MervinPraison's task —— View job


Rebased PR #3790 onto latest main

  • Setup git identity & fetch latest main
  • Rebase onto origin/main (144683d6e)
  • Resolve conflicts (kept PR intent + newer main logic)
  • Run targeted tests
  • Force-push with --force-with-lease

Files resolved

File Conflict Resolution
praisonaiagents/agent/execution_mixin.py main added the tool_progress_channel streaming sink around tool dispatch; this PR wrapped dispatch in an async asyncio.wait_for timeout Merged both — moved the streaming with tool_progress_channel(_progress_sink): blocks inside the new _invoke() coroutine, then wrapped _invoke() in the timeout. Streaming + timeout now coexist. The 2nd commit's retryable: False (non-retryable timeout) marker re-applied cleanly on top.

The other 3 files (agent.py, agents.py, feature_configs.py) auto-merged with no conflicts.

Tests (targeted on changed paths)

  • test_workflow_hierarchical.py + test_agent_centric_enhancements.py39 passed
  • test_tool_timeout.py7 passed, 1 failed only from litellm not being installed in the CI sandbox (ImportError: LiteLLM is required) — pre-existing env limitation, unrelated to the rebase.

Skipped (intentionally)

  • No new Agent params, deps, or exports added — resolution kept minimal, no scope creep.
  • praisonai-rust / praisonai-ts untouched (out of scope).

Branch is now clean on top of main and ready to merge once CI is green.


Branch: claude/issue-3789-20260808-0713

@praisonai-triage-agent praisonai-triage-agent Bot added pipeline/blocked:conflict Blocked: merge conflict or rebase pending pipeline/blocked:cooldown Blocked: post-push or @claude cooldown labels Aug 9, 2026
praisonai-triage-agent Bot and others added 2 commits August 9, 2026 10:15
…y-string guardrails (fixes #3789)

- process=hierarchical: drive the ahierarchical()/hierarchical() generators
  manually so the real manager_task id is sent back via .send()/.asend(),
  restoring the self-delegation guard and manager-task exclusion (was always
  None under plain for/async for).
- execute_tool_async: apply the per-agent ToolConfig.timeout via
  asyncio.wait_for so the async path no longer hangs indefinitely on a stuck
  tool, matching the sync path.
- guardrails: fail loud with a clear ValueError when unenforced policy-string
  guardrails (guardrails=["policy:..."] or GuardrailConfig.policy/.policies)
  are passed, instead of running with silent zero enforcement; fixed the
  misleading GuardrailConfig docstring.

Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
…effects

asyncio.wait_for cannot cancel a sync tool already running in the executor,
so the async retry loop was re-invoking timed-out tools up to max_attempts
times while the original invocation kept running — duplicating DB writes,
API calls, and file mutations (Greptile P1).

Mark the async timeout result with retryable=False and short-circuit it in
_execute_tool_async_with_retry alongside the other non-retryable outcomes.

Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
@praisonai-triage-agent
praisonai-triage-agent Bot force-pushed the claude/issue-3789-20260808-0713 branch from 1331d36 to 781deb9 Compare August 9, 2026 10:16
@MervinPraison MervinPraison added pipeline/blocked:ci Blocked: CI not green on HEAD and removed claude-conflict-pending pipeline/blocked:conflict Blocked: merge conflict or rebase pending labels Aug 9, 2026
@praisonai-triage-agent praisonai-triage-agent Bot removed pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:cooldown Blocked: post-push or @claude cooldown labels Aug 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pipeline/awaiting-merge-gate FINAL done; waiting for merge gate / CI pipeline/blocked:manual-review Blocked: requires manual review

Projects

None yet

1 participant