Skip to content

Thread spawn model from request through to the spawn event#180

Merged
khaliqgant merged 3 commits into
mainfrom
fix/spawn-model-passthrough
Jun 10, 2026
Merged

Thread spawn model from request through to the spawn event#180
khaliqgant merged 3 commits into
mainfrom
fix/spawn-model-passthrough

Conversation

@khaliqgant

Copy link
Copy Markdown
Member

Problem

A caller cannot choose the model a spawned worker boots with. The Agent Relay add_agent MCP model arg was only stored as agent metadata and never reached the broker that launches the CLI, so workers always booted with the session default (Opus) regardless of the requested model.

Change

Threads an optional model through the spawn path:

  • types/agent.tsSpawnAgentRequestSchema accepts optional model.
  • types/events.tsAgentSpawnRequestedEventSchema carries model on the emitted agent payload.
  • engine/routes/agent.ts/v1/agents/spawn reads model, folds it into agent metadata (so it stays visible via list_agents) and includes it in the spawn event data.
  • engine/wsTransform.ts — passes model through on agent.spawn_requested.
  • sdk-rust/types.rsmodel on SpawnAgentRequest and AgentSpawnRequestedPayload.

The TS SDK agents.spawn forwards the whole request body, so it picks up model automatically once the type includes it.

Verified

  • packages/types tsc --noEmit clean.
  • packages/sdk-rust cargo check clean.

(engine/sdk-typescript show only pre-existing env noise — missing better-sqlite3/ws types and stale @relaycast/types dist — none in the changed files.)

Downstream / release

This is the gating half of a two-repo fix. The consumer is AgentWorkforce/relay (branch fix/spawn-model-passthrough, draft), whose MCP/SDK/broker pass model end-to-end to --model. relay consumes the published @relaycast/sdk + relaycast crate, so after this merges it needs a relaycast publish (npm @relaycast/sdk/@relaycast/types + the relaycast crate), then relay bumps those deps. Note: this local checkout was behind published versions — apply onto current main before releasing.

🤖 Generated with Claude Code

khaliqgant and others added 2 commits June 3, 2026 13:25
Adds an optional `model` to the agent spawn path so a caller (e.g. the
Agent Relay `add_agent` MCP tool) can choose the model a spawned worker
boots with. Previously `model` had nowhere to travel: it was only stored
as agent metadata and never reached the broker that launches the CLI.

- SpawnAgentRequestSchema (types/agent.ts): accept optional `model`.
- AgentSpawnRequestedEventSchema (types/events.ts): carry `model` on the
  emitted event's agent payload.
- /v1/agents/spawn route: read `model`, fold it into the agent metadata
  (so it stays visible via list_agents) and include it in the spawn
  event data.
- wsTransform: pass `model` through on agent.spawn_requested.
- sdk-rust: add `model` to SpawnAgentRequest and AgentSpawnRequestedPayload.

The TS SDK `agents.spawn` forwards the whole request body, so it picks up
`model` automatically once the type includes it.

Verified: `packages/types` tsc clean; `sdk-rust` cargo check clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codeant-ai

codeant-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR extends agent spawn request and event handling to include an optional model field throughout the system. TypeScript and Rust types are updated to accept the model, the backend spawn handler persists it to agent metadata and emits it in events, and SDK implementations across Rust and Python are updated accordingly.

Changes

Agent Spawn Model Field

Layer / File(s) Summary
Type and schema definitions
packages/types/src/agent.ts, packages/types/src/events.ts, packages/sdk-rust/src/types.rs
SpawnAgentRequestSchema and AgentSpawnRequestedEventSchema (TypeScript) and SpawnAgentRequest and AgentSpawnRequestedPayload (Rust) now include an optional model: Option<String> / string | null field to support model tracking.
Backend spawn handler and event emission
packages/engine/src/routes/agent.ts
POST /v1/agents/spawn handler now reads and validates optional model from the request, merges it into agent metadata, and includes it in agent.spawn_requested events sent to fanout and webhook queues.
Client-facing event transformation
packages/engine/src/engine/wsTransform.ts
transformForClient now serializes the model field from spawn-requested events to clients, normalized to null when absent.
SDK implementations and tests
packages/sdk-rust/src/registration.rs, packages/sdk-python/tests/test_imports.py, packages/sdk-python/tests/test_ws.py
Rust agent registration client and Python SDK tests are updated to initialize and assert the model field; version assertions are switched to use SDK_VERSION constant.
Integration test
packages/sdk-rust/tests/parity.rs
Parity test for spawn endpoint now includes model field in both the mocked HTTP request and the SpawnAgentRequest passed to the client library.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A model field hops through the spawn,
From request to metadata, dawn to dawn,
Events now carry what agents shall be,
Across all the SDKs, consistent and free!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% 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
Title check ✅ Passed The title clearly and specifically summarizes the main change: threading the optional model field from spawn requests through to the spawn event across the codebase.
Description check ✅ Passed The description is directly related to the changeset, explaining the problem, the solution across multiple files, verification steps, and downstream implications.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 fix/spawn-model-passthrough

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 and usage tips.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces support for a model parameter when spawning an agent. It updates the TypeScript/Zod and Rust schemas, persists the requested model into the agent's metadata, and includes it in WebSocket spawn events. Additionally, Python SDK tests are updated to dynamically reference the SDK version instead of using hardcoded version strings. A review comment suggests using a strict undefined check (model !== undefined) instead of a truthiness check when merging the model into the metadata to ensure that explicit falsy values (like null or empty strings) are correctly persisted.

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.

