fix(agent-runtime): three correctness bugs in adapter and legacy-bridge - #263
Conversation
claudiusthebot
left a comment
There was a problem hiding this comment.
All three bugs are real and the fixes are correct. 34/34 CI β .
Bug 1 (adapter.ts sessions capability): The || β AND guard is the right fix. If only warmSession is defined, advertising sessions capability and providing a no-op resetChat() is a silent contract breach. The fix is minimal and precise.
Bug 2 (legacy-bridge.ts non-plain-object inputs): Adding console.warn instead of silently discarding is the right call. No data loss path changes, but operators now get visibility when a Phase 3 backend emits array-shaped tool inputs before the bridge strips them. The "bridge to {}" behaviour is preserved intentionally β a hard throw would break existing callers.
Bug 3 (legacy-bridge.ts dead saw variable): Clean removal. The ...(saw ? {} : {}) spread was truly a no-op in both branches β not even a future footgun, just misleading dead code. The updated comment is clearer.
One observation for when Dylan reads this: Bug 1 could silently surface in Phase 3+ if any new backend (e.g. the antigravity or agy wrappers) implements warmSession but not resetChat. Worth a grep before the Phase 3 backend refactor lands.
1. adapter.ts β sessions capability falsely advertised when only
warmSession is defined. The old condition (resetChat || warmSession)
created a SessionBackend whose resetChat silently returned undefined,
misleading callers that checked capabilities.sessions into believing
they could reset the session. Guard is now resetChat-only; warmSession
is still forwarded when present alongside resetChat.
2. legacy-bridge.ts β non-plain-object tool inputs silently dropped.
pipeEventsToCallbacks converted any tool_call input that was not a
plain object (e.g. an array, which is valid for tool_call.input:
unknown) to {} without any diagnostic. A console.warn now surfaces
the data loss so operators can identify Phase-3 backends emitting
array-shaped tool inputs before the legacy bridge strips them.
3. legacy-bridge.ts β dead-code saw variable in reduceEventsToResult.
The spread ...(saw ? {} : {}) evaluated to an empty object in both
branches, making the saw flag have no effect on the returned value.
Removed the variable and fixed the comment to accurately describe
when the synthesised-result path is taken.
https://claude.ai/code/session_01Ddo8qvtcTtq5NVU4SkwCCP
e540787 to
0427adc
Compare
Summary
Deep code review of the
main...HEADdiff surfaced three correctness bugs in the newagent-runtimeinfrastructure (Phase 1β2). All are in code that has no production callers yet, which means they would have silently shipped as-is into Phase 3+ without being caught by tests. All 2990 tests pass before and after this fix.Bug 1 β
adapter.ts:sessionscapability falsely advertised when onlywarmSessionis definedFile:
src/core/agent-runtime/adapter.tsRoot cause:
If a legacy backend defined only
warmSession(noresetChat), the adapter would:capabilities.sessions = truesessions.resetChat()method that callslegacy.resetChat?.()β which returnsundefinedand does nothingCallers checking
backend.capabilities.sessionswould believe the backend supports session reset, callsessions.resetChat(chatId), and silently get a no-op. No error, no log, no reset.Fix: Guard session object creation on
legacy.resetChatbeing defined.warmSessionis still forwarded when both are present.Bug 2 β
legacy-bridge.ts: non-plain-object tool inputs silently discardedFile:
src/core/agent-runtime/legacy-bridge.tsRoot cause:
The
tool_callevent inevents.tstypesinputasunknownβ valid values include arrays and other non-plain objects. The legacyonToolUsecallback requiresRecord<string, unknown>, so the bridge must convert. The old code silently replaced any non-plain-object input with{}:A Phase 3 backend emitting
{ type: "tool_call", name: "write_file", input: ["a", "b"] }would silently have["a", "b"]replaced with{}before reachingonToolUse. The tool would receive empty arguments.Fix: Add a
console.warnwhen data loss occurs, so operators can identify backends producing array-shaped tool inputs before the bridge strips them.Bug 3 β
legacy-bridge.ts: dead-codesawvariable inreduceEventsToResultFile:
src/core/agent-runtime/legacy-bridge.tsRoot cause:
...(saw ? {} : {})always spreads an empty object. Thesawflag was computed correctly (settruewhen acompletedevent with a falsy result was seen) but had no effect on the returned value. The comment claimed it distinguished a "silent-stream path" β but both paths produced identical output. This is dead code that would mislead any future engineer extendingreduceEventsToResult.Fix: Remove the
sawvariable and its meaningless spread; clarify the comment.Test results
https://claude.ai/code/session_01Ddo8qvtcTtq5NVU4SkwCCP
Generated by Claude Code