Skip to content

Add ask_agent: agent-to-agent delegation via the embedded MCP server - #893

Open
crspeller wants to merge 33 commits into
masterfrom
cursor/agent-to-agent-delegation-b82c
Open

Add ask_agent: agent-to-agent delegation via the embedded MCP server#893
crspeller wants to merge 33 commits into
masterfrom
cursor/agent-to-agent-delegation-b82c

Conversation

@crspeller

@crspeller crspeller commented Jul 17, 2026

Copy link
Copy Markdown
Member

Summary

Adds an ask_agent tool to the embedded MCP server that lets an agent delegate a self-contained task to any agent the user can access, including itself ("one pane of glass"). The delegating agent calls it like any other embedded tool; admin per-tool policy (seeded at ask), per-agent MCP enablement, dynamic tool loading, and user-level disablement all apply automatically.

How it works

  • Execution is in-process via a new delegation/ package: validate (target exists, CheckUsageRestrictionsForUser) → surface (labeled task post + Operation="delegation" conversation in the initiator's DM with the target agent) → run (normal DM conversation machinery: target agent's persona + a delegated-task preamble, tools built for the initiator, ask_agent excluded from sub-turns on every path incl. approval resume and regen) → await → return (attributed answer + permalink as the tool result).
  • Both visible delegation artifacts use Mattermost 11.10's integration-only silent_notification delivery. The thread remains visible and streams normally without incrementing the initiator's DM unread or mention counts or producing desktop, push, or email notifications.
  • Identity always comes from the session, never tool arguments: initiator = authenticated embedded-MCP session user; delegating agent + parent tool-call ID ride on server-injected call metadata (prepareToolCallMetadata), keyed per call via a context-stamped tool-call ID.
  • No park phase — the parent waits as long as the sub-agent needs (24h abuse backstop only). Nested tool approvals and questions are mirrored into the parent delegation card, while remaining available in the visible delegation thread. Both surfaces submit against the real delegated response post and share the same CAS-protected executor, so only one click can win. Completion wakes the waiting parent via a completion registry plus a delegation_complete plugin cluster event for cross-node approvals, re-reading conversation state from the DB on wake.
  • Because the wait is unbounded, approved delegation batches execute asynchronously: HandleToolCall persists the full decision batch first (which closes duplicate-click double execution), returns immediately, and runs the batch on a detached goroutine. Delegated sub-turn approvals also claim their decision batch before synchronous execution because they can be displayed on two surfaces. A TouchUserActivity keepalive prevents the 30-minute MCP idle sweep from severing long-running delegations.
  • Live progress UI: a delegation card replaces the generic tool card for ask_agent — target agent, task, live phase (startingrunning ("Using search_posts…") → waiting_on_youcompleted/failed/timed_out), inline approval cards, elapsed time, "View conversation" permalink, and a collapsed answer preview. Driven by a new delegation_update websocket event (initiator-scoped) and reconciled on reload from GET /plugins/mattermost-ai/delegations/{parent_tool_call_id} (initiator-only, 404 otherwise).
  • Channels: usable under the existing EnableChannelMentionToolCalling gate; the delegation thread still lives in the initiator's DM; the sub-agent's answer stays an initiator-private tool result until explicitly shared (existing share/redaction machinery).
  • Observability: llm.OperationDelegation (sub-turn tokens meter under the target agent's service), a delegate to agent span, delegation counters + duration histogram, and a per-delegation log line.
  • The minimum supported Mattermost Server version is now 11.10.0.

Testing

  • Table-driven unit tests: validation matrix (including self-delegation), waiter registry (wake/coalesce/re-arm), sub-turn state derivation, ask_agent resolver (identity from session — includes a forged-arguments test), metadata plumbing, sub-turn tool filtering, CAS decision claiming across approval surfaces, both delegation surface posts carrying a boolean silent_notification, inline delegated approval rendering/submission, and delegation card state.
  • Eval (GOEVALS=1 LLM_PROVIDER=anthropic): the agent delegates when another agent is better suited and answers directly otherwise — 4/4 passing.
  • Playwright e2e spec tests/agent-delegation/delegation.spec.ts (aimock, assigned to e2e-shard-1): DM happy path, nested approval directly from the parent thread, channel share gate, and an assertion that delegation leaves the target-agent DM's unread and mention counts unchanged.
  • Manually verified end-to-end against a real Anthropic-backed instance (two agents), including the access-denied error path and reload survival of the waiting_on_you phase.

Demo videos (real Anthropic agents)

DM happy path — pending card → Accept → live phases → completed with answer preview → synthesis → delegation thread in the DM:

delegation-dm-happy-path.webm

Earlier in-thread approval flow (still supported) — sub-agent needs an ask-policy tool (create_post), parent card flips to "Waiting on you", survives a page reload, in-thread approval resumes the sub-turn and the parent completes; the sub-agent's post lands in Town Square as the initiator:

delegation-nested-approval-reload.webm

Channel flow — delegation from a channel mention; an onlooker sees no approval buttons and no unshared answer content; after Share the synthesis streams channel-visible:

delegation-channel-share-initiator.webm · delegation-channel-share-onlooker.webm

Screenshots

pending approval running (live tool activity)
pending running

Release Note

Added an ask_agent tool to the embedded MCP server that lets an agent delegate a task to any accessible agent, including itself, on the requesting user's behalf. The delegated work runs as the user in a visible, silent thread in their DM with the target agent, while nested approvals and questions are also actionable directly from the parent delegation card. Live progress appears on the delegating agent's reply, and the answer is returned to the delegating agent. ask_agent defaults to the "ask" approval policy and follows existing per-agent MCP enablement. Added the custom_mattermost-ai_delegation_update websocket event and the GET /plugins/mattermost-ai/delegations/{parent_tool_call_id} endpoint. Requires Mattermost Server 11.10.0 or later.
Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features
    • Added agent-to-agent delegation via the embedded ask_agent tool, including capped delegated tool rounds and execution in a visible DM thread.
    • Introduced delegation status support (server API + UI card) with approval phases, elapsed timing, and conversation links.
    • Enabled live delegation progress updates and nested approval flows, including “Share” vs “Keep private” result visibility.
  • Documentation
    • Updated the Agents admin guide with delegation setup and privacy/permission behaviour.
  • Tests
    • Added unit and end-to-end coverage for routing, approvals, progress updates, and the delegation UI.

cursoragent and others added 14 commits July 17, 2026 18:35
…k_agent at ask policy

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…turn runner

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…us reconcile endpoint

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…ty keepalive

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…claim persistence

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…t a stream

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…dentity

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…rd assignment

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…y otherwise

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown

🤖 LLM Evaluation Results

OpenAI

⚠️ Overall: 21/28 tests passed (75.0%)

Provider Total Passed Failed Pass Rate
⚠️ OPENAI 28 21 7 75.0%

❌ Failed Evaluations

Show 7 failures

OPENAI

1. TestReactEval/[openai]_react_cat_message

  • Score: 0.00
  • Rubric: The word/emoji is a cat emoji or a heart/love emoji
  • Reason: The output is the text string "heart_eyes_cat", not an actual cat emoji (e.g., 😺) or heart/love emoji (e.g., ❤️).

2. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: is a list of bugs
  • Reason: The output does not provide a list of bugs; it states it cannot access the bug tracker and only offers a template for listing bugs if they are provided.

3. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: includes a description of each bug
  • Reason: The output does not provide descriptions of each bug; it requests that the user paste bug reports and provides a template with empty rows, so no actual bug descriptions are included.

4. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes each bug to a user
  • Reason: The output does not attribute any specific bug to a user; it only requests that bug reports be provided and includes a template with a 'Reported by' column left blank.

5. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes the bug about trying to save without a color and the save button not doing anything to @maria.nunez
  • Reason: The output does not mention the specific bug ('trying to save without a color and the save button not doing anything') nor does it attribute it to @maria.nunez. It instead states it cannot access bug reports and provides a template.

6. TestConversationMentionHandling/[openai]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: the bug about the end user being able to change channel banner is attributed to @maria.nunez
  • Reason: The output does not mention the specific bug about an end user being able to change the channel banner, and it does not attribute that bug to @maria.nunez. It only asks for bug reports to be provided.

7. TestDirectMessageConversations/[openai]_bot_dm_tool_introspection

  • Score: 0.00
  • Rubric: mentions Github and refers to the documentation
  • Reason: The output refers to documentation (Mattermost docs link) but does not mention GitHub anywhere. Since the rubric requires both mentioning Github and referring to the documentation, it fails.

Anthropic

⚠️ Overall: 21/28 tests passed (75.0%)

Provider Total Passed Failed Pass Rate
⚠️ ANTHROPIC 28 21 7 75.0%

❌ Failed Evaluations

Show 7 failures

ANTHROPIC

1. TestReactEval/[anthropic]_react_cat_message

  • Score: 0.00
  • Rubric: The word/emoji is a cat emoji or a heart/love emoji
  • Reason: The output is the text token "heart_eyes_cat", not an actual cat emoji (e.g., 😺) or a heart/love emoji (e.g., ❤️).

2. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: is a list of bugs
  • Reason: The output does not provide a list of bugs; it states inability to access trackers and suggests how to obtain a list, without enumerating any bugs.

3. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: includes a description of each bug
  • Reason: The output explains it cannot access bug trackers and suggests ways to find bugs, but it does not actually list any bugs or provide descriptions of each bug.

4. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes each bug to a user
  • Reason: The output does not list any bugs, nor does it attribute bugs to specific users. It only states lack of access and suggests how to find bugs.

5. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: attributes the bug about trying to save without a color and the save button not doing anything to @maria.nunez
  • Reason: The output does not mention the specific bug (saving without a color causing the save button to do nothing) nor does it attribute it to @maria.nunez. It only states lack of access and suggests how to find bugs.

6. TestConversationMentionHandling/[anthropic]_conversation_from_attribution_long_thread.json

  • Score: 0.00
  • Rubric: the bug about the end user being able to change channel banner is attributed to @maria.nunez
  • Reason: The output does not mention the specific bug about an end user being able to change the channel banner, nor does it attribute that bug to @maria.nunez.

7. TestDirectMessageConversations/[anthropic]_bot_dm_tool_introspection

  • Score: 0.50
  • Rubric: mentions Github and refers to the documentation
  • Reason: The output refers to documentation at docs.mattermost.com, satisfying the documentation reference, but it does not mention GitHub anywhere.

This comment was automatically generated by the eval CI pipeline.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds embedded agent-to-agent delegation with ask_agent, persisted state, delegated sub-turn execution, approval handling, progress events, cluster reconciliation, status APIs, metrics, and web UI coverage.

Changes

Delegation contracts and MCP entry

Layer / File(s) Summary
Delegation contracts and ask_agent entry
delegation/types.go, mcpserver/tools/*, mcpserver/*, llm/tool_call_context.go
Defines delegation requests, lifecycle phases, errors, ask_agent validation, embedded-only registration, and parent tool-call metadata propagation.

Delegation runtime and persistence

Layer / File(s) Summary
Delegation runtime and persistence
delegation/*, conversations/delegation_subturn.go, conversation/*, store/*
Orchestrates delegation records, delegated conversations, sub-turn execution, approval waiting, progress updates, keepalive, completion reconciliation, status derivation, and atomic turn claims.

Platform integration and web validation

Layer / File(s) Summary
Platform integration and web validation
api/*, server/*, metrics/*, format/*, prompts/*, webapp/src/*, e2e/*, docs/admin_guide.md, plugin.json
Connects delegation to HTTP status lookup, plugin activation, cluster completion events, metrics, prompts, formatting, live UI updates, documentation, and end-to-end scenarios.

Estimated code review effort: 5 (Critical) | ~90+ minutes

Possibly related PRs

Suggested labels: Setup Cloud Test Server

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: adding ask_agent-based agent-to-agent delegation in the embedded MCP server.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/agent-to-agent-delegation-b82c

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🧹 Nitpick comments (1)
delegation/delegation_eval_test.go (1)

188-193: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert that the delegated task preserves the user’s request.

Checking only NotEmpty allows regressions such as delegating "handle this" while the canned resolver and response rubric still pass. Add expected task terms per case and assert that args.Task includes them.

🤖 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 `@delegation/delegation_eval_test.go` around lines 188 - 193, Update the
wantDelegation assertions in the delegation evaluation test to define expected
user-request terms for each test case and verify args.Task contains those terms,
rather than only checking that it is non-empty. Keep the existing agent-target
assertion and ensure the canned resolver/rubric cannot pass when the delegated
task omits the request’s key terms.
🤖 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 `@conversations/tool_approval.go`:
- Around line 132-146: Make delegation approval claiming atomic in the flow
around persistAcceptedToolDecisions and executeResolvedToolBatch: replace the
unconditional decision persistence with a transactional or compare-and-set
update that succeeds only when the targeted blocks are still pending. Abort the
current request when the claim fails as stale, and launch the detached execution
goroutine only after a successful claim so concurrent clicks cannot execute
ask_agent twice.

In `@delegation/records.go`:
- Around line 48-62: Update saveRecord to prevent partial persistence when the
parent-tool-call KVSetWithExpiry fails: after a failed secondary write, remove
the conversation-key entry using the available KV delete operation, or use an
atomic persistence mechanism if supported. Ensure saveRecord still returns the
persistence error and both indexes remain consistent.

In `@delegation/service.go`:
- Around line 687-691: The latestSubTurnState function must propagate GetTurns
errors instead of returning subTurnStateNone; update its callers in
delegation/service.go to explicitly handle the returned error in await, status,
and orphan-completion flows. In delegation/service_test.go lines 259-262,
replace the subTurnStateNone expectation with an assertion that the turn-store
error is propagated.
- Around line 421-423: The delegation flow around saveRecord must not continue
after persistence fails. Replace the log-only handling with explicit retry logic
or fail the delegation and return/propagate the error, ensuring downstream
status lookup and orphaned-cluster completion cannot proceed without the durable
record.
- Around line 448-453: Update the asynchronous title-generation path around
GenerateTitle to accept and pass a detached, bounded context as the first
parameter, preserving cancellation independence while enforcing a timeout.
Thread this context through every entry point in the GenerateTitle call path,
and instrument the relevant methods with OpenTelemetry spans using the
repository’s telemetry helpers and attribute keys.

In `@delegation/waiters_test.go`:
- Around line 12-68: Convert TestWaiterRegistry into a table-driven test using a
case slice with per-case setup and assertion callbacks, then iterate over the
cases with t.Run. Preserve all existing scenarios, names, registry operations,
and assertions while removing the separate handwritten subtest blocks.

In `@mcpserver/tools/agents.go`:
- Around line 71-99: Update createMCPToolContext so it always extracts BotUserID
from trusted embedded metadata, regardless of TrackAIGenerated; keep that
setting limited to post-attribution behavior. Preserve ask_agent availability
and add a regression test constructing the context with tracking disabled,
verifying toolAskAgent receives the bot identity instead of failing
authentication.
- Around line 109-110: Update the task-length validation in the relevant
delegation function to count Unicode characters with
utf8.RuneCountInString(task) instead of len(task), while preserving the existing
maximum and error message behavior.

In `@webapp/src/components/delegation/delegation_card.tsx`:
- Around line 175-182: Update formatElapsed and its usages in the delegation
card to route the elapsed-duration output through FormattedMessage or the
project’s existing localized duration formatter, including the additional
occurrences at the referenced lines. Remove hardcoded “m” and “s” user-facing
text while preserving the current minutes/seconds formatting behavior.
- Around line 203-210: Update the expandable Task rendering in the delegation
card, including the corresponding instance near the alternate task layout, so
its clickable variant uses a styled button or equivalent focusable keyboard
semantics. Preserve the existing taskNeedsClamp click behavior and
non-expandable rendering, while ensuring keyboard users can focus and activate
task expansion.
- Around line 103-105: Update the visual-state derivation around terminalPhase,
isPendingApproval, and isRejected in the delegation card so rejected calls and
local decisions take precedence over active phases and stale approval prompts.
Ensure rendering produces exactly one mutually exclusive state, then add
regression coverage for persisted rejection and local decision states.
- Around line 131-144: Update the elapsed timer effect using startedAtRef so it
adopts reconciled?.created_at whenever that timestamp becomes available, even if
the ref was initialized with Date.now(). Preserve the current fallback for
missing creation times and ensure the elapsed calculation remains based on the
reconciled start time.

---

Nitpick comments:
In `@delegation/delegation_eval_test.go`:
- Around line 188-193: Update the wantDelegation assertions in the delegation
evaluation test to define expected user-request terms for each test case and
verify args.Task contains those terms, rather than only checking that it is
non-empty. Keep the existing agent-target assertion and ensure the canned
resolver/rubric cannot pass when the delegated task omits the request’s key
terms.
🪄 Autofix (Beta)

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: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: e035102d-72fe-4c4d-8a87-6136939dc059

📥 Commits

Reviewing files that changed from the base of the PR and between cf496cd and e2492b5.

📒 Files selected for processing (55)
  • api/api.go
  • api/api_delegation.go
  • conversations/conversations.go
  • conversations/delegation_subturn.go
  • conversations/delegation_subturn_internal_test.go
  • conversations/handle_messages.go
  • conversations/regeneration.go
  • conversations/tool_approval.go
  • delegation/delegation_eval_test.go
  • delegation/progress.go
  • delegation/records.go
  • delegation/service.go
  • delegation/service_test.go
  • delegation/types.go
  • delegation/waiters.go
  • delegation/waiters_test.go
  • docs/admin_guide.md
  • e2e/scripts/ci-test-groups.mjs
  • e2e/tests/agent-delegation/delegation.spec.ts
  • format/format.go
  • i18n/en.json
  • llm/token_usage_fields.go
  • llm/tool_call_context.go
  • mcp/client_manager.go
  • mcp/client_manager_test.go
  • mcp/testhelpers_test.go
  • mcp/user_clients.go
  • mcp/user_clients_test.go
  • mcp/vetted_tools.go
  • mcp/vetted_tools_test.go
  • mcpserver/http_server.go
  • mcpserver/inmemory_server.go
  • mcpserver/plugin_handlers.go
  • mcpserver/server.go
  • mcpserver/stdio_server.go
  • mcpserver/tools/agents.go
  • mcpserver/tools/agents_test.go
  • mcpserver/tools/provider.go
  • metrics/metrics.go
  • metrics/noop.go
  • prompts/delegated_task_system.tmpl
  • prompts/prompts_vars.go
  • server/cluster_events.go
  • server/embedded_mcp_server.go
  • server/inmemory_basic_test.go
  • server/main.go
  • toolrunner/toolrunner.go
  • webapp/src/client.tsx
  • webapp/src/components/delegation/delegation_card.test.tsx
  • webapp/src/components/delegation/delegation_card.tsx
  • webapp/src/components/tool_approval_set.tsx
  • webapp/src/hooks/use_delegation_updates.ts
  • webapp/src/i18n/en.json
  • webapp/src/index.tsx
  • webapp/src/types/delegation.ts

Comment thread conversations/tool_approval.go Outdated
Comment thread delegation/records.go Outdated
Comment thread delegation/service.go
Comment thread delegation/service.go
Comment thread delegation/service.go Outdated
Comment thread mcpserver/tools/agents.go Outdated
Comment thread webapp/src/components/delegation/delegation_card.tsx
Comment thread webapp/src/components/delegation/delegation_card.tsx Outdated
Comment thread webapp/src/components/delegation/delegation_card.tsx
Comment thread webapp/src/components/delegation/delegation_card.tsx Outdated
cursoragent and others added 9 commits July 21, 2026 13:28
… and state-error propagation

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
… eval

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
…alized elapsed time

Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: Christopher Speller <crspeller@users.noreply.github.com>
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
@crspeller
crspeller marked this pull request as ready for review July 22, 2026 16:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@api/api_no_tools_test.go`:
- Around line 145-148: Update mockConvServiceStore.UpdateTurnContentIfMatches in
api/api_no_tools_test.go (lines 145-148) to compare stored content with
expected, return false, nil on mismatch, and only update matching content. Apply
the same compare-before-update behavior in
channels/analysis_conversation_test.go (lines 108-114) and add losing-claim
coverage; in channels/channels_eval_test.go (lines 187-190), return false for
missing turns; and in search/search_conversation_test.go (lines 103-109),
preserve the expected-content check and add stale-claim coverage.

In `@conversations/dm_conversation_test.go`:
- Around line 153-176: Keep the fake CAS operation atomic in
UpdateTurnContentIfMatches in conversations/dm_conversation_test.go:153-176 and
conversations/loaded_state_flow_test.go:142-165 by applying updated directly
while s.mu remains held, including updating the mirrored turns slice, then
return true without calling the separately locking UpdateTurnContent helper.
🪄 Autofix (Beta)

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: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 20892484-c7ae-463a-a90c-494f66d1b0ca

📥 Commits

Reviewing files that changed from the base of the PR and between 586d78e and d2dd7ab.

📒 Files selected for processing (23)
  • .github/workflows/ci.yml
  • api/api_no_tools_test.go
  • channels/analysis_conversation_test.go
  • channels/channels_eval_test.go
  • conversation/service.go
  • conversations/delegation_subturn_internal_test.go
  • conversations/dm_conversation_test.go
  • conversations/loaded_state_flow_test.go
  • conversations/tool_approval.go
  • delegation/delegation_eval_test.go
  • delegation/service.go
  • delegation/service_test.go
  • delegation/waiters_test.go
  • docs/admin_guide.md
  • e2e/helpers/mmcontainer.ts
  • e2e/tests/agent-delegation/delegation.spec.ts
  • plugin.json
  • search/search_conversation_test.go
  • store/turns.go
  • store/turns_test.go
  • webapp/src/components/delegation/delegation_card.test.tsx
  • webapp/src/components/delegation/delegation_card.tsx
  • webapp/src/i18n/en.json
🚧 Files skipped from review as they are similar to previous changes (9)
  • delegation/waiters_test.go
  • delegation/delegation_eval_test.go
  • docs/admin_guide.md
  • webapp/src/i18n/en.json
  • delegation/service_test.go
  • e2e/tests/agent-delegation/delegation.spec.ts
  • webapp/src/components/delegation/delegation_card.tsx
  • conversations/tool_approval.go
  • delegation/service.go

Comment thread api/api_no_tools_test.go
Comment thread conversations/dm_conversation_test.go

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2dd7abfcb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread conversations/tool_approval.go Outdated
Comment thread conversations/tool_approval.go
Comment thread conversations/tool_approval.go
cursoragent and others added 2 commits July 23, 2026 12:48
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
cursoragent and others added 7 commits July 23, 2026 13:20
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
Co-authored-by: christopher <christopher@mattermost.com>
@dryrunsecurity

Copy link
Copy Markdown

DryRun Security

This pull request introduces a high-severity risk of indirect prompt injection by returning unvalidated LLM output directly to the delegating agent. The DelegationResult function in format/format.go fails to sanitize the target agent's answer, allowing malicious instructions to manipulate the delegating agent's behavior.

🟠 Indirect Prompt Injection via Unvalidated LLM Output in format/format.go (drs_cfc427f6)
Vulnerability Indirect Prompt Injection via Unvalidated LLM Output
Description The DelegationResult function formats the output of a delegated agent by prepending attribution text and then appending the raw answer string from the target agent. This formatted string is then returned to the delegating agent as a tool result. If the target agent's answer contains malicious instructions (prompt injection), these instructions are directly injected into the delegating agent's context as part of the tool result, potentially allowing the target agent to manipulate the delegating agent's behavior.

b.WriteString(answer)
return b.String()
}


Comment to provide feedback on these findings.

Report false positive: @dryrunsecurity fp [FINDING ID] [FEEDBACK]
Report low-impact: @dryrunsecurity nit [FINDING ID] [FEEDBACK]

Example: @dryrunsecurity fp drs_90eda195 This code is not user-facing

All finding details can be found in the DryRun Security Dashboard.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants