fix(spawn): persist the resolved default agent on the session#221
fix(spawn): persist the resolved default agent on the session#221codebanditssss wants to merge 1 commit into
Conversation
A spawn with no explicit harness ran the daemon default (claude-code) but stored an empty harness: effectiveHarness returned "", seedRecord persisted it, and the empty->default resolution lived only inside agentRegistry.Agent. The API then omitted harness and the UI defaulted to "codex" — mislabelling a Claude Code session. Inject the daemon's default agent (AO_AGENT / config.DefaultAgent) into the session manager and resolve an unspecified harness to it before the seed row is written, so the stored/returned harness matches the agent that actually runs. Closes #220
Greptile SummaryThis PR fixes a bug where spawning a session without an explicit
Confidence Score: 5/5Safe to merge; the change is small, targeted, and adds no new failure modes — it only fills a field before a write that was previously left empty. The fix touches exactly two code sites: one guard in Spawn and one dep field in wiring. Precedence is preserved (explicit harness and per-project role overrides are resolved before the daemon-default fill), existing sessions with an empty harness continue to work via the agent registry's own fallback, and the new test covers both the default-fill and the explicit-override path. No data migration is needed and the PR notes the forward-compatibility concern clearly. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant caller as CLI / API caller
participant wiring as lifecycle_wiring.go
participant mgr as Manager.Spawn
participant store as Store.CreateSession
participant resolver as agentRegistry.Agent
Note over wiring: cfg.Agent == empty → defaultAgent = config.DefaultAgent
wiring->>wiring: resolve defaultAgent once
wiring->>mgr: "New(Deps{DefaultHarness: defaultAgent})"
wiring->>resolver: buildAgentResolver(defaultAgent)
caller->>mgr: "Spawn(cfg{Harness: empty})"
mgr->>mgr: effectiveHarness(empty, kind, projectCfg) → empty
mgr->>mgr: "cfg.Harness empty → cfg.Harness = defaultHarness (NEW)"
mgr->>store: "CreateSession(seedRecord{Harness: claude-code})"
store-->>mgr: "SessionRecord{Harness: claude-code}"
mgr->>resolver: Agent(claude-code)
resolver-->>mgr: claudeCodeAdapter
mgr->>mgr: runtime.Create(...)
mgr-->>caller: "SessionRecord{Harness: claude-code}"
Note over caller: API/UI now sees harness=claude-code, not empty
Reviews (1): Last reviewed commit: "fix(spawn): persist the resolved default..." | Re-trigger Greptile |
Closes #220.
Problem
A worker/orchestrator spawned without an explicit
--harnessruns the daemon's default agent (claude-code) but stored an empty harness. Caught live: a session running Claude Code showedAgent: codexin the inspector, andGET /api/v1/sessionsreturned noharness.Root cause:
effectiveHarness("", …)returns"",seedRecordpersists it, and the empty→default resolution lives only insideagentRegistry.Agent(lifecycle_wiring.go) — never written back. The empty harness is then omitted from the DTO, so the frontend'stoAgentProvider(undefined)falls back to"codex".Change
Inject the daemon's default agent (
AO_AGENT/config.DefaultAgent) into the session manager and resolve an unspecified harness to it before the seed row is written — so the stored/returned harness matches the agent that actually launches. Backend-only: onceharnessis present, the frontend already mapsclaude-code→ its label correctly.Test
TestSpawn_PersistsResolvedDefaultHarness: an unspecified harness persists the injected default; an explicit harness still wins.go build ./..., fullgo test ./...,gofmt,golangci-lintall clean.ao spawnwith no--harnessnow returnsharness = "claude-code"(was empty).Notes
toAgentProviderdefault as-is; it's now rarely reached since the API always carries the real harness. A follow-up could make that fallback "unknown" rather than "codex".