metadata,
// Persist the requested model into agent metadata so it is visible via
// list_agents, in addition to being emitted on the spawn event below.
metadata: model ? { ...(metadata ?? {}), model } : metadata,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using a truthiness check (model ? ...) will prevent explicitly passed falsy values (such as null or an empty string "") from being persisted in the agent's metadata. Since model is optional and nullable (z.string().nullable().optional()), checking model !== undefined is more robust and ensures that explicit null or empty string values are correctly propagated and stored.

Suggested change
metadata: model ? { ...(metadata ?? {}), model } : metadata,
metadata: model !== undefined ? { ...(metadata ?? {}), model } : metadata,

The Rust SDK build broke after adding `model` to SpawnAgentRequest: the
broker self-registration path (registration.rs) and the parity test both
construct the struct with explicit fields. Add `model` to both.

- registration.rs: `model: None` (worker-session auto-registration has no
  caller-chosen model).
- parity.rs: set `model` and assert it appears in the serialized
  /v1/agents/spawn body, proving the field flows through the request.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@codeant-ai

codeant-ai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI.

@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: 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 `@packages/engine/src/routes/agent.ts`:
- Around line 351-354: The metadata persistence uses a truthy check that drops
valid empty-string models; change the conditional in the object construction
that sets metadata to use a nullish check so empty strings remain persisted
(i.e., replace the existing "model ? { ...(metadata ?? {}), model } : metadata"
logic with a nullish-aware check using model ?? to decide whether to include
model in metadata), updating the code around the metadata assignment so
persisted metadata and the emitted spawn event use the same model presence
semantics.
🪄 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: 9cb54c96-b064-458c-a1fa-35a1a77771d1

📥 Commits

Reviewing files that changed from the base of the PR and between bf4d569 and b132d0b.

📒 Files selected for processing (9)
  • packages/engine/src/engine/wsTransform.ts
  • packages/engine/src/routes/agent.ts
  • packages/sdk-python/tests/test_imports.py
  • packages/sdk-python/tests/test_ws.py
  • packages/sdk-rust/src/registration.rs
  • packages/sdk-rust/src/types.rs
  • packages/sdk-rust/tests/parity.rs
  • packages/types/src/agent.ts
  • packages/types/src/events.ts

Comment on lines +351 to 354
// Persist the requested model into agent metadata so it is visible via
// list_agents, in addition to being emitted on the spawn event below.
metadata: model ? { ...(metadata ?? {}), model } : metadata,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use a nullish check when persisting model into metadata.

model ? ... drops valid empty-string inputs, while the emitted event still includes model via model ?? null. This creates inconsistent persisted vs emitted data.

Suggested fix
+      const hasExplicitModel = model !== undefined && model !== null;
       const result = await agentEngine.spawnAgent(db, workspace.id, {
         name,
         cli,
         task,
         channel: channel ?? undefined,
         persona: persona ?? undefined,
         // Persist the requested model into agent metadata so it is visible via
         // list_agents, in addition to being emitted on the spawn event below.
-        metadata: model ? { ...(metadata ?? {}), model } : metadata,
+        metadata: hasExplicitModel ? { ...(metadata ?? {}), model } : metadata,
       });
🤖 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/engine/src/routes/agent.ts` around lines 351 - 354, The metadata
persistence uses a truthy check that drops valid empty-string models; change the
conditional in the object construction that sets metadata to use a nullish check
so empty strings remain persisted (i.e., replace the existing "model ? {
...(metadata ?? {}), model } : metadata" logic with a nullish-aware check using
model ?? to decide whether to include model in metadata), updating the code
around the metadata assignment so persisted metadata and the emitted spawn event
use the same model presence semantics.

@khaliqgant khaliqgant merged commit 36db877 into main Jun 10, 2026
5 checks passed
@khaliqgant khaliqgant deleted the fix/spawn-model-passthrough branch June 10, 2026 09:20
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.

1 participant