feat(web,desktop): Luke can start a coding agent from a planning call

Merged
DA
8d ago
+701-178

Dean: "I want Luke to be able to start a new agent as well... the user doesn't have to press the 'Start' button and could simply ask Luke to start an agent to kick off the plan. Luke should also be able to start any coding agent with any instructions."

What changes

  • start_coding_agent (apps/web/server/hosted/coding-agent-tools.ts), a fourth planning tool beside #1960's three: { task?, model?, effort? }. No task starts an agent on the plan exactly as the Start button does; a task starts the task-brief agent #1962's draft creates. Model and effort default to the account's stored default and are checked against the catalog, as a Start is; a refused pair is answered with every offered model and its efforts so Luke can retry or ask. The plan is always the call's. eve's id for the tool call is the idempotency key, so a call run again after a lost answer starts no second agent. The answer is the agent's id, model, effort, and status.
  • One start path (apps/web/server/hosted/coder-host/start.ts): the route's start logic pulled into startCodingAgent, which POST /api/plans/{id}/agents and the tool both call, as steer.ts does for messages. The route still makes a named choice the account's default; the tool does the same through the shared path, so a spoken "start Sonnet on…" is the menu's next default too, as a Start naming Sonnet would be.
  • The trust path (brain-host/auth.ts, coder-host/channel.ts): the deployment's table at eve's door is now keyed by what a message does, opening a session or following one up, and then by turn kind. On main the one typed row already admitted both acts through MESSAGE_ROUTE, so the channel comment's claim that nothing of the deployment's starts an agent was not what the code enforced; the table now says it. The planning channel's rows are unchanged in effect (spoken on both acts); the coder channel's new row is the typed opening, minted as the developer's own principal with the luke:carrier attribute and bounded by the door's ownership check to a conversation the account owns, which is the row the Start made before eve is asked. Everything else stays refused.
  • Luke's behavior (planning instructions, packages/live/src/instructions.ts): start when clearly asked, say in one sentence what was started naming the model, ask first only when it is unclear whether they want an agent or what it should do, never start one unasked, never a second one for the same ask; the agent it started is one the other tools then read and message.
  • Desktop: PLAN_WORK_TOOL.START_AGENT / CALL_KIND.START_AGENT with the verb "Started an agent" and a play icon in the shared tables; the plans tab reads the plan's agents again as a start call in the work answers, so a Luke-started agent's tab appears without a reload (use-plans-tab.ts, startedAgentCallIds in work-model.ts). BrainHost.runTool and the planning tool services now carry ModelCatalog, which the web runtime already provides.

Tests

  • hosted-brain-host-tools.test.ts: the tool starts a plan agent on the default choice as the deployment for the account (eve's opening checked: path, secret, account, conversation, turn, the plan as the first message); the same call id again is the same agent with no second opening; a task agent on an explicit model and effort; an invalid pair refused with the choices; a model without its effort unreadable; no secret starts nothing; the agents it started are what list_coding_agents lists.
  • coder-agent.test.ts: the deployment's typed opening is minted as the developer with the carrier attribute, and a spoken opening is refused.
  • hosted-planning.test.ts lists the new tool; plan-work.test.ts gives it an input so every offered tool reads as a kind of its own.
  • use-plans-tab.test.ts: a running start reads nothing, an answered one reads the list once, the same start seen again reads nothing more, and a start already in the work as the plan opens is read with the plan.
  • The route's existing Start tests pass through the shared path unchanged.
  • No test:agent case: as #1960 found, the eval has no eve origin for the coder service and could only assert a refusal.

Golden

packages/hosted/fixtures/json-schema/live-contract-planWorkFrameSchema.json re-recorded under LUKE_UPDATE_FIXTURES=1: the one change is start-agent added to the tool enum in both places it appears.

Verification

./scripts/check.sh exits 0. CI could not verify the Mac change: CI builds nothing for the Mac and Dean waived verify.sh for this rollout. The desktop change is a row in the Work tab's call-kind tables (verb and icon) and a list re-read in a hook, with no new component, as #1960's was, so there is no screenshot.

🤖 Generated with Claude Code


Open workspace in Conductor


Devin Review