Every chat session now runs through the Hermes bridge, so the three chat chains become feature-equivalent instead of three partially-maintained dispatch paths. Keeping the coding-agent and in-house agent runtimes alive meant every bridge change had to be mirrored into two more runtimes that had already drifted. Historical rows are read, not migrated: sessions stored with the retired source normalize to cli on load, workflow graphs naming the retired agents keep loading and run on the bridge, and the visible-source check plus SOURCE_LABELS still recognize the old value so those sessions stay listed. The public surface follows the code: the OpenAPI generator and the MCP chat-run tool schema drop the six retired entry fields so external callers are not told about runtimes that no longer exist. harness-check gains a RETIRED_RUNTIME scan so the residual check is a mechanical gate instead of a manual grep, with the two surviving read-side compat sites recorded with reasons. Refs: docs/phases/phase_003.md
4.4 KiB
date, pr, feature, impact
| date | pr | feature | impact |
|---|---|---|---|
| 2026-10-16 | pending | Phase 003 - remove the coding-agent and ekko-agent runtimes | Every chat session now runs through the Hermes bridge; sessions stored with the old `coding_agent` source are normalized to `cli` on load. |
Phase 003 — Remove the coding-agent and ekko-agent runtimes
Phase: docs/phases/phase_003.md (groups I and J)
What Changed
The chat chain had three dispatch branches: bridge, coding agent (Claude Code / Codex), and ekko-agent. Phase 003 deletes the latter two, leaving the bridge as the single execution path.
Deleted modules
packages/server/src/services/agent-runner/— 13 files. Adapters for the Anthropic and OpenAI Responses streaming shapes, the Claude Code / Codex HTTP proxies, the SSE helpers, andcoding-agent-run-manager.packages/server/src/services/ekko-agent/— 2 files (manager.ts,mcp.ts).packages/ekko-agent/— the in-house agent runtime package.run-chat/handle-coding-agent-run.ts,run-chat/handle-ekko-agent-run.ts.run-chat/sse-utils.ts— an orphan that only re-exportedagent-runner/sse. No production module imported it; the single remaining reference was avi.mockinrun-chat-load-state.test.ts.- The three route modules, the controller, the service,
CodingAgentsView.vue, andpackages/client/src/api/coding-agents.ts.
Dispatch
runAndWait in run-chat/index.ts was a three-way branch. It is now a single
call to handleBridgeRun. Two predicates went away with it:
isCodingAgentExecution(source, data)isEkkoAgentExecution(data)
isWorking was computed as !isCodingAgentExecution(...) at three call sites
(queue start, direct run start, resumed run). All three are now true.
Types and session fields
ChatCodingAgentId— defined twice (serverrun-chat/types.ts, clientapi/coding-agents.ts). Both definitions are gone; nothing imports them now.ChatRunSourcelost'coding_agent'.QueuedRunlostcodingAgentId/agentId.StartRunRequestlostcoding_agent_id/agent_id.- The client
Sessionshape lostcodingAgentId/codingAgentMode.
ChatRunSource compatibility
resolveRunSource previously passed 'coding_agent' through. It now falls
through to the default 'cli', so sessions stored with the old source run
through the bridge without a data migration. The same is true for the
value-based checks in controllers/hermes/sessions.ts — they read the stored
string, and any source that is not global_agent or workflow resolves to the
bridge path.
isCodingAgentSession in the sessions controller controlled three things at
once: whether a workspace was created, whether the bridge was notified of a
model change, and whether agent_native_session_id was cleared. All three now
apply to every session, which is the intended post-Phase-003 behavior.
Workflow
WorkflowNodeAgent narrowed to 'hermes'. resolveWorkflowNodeRunTarget
ignores its argument and always returns the Hermes target, so saved workflows
that still name claude-code or codex keep loading. The node editor's
protocol dropdown and the apiModeRequired validation were removed, along with
the apiMode field on WorkflowAgentNodeData.
Usage recording
RecordSessionUsageInput.source and .agent narrowed to 'hermes'. The only
caller is handle-bridge-run.ts, which already passed those values. Rows
written before this phase keep their stored source / agent strings; the
client's AgentBreakdown maps anything it does not recognize to unknown.
Contract Check
/chat-run event names, field names, and field types are unchanged. The
socket.start_run payload only ever sent coding_agent_id / agent_id for
sessions that were already coding-agent sessions; nothing new is sent. Two
optional request fields were removed, and every session that used them now
takes the bridge path instead.
Residual Strings
Kept on purpose, so existing records still render a sensible label:
packages/client/src/shared/session-display.ts—coding_agent: 'Coding Agent'inSOURCE_LABELS, which labels sessions already stored in the DB.packages/server/src/controllers/hermes/sessions.ts— theisVisibleWebUiSessionSourcecheck still lists'coding_agent'so old sessions stay visible in the Web UI session list.
Both are registered in the scripts/harness-check.mjs allow-list.
Verification
npm run harness:check
npm run build
npm run test