Skip to content

fix: async loop expansion, tool-tracking race, MCP skill-gate (#3307) - #3326

Merged
praisonai-triage-agent[bot] merged 2 commits into
mainfrom
claude/issue-3307-20260723-1028
Jul 27, 2026
Merged

fix: async loop expansion, tool-tracking race, MCP skill-gate (#3307)#3326
praisonai-triage-agent[bot] merged 2 commits into
mainfrom
claude/issue-3307-20260723-1028

Conversation

@praisonai-triage-agent

Copy link
Copy Markdown
Contributor

Fixes #3307

Fixes all three code-verified gaps in praisonaiagents, minimally and backward-compatibly.

Gap 1 — aworkflow() dropped loop-task pre-expansion

process/process.py: ported the loop pre-expansion block from workflow() into aworkflow() (was just a TODO). Async workflows with a task_type="loop" CSV start task now expand one subtask per row instead of running once, matching sync behaviour.

Gap 2 — concurrent achat()/chat() race on _turn_tools_used

agent/agent.py, tool_execution.py, execution_mixin.py, chat_mixin.py: the per-turn tool buffer is now backed by the same AsyncSafeState lock that already protects chat_history. All reset/append/read-and-clear sites go through _reset_turn_tools / _record_turn_tool / _drain_turn_tools. A backward-compatible _turn_tools_used property is retained so existing consumers/tests keep working. No new Agent params.

Gap 3 — MCP skill-gate always failed closed

mcp/mcp.py, skills/capability_validator.py: MCP now records namespaced server names in a process-level registry (MCP.list_active_server_names(), populated in with_tool_prefix() — same pattern as the tool registry), and CapabilityValidator._get_available_servers() reads from it. MCP-server-gated skills can now pass STRICT validation instead of always being dropped.

Tests

  • New test_aworkflow_loop_expansion.py (async == sync loop expansion parity)
  • New Gap 2 thread-safety test + Gap 3 registry/STRICT tests
  • self_improve / capability / async-workflow suites: 76 passed
  • Pre-existing/environmental failures (missing fastapi/litellm, unrelated LLMGuardrail.logger) are not touched by this change

🤖 Generated with Claude Code

@MervinPraison

Copy link
Copy Markdown
Owner

@coderabbitai review

@MervinPraison

Copy link
Copy Markdown
Owner

/review

@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 Jul 23, 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.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@MervinPraison, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 47 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e5b4a3f4-8d4e-40e2-8f09-08d369bdb379

📥 Commits

Reviewing files that changed from the base of the PR and between 7494bba and aca311e.

📒 Files selected for processing (10)
  • src/praisonai-agents/praisonaiagents/agent/agent.py
  • src/praisonai-agents/praisonaiagents/agent/chat_mixin.py
  • src/praisonai-agents/praisonaiagents/agent/execution_mixin.py
  • src/praisonai-agents/praisonaiagents/agent/tool_execution.py
  • src/praisonai-agents/praisonaiagents/mcp/mcp.py
  • src/praisonai-agents/praisonaiagents/process/process.py
  • src/praisonai-agents/praisonaiagents/skills/capability_validator.py
  • src/praisonai-agents/tests/test_aworkflow_loop_expansion.py
  • src/praisonai-agents/tests/unit/skills/test_capability_validator.py
  • src/praisonai-agents/tests/unit/skills/test_self_improve.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/issue-3307-20260723-1028

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 Jul 23, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR synchronizes MCP server-registry access and updates capability-validation and regression tests.

  • Adds a lock around MCP registry reads and registrations.
  • Keeps capability validation on live registry snapshots.
  • Adds async-loop, MCP capability, and tool-tracking regression coverage.

Confidence Score: 4/5

The PR is not yet safe to merge because synchronized registry access still allows STRICT validation to accept MCP servers that are shut down or owned by another Agent.

MCP names remain permanently stored in a process-global registry, while capability validation treats every stored name as currently usable by the validating Agent.

Files Needing Attention: src/praisonai-agents/praisonaiagents/mcp/mcp.py and src/praisonai-agents/praisonaiagents/skills/capability_validator.py

Important Files Changed

Filename Overview
src/praisonai-agents/praisonaiagents/mcp/mcp.py Adds synchronized registry access, but server entries remain unscoped and survive shutdown.
src/praisonai-agents/praisonaiagents/skills/capability_validator.py Continues reading live MCP registry snapshots under the new synchronization.
src/praisonai-agents/tests/test_aworkflow_loop_expansion.py Adds sync/async loop-expansion parity coverage without changing production behavior.
src/praisonai-agents/tests/unit/skills/test_capability_validator.py Adds live-registry and STRICT validation coverage but does not cover shutdown or Agent scoping.
src/praisonai-agents/tests/unit/skills/test_self_improve.py Adds concurrent helper-operation coverage without changing production behavior.

Reviews (3): Last reviewed commit: "fix(skills): read MCP server registry li..." | Re-trigger Greptile

Comment thread src/praisonai-agents/praisonaiagents/agent/agent.py Outdated
Comment thread src/praisonai-agents/praisonaiagents/mcp/mcp.py
Comment thread src/praisonai-agents/praisonaiagents/process/process.py Outdated
@MervinPraison MervinPraison added pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:manual-review Blocked: requires manual review pipeline/blocked:no-final Blocked: no FINAL @claude trigger yet pipeline/final-claude-pending Reviews done; waiting for FINAL @claude labels Jul 23, 2026
@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 Jul 23, 2026
@praisonai-triage-agent

praisonai-triage-agent Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

Claude finished @MervinPraison's task —— View job


Final Architecture Review — PR #3326

Verdict: Approve (one valid staleness bug fixed and pushed; other two reviewer P1s judged out-of-scope / pre-existing).

Phase 1 — AGENTS.md compliance

  • Protocol-driven / routing ✅ — changes stay in core praisonaiagents where they belong (process orchestration, agent internals, MCP registry, skills validator). No tools/plugins/sandbox concerns misrouted.
  • Backward compatible ✅ — _turn_tools_used property retained; clear_cache() and _server_cache field retained; no Agent params added.
  • Performance ✅ — live MCP registry read is a set-copy under a threading.Lock, invoked only during skill validation (cold path), not a hot path.
  • SDK value ✅ — all three gaps are genuine correctness fixes (async/sync loop parity, tool-buffer data race, skill-gate failing closed), no knob/scope creep. Agent class grew ~32 lines of small locked helpers, well under the 100-line gate.

Phase 2 — Triage of the 3 greptile P1s

# Finding Verdict Action
1 agent.py shared tool buffer mixes concurrent turns Pre-existing design limitation, not a regression. Buffer was Agent-level before this PR; Gap 2's goal (fix the data race) is achieved. Full per-turn ownership = thread/task-local redesign = scope creep. No change (documented limitation)
2 mcp.py/capability_validator.py stale server cache VALID — validator cached the MCP registry snapshot once; servers connecting later stayed invisible under STRICT. This PR introduced the dynamic source. FIXED
3 process.py empty async loop never advances Not valid for this PR — async block is an exact port of sync workflow(); empty-loop behavior is identical in both. Fixing only async breaks the parity this PR delivers. No change (out of scope)

Files modified (this review)

  • src/praisonai-agents/praisonaiagents/skills/capability_validator.py_get_available_servers() now reads MCP.list_active_server_names() live instead of caching once.
  • src/praisonai-agents/tests/unit/skills/test_capability_validator.py — added test_available_servers_read_live_not_cached locking in the fix.

Skipped (with rationale)

  • greptile P1 Github actions fix #1 (concurrent-turn ownership) and Main #3 (empty-loop) — see table above; both are broader pre-existing behaviors outside this PR's minimal, backward-compatible scope.

Tests

test_capability_validator.py + test_self_improve.py + test_aworkflow_loop_expansion.py69 passed.

Pushed to claude/issue-3307-20260723-1028 (8de14c369).

Job run • Branch claude/issue-3307-20260723-1028

@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 Jul 23, 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 Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

Claude finished @MervinPraison's task —— View job


Rebase complete — PR #3326 onto latest main

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

Key finding

While this PR was open, main independently merged its own versions of Gap 1 (async loop expansion) and Gap 2 (tool-tracking race). So conflict resolution converged the branch onto main's now-canonical implementations, keeping this PR's genuinely-additive piece (Gap 3, the thread-safe MCP registry).

Files resolved (7 source)

File Resolution
agent/agent.py Kept main's _turn_tools_used list + DualLock. Removed the PR's leftover _turn_tools_state property/setter + duplicate helper methods that the auto-merge left behind (they referenced a now-nonexistent attribute and broke 34 tests).
agent/chat_mixin.py Kept main's _reset_turn_tools() (guards _in_skill_review internally, so PR's extra if was redundant).
agent/execution_mixin.py Kept main's _record_turn_tool() (self-guarding).
agent/tool_execution.py Kept main's _drain_turn_tools() at reset sites; canonical _reset/_record/_drain helpers live here.
mcp/mcp.py Kept this PR's thread-safe registry (_active_server_names_lock) over main's unlocked version; retained the if prefix: guard from main.
skills/capability_validator.py Kept the live (non-cached) _get_available_servers() reading set(MCP.list_active_server_names()) — the staleness fix from this PR's 2nd commit; merged both docstrings.
process/process.py Comment-only conflicts (both sides had the loop pre-expansion); kept main's comments.

Test files (test_aworkflow_loop_expansion.py, test_capability_validator.py, test_self_improve.py) had no conflicts and now validate against main's implementation.

Skipped

  • No Agent params added; Agent class net −27 lines (removed leftover PR block). No scope creep introduced during resolution.

Tests

test_aworkflow_loop_expansion.py + test_capability_validator.py + test_self_improve.py (incl. the Gap 2 thread-safety test) → 69 passed.

Rebased & force-pushed (--force-with-lease) to claude/issue-3307-20260723-1028 (d15657ba2).

Job run • Branch claude/issue-3307-20260723-1028

praisonai-triage-agent Bot and others added 2 commits July 27, 2026 08:44
…3307)

Gap 1: port loop-task pre-expansion from workflow() into aworkflow() so
async workflows with a CSV-driven loop start task expand per-row instead
of running once.

Gap 2: guard the per-turn _turn_tools_used buffer with the same
AsyncSafeState lock that protects chat_history, routing all sites through
_reset/_record/_drain helpers so concurrent chat()/achat() turns on one
Agent no longer corrupt hook/self-improve tool data. Backward-compatible
_turn_tools_used property retained.

Gap 3: track namespaced MCP server names in a process-level registry
(MCP.list_active_server_names(), populated in with_tool_prefix) and read
it from CapabilityValidator._get_available_servers so MCP-server-gated
skills can pass STRICT validation instead of always failing closed.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
CapabilityValidator cached the MCP server snapshot once, so servers that
connected after the first validation stayed invisible under STRICT
enforcement. Read the process-level registry live each call (cheap
set-copy under lock); tool cache is unchanged. (#3307)

Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com>
@praisonai-triage-agent
praisonai-triage-agent Bot force-pushed the claude/issue-3307-20260723-1028 branch from 8de14c3 to d15657b Compare July 27, 2026 08:44
@MervinPraison MervinPraison added pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:conflict Blocked: merge conflict or rebase pending pipeline/blocked:cooldown Blocked: post-push or @claude cooldown and removed pipeline/blocked:manual-review Blocked: requires manual review labels Jul 27, 2026
Comment on lines +850 to +857
# Record this server in the process-level registry so skills'
# CapabilityValidator can discover it (issue #3307). Store both the
# original name and its sanitized form so a skill requirement matches
# regardless of which spelling it declares.
with type(self)._active_server_names_lock:
if prefix:
type(self)._active_server_names.add(prefix)
type(self)._active_server_names.add(sanitized)

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.

P1 MCP availability remains stale

When a namespaced MCP server shuts down or belongs to another Agent, its name remains in the process-global registry and STRICT validation treats it as usable, causing the skill to be activated even though its Agent cannot invoke the required server.

Knowledge Base Used: praisonai-agents Core Library

@praisonai-triage-agent praisonai-triage-agent Bot added pipeline/merge-ready Eligible for merge gate auto-merge and removed pipeline/awaiting-merge-gate FINAL done; waiting for merge gate / CI pipeline/blocked:ci Blocked: CI not green on HEAD pipeline/blocked:conflict Blocked: merge conflict or rebase pending pipeline/blocked:cooldown Blocked: post-push or @claude cooldown labels Jul 27, 2026
@praisonai-triage-agent

Copy link
Copy Markdown
Contributor Author

Merge gate scan — eligible for assessment. Claude merge gate will assess and may auto-merge if MERGE_GATE_VERDICT: APPROVE.

@praisonai-triage-agent
praisonai-triage-agent Bot merged commit 112e61c into main Jul 27, 2026
44 checks passed
@praisonai-triage-agent

Copy link
Copy Markdown
Contributor Author

Merged by Claude PR merge gate (claude-merge-gate.yml).
Verdict: MERGE_GATE_VERDICT: APPROVE
SHA: d15657b
Method: merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

auto-merged-by-gate pipeline/merge-ready Eligible for merge gate auto-merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

praisonaiagents: aworkflow() drops loop-task expansion, concurrent achat() races on tool-tracking state, MCP skill-gate always fails closed

1 participant