feat(spawn): add task-exit mode#1129
Conversation
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds an optional ChangesTask-exit mode for agent-relay spawn APIs
Sequence Diagram(s)sequenceDiagram
participant CLI as local-agent CLI / MCP add_agent
participant HarnessDriver as HarnessDriverClient
participant BrokerHTTP as listen_api_spawn (HTTP)
participant BrokerRuntime as BrokerRuntime::handle_api_request
participant Session as apply_exit_after_task_instruction
CLI->>HarnessDriver: spawnPty({ spawnMode: 'task_exit', exitAfterTask: true, task })
HarnessDriver->>BrokerHTTP: POST /api/spawn { spawnMode, exitAfterTask, task }
BrokerHTTP->>BrokerHTTP: parse spawn_mode → derive exit_after_task bool (OR with explicit field)
BrokerHTTP-->>CLI: 400 BAD_REQUEST (if unsupported spawnMode)
BrokerHTTP->>BrokerRuntime: ListenApiRequest::Spawn { exit_after_task: true, task }
BrokerRuntime->>Session: apply_exit_after_task_instruction(task)
Session-->>BrokerRuntime: task + EXIT_AFTER_TASK_INSTRUCTION (/exit)
BrokerRuntime->>BrokerRuntime: spawn agent session with effective_task
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Code Review
This pull request introduces an optional task-exit mode for spawned CLI agents, allowing them to cleanly self-terminate with /exit after completing their injected task. This is implemented across the Rust broker, CLI commands, MCP server, and harness driver. Feedback on the changes suggests improving the robustness of the TypeScript helper withExitAfterTaskInstruction to handle empty or whitespace-only tasks without prepending unnecessary newlines, aligning its behavior with the Rust implementation.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| function withExitAfterTaskInstruction(task: string): string { | ||
| return `${task}\n\n${EXIT_AFTER_TASK_INSTRUCTION}`; | ||
| } |
There was a problem hiding this comment.
If the task parameter is empty or contains only whitespace, the current implementation will prepend unnecessary newlines (\n\n) before the instruction. To match the robustness of the Rust implementation (apply_exit_after_task_instruction), we should trim the task and only append the newlines if the task is non-empty.
| function withExitAfterTaskInstruction(task: string): string { | |
| return `${task}\n\n${EXIT_AFTER_TASK_INSTRUCTION}`; | |
| } | |
| function withExitAfterTaskInstruction(task: string): string { | |
| const trimmed = task.trim(); | |
| return trimmed ? `${trimmed}\n\n${EXIT_AFTER_TASK_INSTRUCTION}` : EXIT_AFTER_TASK_INSTRUCTION; | |
| } |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 027ea9e0cd
ℹ️ 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".
| spawnMode?: SpawnMode; | ||
| exitAfterTask?: boolean; |
There was a problem hiding this comment.
Permit task-exit fields in driver action schema
These new public spawn fields are not mirrored in the registered agent.create action schema: packages/harness-driver/src/actions.ts still sets additionalProperties: false and only lists the older spawn properties. In environments that create agents through registerDriverActions instead of calling HarnessDriverClient.spawnPty directly, inputs such as spawnMode: 'task_exit' or exitAfterTask: true are rejected as additional properties before BrokerDriver.spawn can forward them, so the new task-exit mode is unavailable on that spawn API.
Useful? React with 👍 / 👎.
|
No blocking findings in the current checkout. I did not apply any edits. Addressed comments
Verification
Could not run Rust CI locally because |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
CHANGELOG.md (1)
12-12: ⚡ Quick winRewrite this bullet to be impact-first and less implementation-specific.
This reads a bit implementation-heavy for
[Unreleased]; keep it as a short user-visible outcome.Suggested wording
-- `agent-relay` spawn APIs add an optional task-exit mode so spawned CLI agents run the injected task and then cleanly self-terminate with `/exit`. +- `agent-relay` spawn APIs now support an optional task-exit mode so spawned CLI agents can automatically exit after task completion.As per coding guidelines, “Changelog entries should be concise and impact-first, with one short bullet per user-visible change… Omit … implementation details.”
🤖 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 `@CHANGELOG.md` at line 12, Rewrite the changelog entry on line 12 to focus on the user-visible impact rather than implementation details. Remove technical jargon like "spawn APIs," "task-exit mode," and "/exit" command, and instead express the benefit in simple terms: that spawned CLI agents can now cleanly complete their task and exit automatically. Keep the entry concise and outcome-focused, omitting internal mechanics and API specifics.Source: Coding guidelines
packages/cli/src/cli/commands/local-agent.test.ts (1)
70-98: ⚡ Quick winAdd parity tests for the
newcommand and invalid--spawn-modepaths.Line 70 adds good coverage for
spawn, but the same lifecycle plumbing/validation was also added tolocal agent new. Please add tests for: (1) forwarding onnew, and (2) rejection of unsupported spawn-mode values, to prevent drift between the two command paths.Proposed test additions
+ it('new forwards task-exit lifecycle options', async () => { + const { program, client, attach } = harness(); + await program.parseAsync( + [ + 'local', + 'agent', + 'new', + 'codex', + '--name', + 'WorkerB', + '--task', + 'Ship it', + '--spawn-mode', + 'task-exit', + '--exit-after-task', + ], + { from: 'user' } + ); + + expect(client.spawnPty).toHaveBeenCalledWith( + expect.objectContaining({ + name: 'WorkerB', + cli: 'codex', + task: 'Ship it', + spawnMode: 'task_exit', + exitAfterTask: true, + }) + ); + expect(attach).toHaveBeenCalled(); + }); + + it('spawn rejects unknown spawn mode', async () => { + const { program, client, error, exit } = harness(); + await program.parseAsync( + ['local', 'agent', 'spawn', 'codex', '--spawn-mode', 'bogus'], + { from: 'user' } + ); + expect(client.spawnPty).not.toHaveBeenCalled(); + expect(error).toHaveBeenCalledWith(expect.stringContaining('Unknown spawn mode')); + expect(exit).toHaveBeenCalledWith(1); + });🤖 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 `@packages/cli/src/cli/commands/local-agent.test.ts` around lines 70 - 98, The test at line 70-98 provides good coverage for the spawn command's task-exit lifecycle options forwarding, but similar tests are missing for parity. Add tests for the local agent new command that verify it forwards the same task-exit lifecycle options (name, cli, task, spawnMode as task_exit, and exitAfterTask) to client.spawnPty, similar to the spawn test structure. Additionally, add tests that verify both the spawn and new command paths properly reject invalid spawn-mode values that are not supported, ensuring validation consistency between the two command implementations.
🤖 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 @.agentworkforce/trajectories/completed/2026-06/traj_aq4edi70h18a/summary.md:
- Line 41: The token mcp**agent-relay**_ in the summary line has malformed
emphasis markup with mismatched delimiters (starting with ** but ending with _),
which violates markdown linting rule MD037. Fix this by ensuring the emphasis
markup uses consistent delimiters throughout—either replace it with
mcp_agent-relay_ (using underscores on both sides) or mcp**agent-relay** (using
asterisks on both sides), or remove the emphasis entirely depending on the
intended formatting.
---
Nitpick comments:
In `@CHANGELOG.md`:
- Line 12: Rewrite the changelog entry on line 12 to focus on the user-visible
impact rather than implementation details. Remove technical jargon like "spawn
APIs," "task-exit mode," and "/exit" command, and instead express the benefit in
simple terms: that spawned CLI agents can now cleanly complete their task and
exit automatically. Keep the entry concise and outcome-focused, omitting
internal mechanics and API specifics.
In `@packages/cli/src/cli/commands/local-agent.test.ts`:
- Around line 70-98: The test at line 70-98 provides good coverage for the spawn
command's task-exit lifecycle options forwarding, but similar tests are missing
for parity. Add tests for the local agent new command that verify it forwards
the same task-exit lifecycle options (name, cli, task, spawnMode as task_exit,
and exitAfterTask) to client.spawnPty, similar to the spawn test structure.
Additionally, add tests that verify both the spawn and new command paths
properly reject invalid spawn-mode values that are not supported, ensuring
validation consistency between the two command implementations.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 2fa9f7ad-ea65-40a9-a3d1-d65f0ffc7149
📒 Files selected for processing (16)
.agentworkforce/trajectories/completed/2026-06/traj_aq4edi70h18a/summary.md.agentworkforce/trajectories/completed/2026-06/traj_aq4edi70h18a/trajectory.jsonCHANGELOG.mdcrates/broker/src/listen_api.rscrates/broker/src/runtime/api.rscrates/broker/src/runtime/session.rscrates/broker/src/runtime/tests.rspackages/cli/src/cli/agent-relay-mcp.startup.test.tspackages/cli/src/cli/agent-relay-mcp.tspackages/cli/src/cli/commands/local-agent.test.tspackages/cli/src/cli/commands/local-agent.tspackages/cli/src/cli/lib/client-factory.tspackages/harness-driver/src/agent-result.test.tspackages/harness-driver/src/client.tspackages/harness-driver/src/lifecycle-hooks.tspackages/harness-driver/src/types.ts
|
Findings
I applied one mechanical fix:
Addressed comments
Verification
Not printing |
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds eval coverage for the task_exit spawn mode introduced in #1129: - s08-task-exit.ts: directly spawns a worker with EXIT_AFTER_TASK_INSTRUCTION and checks for a clean agent_exited (code 0) event — no lead required - ScenarioResult gains exitConfirmed and exitCode optional fields - Runner gains task-exit group (--group=task-exit) and imports TASK_EXIT_EVAL_SCENARIOS - run-task-exit-evals.sh drives the full matrix: claude (haiku/sonnet/opus), codex (gpt-4.5/gpt-4.1/o3/o4-mini), and opencode in batches of 3 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
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 `@tests/integration/broker/evals/run-task-exit-evals.sh`:
- Around line 66-71: The flush_batch() function at lines 66-71 suppresses all
exit codes from child processes using the || true pattern, causing the script to
ignore eval failures and report success even when runs fail. Remove the || true
suppression from the wait command and instead capture exit codes or exit the
script immediately when a child process fails, ensuring that any failed eval run
causes the overall script to fail. Apply this same fix to the other occurrences
of the flush_batch() function or equivalent wait patterns at lines 84-88 and
156-159.
In `@tests/integration/broker/evals/runner.ts`:
- Around line 142-153: The task-exit group selection routes evals through
mergeRepeats which currently omits the exitConfirmed and exitCode fields from
merged results, causing repeated task-exit evals to lose these newly added
signal fields. Preserve the exitConfirmed and exitCode fields when merging
repeated results in the mergeRepeats function or related merge logic that
processes scenarios for the task-exit group condition, ensuring these fields are
retained in the final merged output.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: fc81eb45-537f-41dc-a8f5-684b35485887
📒 Files selected for processing (10)
CHANGELOG.mdcrates/broker/src/listen_api.rscrates/broker/src/runtime/api.rspackages/cli/src/cli/agent-relay-mcp.startup.test.tspackages/cli/src/cli/agent-relay-mcp.tstests/integration/broker/evals/run-task-exit-evals.shtests/integration/broker/evals/runner.tstests/integration/broker/evals/scenarios/index.tstests/integration/broker/evals/scenarios/s08-task-exit.tstests/integration/broker/evals/types.ts
✅ Files skipped from review due to trivial changes (1)
- tests/integration/broker/evals/scenarios/s08-task-exit.ts
🚧 Files skipped from review as they are similar to previous changes (3)
- packages/cli/src/cli/agent-relay-mcp.startup.test.ts
- crates/broker/src/runtime/api.rs
- crates/broker/src/listen_api.rs
| flush_batch() { | ||
| for pid in "${PIDS[@]:-}"; do | ||
| wait "$pid" 2>/dev/null || true | ||
| done | ||
| PIDS=() | ||
| } |
There was a problem hiding this comment.
Don’t swallow failed eval exits in batch waits.
flush_batch() ignores child failures (wait ... || true), so the script can report success even when one or more eval runs fail.
Suggested fix
PIDS=()
+FAILED=0
flush_batch() {
for pid in "${PIDS[@]:-}"; do
- wait "$pid" 2>/dev/null || true
+ if ! wait "$pid"; then
+ FAILED=1
+ fi
done
PIDS=()
}
@@
- PIDS+=($!)
+ PIDS+=("$!")
@@
echo ""
echo "═══ All logs in $LOG_DIR ════════════════════════════════════════════════"
echo " Reports written to evals-reports/"
+exit "$FAILED"Also applies to: 84-88, 156-159
🤖 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 `@tests/integration/broker/evals/run-task-exit-evals.sh` around lines 66 - 71,
The flush_batch() function at lines 66-71 suppresses all exit codes from child
processes using the || true pattern, causing the script to ignore eval failures
and report success even when runs fail. Remove the || true suppression from the
wait command and instead capture exit codes or exit the script immediately when
a child process fails, ensuring that any failed eval run causes the overall
script to fail. Apply this same fix to the other occurrences of the
flush_batch() function or equivalent wait patterns at lines 84-88 and 156-159.
| : flags.group === 'task-exit' | ||
| ? TASK_EXIT_EVAL_SCENARIOS | ||
| : flags.group === 'all' | ||
| ? ALL_SCENARIOS | ||
| : SCENARIOS; | ||
| if ( | ||
| flags.group === 'lifecycle' || | ||
| flags.group === 'phrasing' || | ||
| flags.group === 'auto-routing' || | ||
| flags.group === 'lead-delegation' | ||
| flags.group === 'lead-delegation' || | ||
| flags.group === 'task-exit' | ||
| ) |
There was a problem hiding this comment.
Preserve task-exit exit signals in repeated runs.
Selecting task-exit here routes runs through mergeRepeats; in Line 159 onward, merged results omit exitConfirmed and exitCode, so repeated task-exit evals lose the newly added signal fields.
Suggested fix
function mergeRepeats(results: ScenarioResult[]): ScenarioResult {
const n = results.length;
const passes = results.filter((r) => r.pass).length;
const adherence = results.filter((r) => r.protocolAdherence !== null);
const first = results[0];
+ const hasExitFields = results.some((r) => r.exitConfirmed !== undefined || r.exitCode !== undefined);
return {
id: first.id,
title: first.title,
pass: passes / n >= 0.5,
@@
releaseCount: results.reduce((s, r) => s + (r.releaseCount ?? 0), 0),
onboarding: first.onboarding,
notes: `${passes}/${n} runs passed` + (first.notes ? ` · ${first.notes}` : ''),
+ ...(hasExitFields
+ ? {
+ exitConfirmed: results.every((r) => r.exitConfirmed === true),
+ exitCode: results.every((r) => r.exitCode === 0) ? 0 : null,
+ }
+ : {}),
};
}🤖 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 `@tests/integration/broker/evals/runner.ts` around lines 142 - 153, The
task-exit group selection routes evals through mergeRepeats which currently
omits the exitConfirmed and exitCode fields from merged results, causing
repeated task-exit evals to lose these newly added signal fields. Preserve the
exitConfirmed and exitCode fields when merging repeated results in the
mergeRepeats function or related merge logic that processes scenarios for the
task-exit group condition, ensuring these fields are retained in the final
merged output.
…output The original approach relied on the model outputting `/exit` as bare text, which the broker PTY watches for but Claude models never emit reliably. The correct task-exit pattern is for the worker to call mcp__agent-relay__remove_agent with its own name, which triggers the broker to kill the PTY via workers.release(). Changes: - s08-task-exit: spawn worker with explicit name in task, wait for agent_released event, score pass = message sent + self-released - broker-harness: thread exitAfterTask through spawnAgent options - fleet.rs: add missing exit_after_task: false to ListenApiRequest::Spawn Verified results (1 run each): claude:haiku PASS claude:sonnet PASS claude:opus PASS codex PASS opencode FAIL (sent=0, no self-release) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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 `@tests/integration/broker/evals/scenarios/s08-task-exit.ts`:
- Around line 39-53: The scenario is not properly validating the task-exit
runtime contract. In the spawnAgent call at lines 39-53, add exitAfterTask: true
to the options object to enable task-exit mode. Then in the event waiters at
lines 47-60, change from waiting for agent_released to waiting for agent_exited
and validate the exit code to confirm actual process termination semantics
rather than just self-release. Apply the same corrections at the sibling
locations at lines 57-63 and 85-86 in the same file to ensure all phases
properly assert agent process exit rather than just agent release.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 30086427-431d-46a4-aec3-8db3d6120e97
📒 Files selected for processing (3)
crates/broker/src/runtime/fleet.rstests/integration/broker/evals/scenarios/s08-task-exit.tstests/integration/broker/utils/broker-harness.ts
| await harness.spawnAgent(worker, cli, ['general'], { task, model }); | ||
| await sleep(STARTUP_MS); | ||
| harness.clearEvents(); | ||
|
|
||
| // Phase 1: wait for the worker to send its task result. | ||
| await harness.waitForEvent('relay_inbound', phaseMs).promise.catch(() => {}); | ||
|
|
||
| // Phase 2: wait for the worker to self-release via remove_agent(own name). | ||
| const releaseWaiter = harness.waitForEvent( | ||
| 'agent_released', | ||
| phaseMs, | ||
| (e) => (e as Extract<BrokerEvent, { kind: 'agent_released' }>).name === worker | ||
| ); | ||
| await releaseWaiter.promise.catch(() => {}); | ||
|
|
There was a problem hiding this comment.
Scenario is validating self-release, not the task-exit runtime contract.
Line [39] does not set exitAfterTask, so regressions in the new spawn-mode plumbing can slip through. Lines [47]-[60] and Line [85] treat agent_released as exit confirmation, which does not assert actual agent process exit semantics (agent_exited + exit code).
Suggested adjustment
- await harness.spawnAgent(worker, cli, ['general'], { task, model });
+ await harness.spawnAgent(worker, cli, ['general'], { task, model, exitAfterTask: true });
- const releaseWaiter = harness.waitForEvent(
- 'agent_released',
- phaseMs,
- (e) => (e as Extract<BrokerEvent, { kind: 'agent_released' }>).name === worker
- );
- await releaseWaiter.promise.catch(() => {});
+ await harness
+ .waitForEvent(
+ 'agent_exited',
+ phaseMs,
+ (e) => (e as Extract<BrokerEvent, { kind: 'agent_exited' }>).name === worker
+ )
+ .promise
+ .catch(() => {});
- const released = events.some(
- (e): e is Extract<BrokerEvent, { kind: 'agent_released' }> =>
- e.kind === 'agent_released' && e.name === worker
- );
- const pass = released && base.sent > 0;
+ const exited = events.some(
+ (e): e is Extract<BrokerEvent, { kind: 'agent_exited' }> =>
+ e.kind === 'agent_exited' && e.name === worker
+ );
+ const pass = exited && base.sent > 0;
- exitConfirmed: released,
+ exitConfirmed: exited,
+ // also populate exitCode from the matched agent_exited eventAlso applies to: 57-63, 85-86
🤖 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 `@tests/integration/broker/evals/scenarios/s08-task-exit.ts` around lines 39 -
53, The scenario is not properly validating the task-exit runtime contract. In
the spawnAgent call at lines 39-53, add exitAfterTask: true to the options
object to enable task-exit mode. Then in the event waiters at lines 47-60,
change from waiting for agent_released to waiting for agent_exited and validate
the exit code to confirm actual process termination semantics rather than just
self-release. Apply the same corrections at the sibling locations at lines 57-63
and 85-86 in the same file to ensure all phases properly assert agent process
exit rather than just agent release.
…opencode /exit output was evaluated for opencode but found unreliable: the model sends the task message but does not produce a bare /exit line the PTY watcher can detect. remove_agent(self) works across all harnesses. Also fixes opencode sent=0 regression: use relay message trigger after startup (matching all other scenario patterns) so the action fires after MCP is up. Verified results: claude:haiku PASS opencode PASS (all previous Claude/codex results unchanged) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…merge The fleet SDK commit (491d9a0) reorganized agent-relay-mcp.ts and inadvertently removed the agent_relay_tool_call telemetry tracking that was added in 1cb41cf. The fleet commit also changed the invoke_action test expectation to NOT fire telemetry (actions API has its own path), so the blanket enableInboxPiggyback wrapper approach no longer fits. Restores tracking by adding inline trackAgentRelayToolCall calls directly to the add_agent and remove_agent handlers, threaded via a new telemetryTransport param on registerAgentRelayTools. invoke_action via the actions API continues to skip agent_relay_tool_call as the fleet commit intended. Also runs npm install to link @agent-relay/fleet into node_modules, fixing the fleet.test.ts module-not-found failure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The generic AGENT_RELAY_TOOL_CALL_METADATA table, readInvokedActionName, agentRelayActionNameCategory, and agentRelayToolCallMetadata were added when restoring telemetry via the enableInboxPiggyback blanket wrapper, but the final approach uses inline calls in add_agent/remove_agent instead. Remove the unused code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
My earlier fix only re-instrumented add_agent/remove_agent inline, which satisfied the failing test but silently dropped agent_relay_tool_call telemetry for the ~28 other owned tools that PR #1041 deliberately instrumented (post_message, send_dm, channels, reactions, inbox, etc.). Restore the original wrapper-based tracking in enableInboxPiggyback so every statically-registered owned tool emits telemetry again, and add a skip for the action-routed path (invoke_action + the dynamic per-action tools in actionToolNames) to honor the fleet SDK commit's intent that registered actions do not route through per-tool telemetry. Reverts the inline handler boilerplate and the registerAgentRelayTools param. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…metry entries Fresh-eyes review follow-ups: - gitignore /opencode.json: the opencode harness writes it to the repo root during eval runs with a live rk_live_ workspace key + at_live_ agent token; it was untracked but not ignored, one `git add .` from a secret leak. - Drop 3 stale AGENT_RELAY_TOOL_CALL_METADATA entries (get_message, get_thread, list_channel_members) — no such tools are registered, so the entries were dead lookups carried over from PR #1041. - Fix run-task-exit-evals.sh header: the s08 scenario self-releases via remove_agent(self), not `/exit` output. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The `spawn` tool delegates to the actions surface (actions.invoke('spawn'))
exactly like `invoke_action` and the dynamic per-action tools, which are
deliberately excluded from agent_relay_tool_call telemetry. Tracking `spawn`
but not `invoke_action({name:'spawn'})` counted the same underlying action
differently depending on which MCP surface the caller used.
Introduce ACTION_ROUTED_TOOL_NAMES ({invoke_action, spawn}) and skip per-tool
telemetry for those names alongside the actionToolNames check. Adds a test
asserting spawn still runs but emits no telemetry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
agent-relay local agent spawn/new --spawn-mode task-exitand--exit-after-taskflags.add_agentwith task-exit options by appending the post-task/exitinstruction.CHANGELOG.md.Verification
cargo test -p agent-relay-broker exit_after_task_instruction_appends_clean_exit_contractcargo test -p agent-relay-broker spawn_route_forwards_extended_fieldsnpx vitest run packages/harness-driver/src/agent-result.test.ts packages/cli/src/cli/commands/local-agent.test.ts packages/cli/src/cli/agent-relay-mcp.startup.test.tsnpm run build:harness-drivernpm --prefix packages/cli run buildNo merge performed.