fix(agent-loop): always close a started turn and any open step on error (P1-5)
After turn/start was appended, nothing guaranteed a matching turn/end: a throw from a boundary emit (agent/turn-start, agent/step-start, the normal-path agent/turn-end) escaped runTurn, and the outer runLoop backstop logged an error but never appended turn/end — leaving an unbalanced turn that replay, telemetry, and the invariants plugin all assume is impossible. runTurn is restructured around idempotent finalizers that satisfy the four traps a naive finally would hit: - closeStep()/closeTurn(emit) are guarded (stepOpen/turnEnded) so they run at most once; the agent/step-end and agent/error emits are contained so a throwing listener can't strand the turn open. - failTurn() records the single error event + reason and emits agent/error exactly once (errorReported guard) — no double-logging when the outer catch also runs (e.g. a step error followed by a throwing turn-end listener). - the catch closes an open step BEFORE turn/end (invariants reject turn/end while a step is open), and rethrows ONLY pre-turn throws (turnStarted false), where no turn/end is owed, so the backstop still nets them. - disposal precedence: reason stays disposed only when disposed AND no error was reported; otherwise the error reason wins. Tests (with the invariants plugin loaded as a balance oracle): throwing turn-start (one error, one turn/end, no step), throwing step-start (step/end before turn/end), throwing agent/error on a step-error path (balanced, loop survives), disposal mid-turn (reason disposed, no error event), a pre-turn turn/start-append throw (rethrown to the backstop, no turn/end owed), and a step error + throwing turn-end listener (error logged exactly once). Verified all six fail against a simulated finalizer bypass. dsh-invariants added as an agent-loop devDependency (test-only oracle; no package cycle).
This commit is contained in:
@@ -558,6 +558,7 @@ __metadata:
|
||||
resolution: "@deepseek-ai/dsh-agent-loop@workspace:packages/agent-loop"
|
||||
dependencies:
|
||||
"@deepseek-ai/dsh-agent": "npm:^0.0.1"
|
||||
"@deepseek-ai/dsh-invariants": "npm:^0.0.1"
|
||||
"@deepseek-ai/dsh-llm": "npm:^0.0.1"
|
||||
"@deepseek-ai/dsh-session": "npm:^0.0.1"
|
||||
"@deepseek-ai/dsh-system-prompt": "npm:^0.0.1"
|
||||
@@ -611,7 +612,7 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@deepseek-ai/dsh-invariants@workspace:packages/invariants":
|
||||
"@deepseek-ai/dsh-invariants@npm:^0.0.1, @deepseek-ai/dsh-invariants@workspace:packages/invariants":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@deepseek-ai/dsh-invariants@workspace:packages/invariants"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user