@duetso/agent 0.1.80 → 0.1.82

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/memory/observational.d.ts +8 -1
  3. package/dist/src/memory/observational.d.ts.map +1 -1
  4. package/dist/src/memory/observational.js +9 -3
  5. package/dist/src/memory/observational.js.map +1 -1
  6. package/dist/src/session/session.d.ts +31 -13
  7. package/dist/src/session/session.d.ts.map +1 -1
  8. package/dist/src/session/session.js +63 -23
  9. package/dist/src/session/session.js.map +1 -1
  10. package/dist/src/tui/app.d.ts +25 -35
  11. package/dist/src/tui/app.d.ts.map +1 -1
  12. package/dist/src/tui/app.js +195 -2308
  13. package/dist/src/tui/app.js.map +1 -1
  14. package/dist/src/tui/autocomplete-controller.d.ts +83 -0
  15. package/dist/src/tui/autocomplete-controller.d.ts.map +1 -0
  16. package/dist/src/tui/autocomplete-controller.js +308 -0
  17. package/dist/src/tui/autocomplete-controller.js.map +1 -0
  18. package/dist/src/tui/boot-screen.d.ts +64 -0
  19. package/dist/src/tui/boot-screen.d.ts.map +1 -0
  20. package/dist/src/tui/boot-screen.js +137 -0
  21. package/dist/src/tui/boot-screen.js.map +1 -0
  22. package/dist/src/tui/controllers.d.ts +39 -0
  23. package/dist/src/tui/controllers.d.ts.map +1 -0
  24. package/dist/src/tui/controllers.js +53 -0
  25. package/dist/src/tui/controllers.js.map +1 -0
  26. package/dist/src/tui/copy-controller.d.ts +75 -0
  27. package/dist/src/tui/copy-controller.d.ts.map +1 -0
  28. package/dist/src/tui/copy-controller.js +140 -0
  29. package/dist/src/tui/copy-controller.js.map +1 -0
  30. package/dist/src/tui/history-replay.d.ts +33 -0
  31. package/dist/src/tui/history-replay.d.ts.map +1 -0
  32. package/dist/src/tui/history-replay.js +47 -0
  33. package/dist/src/tui/history-replay.js.map +1 -0
  34. package/dist/src/tui/initial-prompt.d.ts +24 -0
  35. package/dist/src/tui/initial-prompt.d.ts.map +1 -0
  36. package/dist/src/tui/initial-prompt.js +29 -0
  37. package/dist/src/tui/initial-prompt.js.map +1 -0
  38. package/dist/src/tui/key-handlers.d.ts +49 -0
  39. package/dist/src/tui/key-handlers.d.ts.map +1 -0
  40. package/dist/src/tui/key-handlers.js +192 -0
  41. package/dist/src/tui/key-handlers.js.map +1 -0
  42. package/dist/src/tui/layout.d.ts +71 -0
  43. package/dist/src/tui/layout.d.ts.map +1 -0
  44. package/dist/src/tui/layout.js +245 -0
  45. package/dist/src/tui/layout.js.map +1 -0
  46. package/dist/src/tui/paste-controller.d.ts +90 -0
  47. package/dist/src/tui/paste-controller.d.ts.map +1 -0
  48. package/dist/src/tui/paste-controller.js +234 -0
  49. package/dist/src/tui/paste-controller.js.map +1 -0
  50. package/dist/src/tui/question-picker.d.ts +111 -0
  51. package/dist/src/tui/question-picker.d.ts.map +1 -0
  52. package/dist/src/tui/question-picker.js +308 -0
  53. package/dist/src/tui/question-picker.js.map +1 -0
  54. package/dist/src/tui/renderer-lifecycle.d.ts +20 -0
  55. package/dist/src/tui/renderer-lifecycle.d.ts.map +1 -0
  56. package/dist/src/tui/renderer-lifecycle.js +50 -0
  57. package/dist/src/tui/renderer-lifecycle.js.map +1 -0
  58. package/dist/src/tui/session-subscription.d.ts +30 -0
  59. package/dist/src/tui/session-subscription.d.ts.map +1 -0
  60. package/dist/src/tui/session-subscription.js +78 -0
  61. package/dist/src/tui/session-subscription.js.map +1 -0
  62. package/dist/src/tui/sidebar.d.ts +2 -2
  63. package/dist/src/tui/sidebar.d.ts.map +1 -1
  64. package/dist/src/tui/sidebar.js +1 -1
  65. package/dist/src/tui/sidebar.js.map +1 -1
  66. package/dist/src/tui/slash-commands.d.ts +23 -0
  67. package/dist/src/tui/slash-commands.d.ts.map +1 -0
  68. package/dist/src/tui/slash-commands.js +79 -0
  69. package/dist/src/tui/slash-commands.js.map +1 -0
  70. package/dist/src/tui/starter-section.d.ts +99 -0
  71. package/dist/src/tui/starter-section.d.ts.map +1 -0
  72. package/dist/src/tui/starter-section.js +254 -0
  73. package/dist/src/tui/starter-section.js.map +1 -0
  74. package/dist/src/tui/status-controller.d.ts +94 -0
  75. package/dist/src/tui/status-controller.d.ts.map +1 -0
  76. package/dist/src/tui/status-controller.js +186 -0
  77. package/dist/src/tui/status-controller.js.map +1 -0
  78. package/dist/src/tui/step-renderer.d.ts +55 -0
  79. package/dist/src/tui/step-renderer.d.ts.map +1 -0
  80. package/dist/src/tui/step-renderer.js +246 -0
  81. package/dist/src/tui/step-renderer.js.map +1 -0
  82. package/dist/src/tui/transcript-writer.d.ts +63 -0
  83. package/dist/src/tui/transcript-writer.d.ts.map +1 -0
  84. package/dist/src/tui/transcript-writer.js +130 -0
  85. package/dist/src/tui/transcript-writer.js.map +1 -0
  86. package/dist/src/turn-runner/turn-runner.d.ts +77 -1
  87. package/dist/src/turn-runner/turn-runner.d.ts.map +1 -1
  88. package/dist/src/turn-runner/turn-runner.js +150 -12
  89. package/dist/src/turn-runner/turn-runner.js.map +1 -1
  90. package/dist/src/turn-runner/usage-accounting.d.ts +18 -1
  91. package/dist/src/turn-runner/usage-accounting.d.ts.map +1 -1
  92. package/dist/src/turn-runner/usage-accounting.js +48 -27
  93. package/dist/src/turn-runner/usage-accounting.js.map +1 -1
  94. package/dist/src/types/protocol.d.ts +48 -17
  95. package/dist/src/types/protocol.d.ts.map +1 -1
  96. package/package.json +1 -1
@@ -0,0 +1,130 @@
1
+ import { TextRenderable, } from "@opentui/core";
2
+ import { COLORS } from "./theme.js";
3
+ /**
4
+ * Owns every write to the transcript ScrollBox plus the `/diag` key+selection
5
+ * event log. Centralizing here keeps the post-teardown try/catch that swallows
6
+ * "TextBuffer is destroyed" in exactly one place (v0.1.68 fix), and gives the
7
+ * status/hint controllers a single `isDestroyed()` source of truth.
8
+ */
9
+ export class TranscriptWriter {
10
+ renderer;
11
+ transcript;
12
+ options;
13
+ destroyed = false;
14
+ hasRenderedAnyBlock = false;
15
+ keyDiagnostics = false;
16
+ log = [];
17
+ constructor(renderer, transcript, options) {
18
+ this.renderer = renderer;
19
+ this.transcript = transcript;
20
+ this.options = options;
21
+ }
22
+ // ---- transcript writes ---------------------------------------------------
23
+ /** Append a single line. Empty content is ignored so callers can guard with
24
+ * raw input without producing blank rows; use `addLine` instead when a
25
+ * spacer is wanted and a renderable handle is needed. */
26
+ appendLine(content, fg) {
27
+ if (!content)
28
+ return;
29
+ if (this.destroyed)
30
+ return;
31
+ try {
32
+ const line = new TextRenderable(this.renderer, { content, fg });
33
+ this.transcript.add(line);
34
+ }
35
+ catch (error) {
36
+ if (isTextBufferDestroyedError(error)) {
37
+ this.handleBufferDestroyed();
38
+ return;
39
+ }
40
+ throw error;
41
+ }
42
+ }
43
+ /** Append a labelled block. `beginBlock()` inserts a blank separator before
44
+ * every block except the first so distinct steps stay visually distinct. */
45
+ appendBlock(label, body, fg) {
46
+ this.beginBlock();
47
+ const text = label ? `${label}\n${body}` : body;
48
+ for (const line of text.split("\n"))
49
+ this.appendLine(line, fg);
50
+ }
51
+ beginBlock() {
52
+ if (this.hasRenderedAnyBlock)
53
+ this.appendLine(" ", COLORS.hint);
54
+ this.hasRenderedAnyBlock = true;
55
+ }
56
+ /** Append a line and return the renderable handle. Used by the starter
57
+ * block (which destroys its own refs on dismiss) and substitutes a single
58
+ * space for empty content so the renderable still occupies a row. */
59
+ addLine(content, fg) {
60
+ const line = new TextRenderable(this.renderer, { content: content || " ", fg });
61
+ this.transcript.add(line);
62
+ return line;
63
+ }
64
+ // ---- transcript log ------------------------------------------------------
65
+ /** Records a user/agent message body in the parallel log read by `/copy`
66
+ * and the copy keystroke. Trims and drops empty payloads so noisy
67
+ * presentation-only writes (spacers, etc.) do not pollute the log. */
68
+ recordEntry(kind, text) {
69
+ const trimmed = text.trim();
70
+ if (!trimmed)
71
+ return;
72
+ this.log.push({ kind, text: trimmed });
73
+ }
74
+ entries() {
75
+ return this.log;
76
+ }
77
+ // ---- teardown ------------------------------------------------------------
78
+ /** Flipped from the renderer `destroy` handler. Subsequent transcript
79
+ * writes short-circuit instead of throwing from a destroyed buffer. */
80
+ markDestroyed() {
81
+ this.destroyed = true;
82
+ }
83
+ isDestroyed() {
84
+ return this.destroyed;
85
+ }
86
+ // ---- /diag key + selection logging ---------------------------------------
87
+ setKeyDiagnosticsEnabled(enabled) {
88
+ this.keyDiagnostics = enabled;
89
+ }
90
+ isKeyDiagnosticsEnabled() {
91
+ return this.keyDiagnostics;
92
+ }
93
+ logKey(label, key) {
94
+ if (!this.keyDiagnostics)
95
+ return;
96
+ const flags = [];
97
+ if (key.ctrl)
98
+ flags.push("ctrl");
99
+ if (key.shift)
100
+ flags.push("shift");
101
+ if (key.meta)
102
+ flags.push("meta");
103
+ if (key.super)
104
+ flags.push("super");
105
+ if (key.option)
106
+ flags.push("option");
107
+ const selection = this.options.getLastSelectionText();
108
+ this.appendBlock("[diag]", `${label} name=${JSON.stringify(key.name)} flags=[${flags.join(",")}] sequence=${JSON.stringify(key.sequence)} source=${key.source} | lastSelection=${selection.length}c rendererSel=${this.renderer.hasSelection ? "yes" : "no"}`, COLORS.hint);
109
+ }
110
+ logSelection(text) {
111
+ if (!this.keyDiagnostics)
112
+ return;
113
+ this.appendBlock("[diag]", `selection event: ${text.length} chars — ${JSON.stringify(text.slice(0, 80))}`, COLORS.hint);
114
+ }
115
+ handleBufferDestroyed() {
116
+ this.destroyed = true;
117
+ this.options.onBufferDestroyed?.();
118
+ }
119
+ }
120
+ /**
121
+ * OpenTUI's TextBuffer throws a plain Error with this exact message from its
122
+ * `guard()` method when any setter is touched after destroy. We sniff the
123
+ * message to distinguish post-teardown races (swallow) from real bugs
124
+ * (rethrow). Exported so the status/hint controllers can share the same
125
+ * sniff without re-importing OpenTUI internals.
126
+ */
127
+ export function isTextBufferDestroyedError(error) {
128
+ return error instanceof Error && error.message === "TextBuffer is destroyed";
129
+ }
130
+ //# sourceMappingURL=transcript-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transcript-writer.js","sourceRoot":"","sources":["../../../src/tui/transcript-writer.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import { MemoryContextCache } from "../memory/store.js";
6
6
  import type { TurnRunnerConfig } from "../types/config.js";
7
7
  import type { TurnAgentFile, TurnAnswerCommand, TurnContextWindowUsage, TurnEditFollowUpQueueCommand, TurnEvent, TurnInterruptCommand, TurnMode, TurnPromptCommand, TurnState, TurnTokenUsage, TurnStartCommand, TurnTerminalEvent, TurnCommand, TurnOptions } from "../types/protocol.js";
8
8
  import type { StateMachineAgentState } from "../types/state-machine.js";
9
+ import { type WireGuardHorizon } from "./wire-shaping.js";
9
10
  import { type TurnRunnerControlResult } from "./tools.js";
10
11
  import { SkillContext } from "./skill-context.js";
11
12
  import { type StateAgentHandle } from "./state-machine-controller.js";
@@ -76,6 +77,21 @@ export declare class TurnRunner {
76
77
  private started;
77
78
  /** Aggregates model usage across parent agents, state agents, and memory work for one turn chain. */
78
79
  private turnUsage?;
80
+ /**
81
+ * Snapshot of the latest parent assistant `message_end`'s bar fields.
82
+ * State-agent and terminal emissions reuse these so the bar/breakdown
83
+ * does not jitter mid-turn when only a state agent advanced cost.
84
+ *
85
+ * Always set by the time a state agent runs in production: the parent
86
+ * worker selects a state via a real LLM call, which emits `message_end`
87
+ * and populates this. Exposed as `protected` for test harnesses that
88
+ * stub `runAgentWorker` past the real parent path and need to seed the
89
+ * snapshot before driving a state-agent emission.
90
+ */
91
+ protected lastParentUsageSnapshot?: {
92
+ effectiveContextWindow: number;
93
+ contextWindowUsage: TurnContextWindowUsage;
94
+ };
79
95
  /** Ensures persisted memory hydrates once before the first turn that needs it. */
80
96
  private memoryLoaded;
81
97
  /** MCP servers connected during start(). Disposed on runner.dispose(). */
@@ -162,7 +178,56 @@ export declare class TurnRunner {
162
178
  protected runAgentMode(state: TurnState, prompt: string, images?: ImageContent[]): Promise<TurnTerminalEvent>;
163
179
  protected runAgentWorker(input: AgentWorkerInput): Promise<AgentWorkerResult>;
164
180
  private setParentAgentRunning;
181
+ /**
182
+ * Records the parent worker's per-call usage into the running turn
183
+ * aggregate and emits a `usage` event so consumers see cost tick after
184
+ * each parent agent boundary. Recording at the worker boundary (instead
185
+ * of per `message_end`) keeps the same behavior when test harnesses
186
+ * stub `runAgentWorker` and supply `terminal.usage` directly without
187
+ * running a real pi `Agent`.
188
+ */
165
189
  private runAgentWorkerWithUsage;
190
+ /**
191
+ * Inspect the most recent assistant message after a parent prompt and,
192
+ * when it carries a provider context-overflow error, mutate the agent
193
+ * state and the sticky `wireGuardHorizon` so that a subsequent re-prompt
194
+ * sends roughly the newer half of observable history.
195
+ *
196
+ * Returns `true` only when recovery actually happened — meaning the
197
+ * horizon advanced past at least one observable message. Callers use
198
+ * the return value as a single-shot gate: invoke once after the first
199
+ * `agent.prompt(...)` and, on `true`, resume the turn via
200
+ * `agent.continue()` exactly once. The helper never inspects the
201
+ * failing message again, so a second overflow on the retry falls
202
+ * through naturally as a `failed` turn.
203
+ *
204
+ * Mutations on success:
205
+ * - pops the failure assistant message that pi-agent pushed for the
206
+ * overflow (an empty-text marker with `stopReason: "error"` and
207
+ * `errorMessage`) so the retry's transcript does not carry it.
208
+ * `agent.continue()`'s own run lifecycle resets `errorMessage`
209
+ * before the retry, so we do not clear it here;
210
+ * - advances `this.wireGuardHorizon.evictionHorizon` to the smallest
211
+ * value at which `findEvictionHorizon` reports the dispatched list
212
+ * shrinks to at most `floor(n / 2)` observable messages, where `n`
213
+ * excludes the failure message itself.
214
+ *
215
+ * Emits one informational `system` event describing the compaction so
216
+ * surfaces can show a notice. The message reports the *actual*
217
+ * post-eviction drop count (after `MIN_HISTORY_TAIL` clamping and
218
+ * orphan-head skipping), not the half-of-n target.
219
+ *
220
+ * Returns `false` when:
221
+ * - the parent agent did not fail (`errorMessage` is unset);
222
+ * - the failure is not a context overflow (rate limit, transport
223
+ * error, etc. — left as-is for the caller to surface);
224
+ * - no horizon advance is possible (e.g. the existing horizon already
225
+ * covers every evictable message, or the history is too short to
226
+ * satisfy `MIN_HISTORY_TAIL`). In those cases retrying with the
227
+ * same context would still overflow, so we accept the failure
228
+ * instead of paying a second pointless request.
229
+ */
230
+ protected tryRecoverFromContextOverflow(agent: Agent): boolean;
166
231
  protected updateMemoryAfterAgentRun(messages: AgentMessage[], options: TurnOptions | undefined): Promise<void>;
167
232
  private refreshMemoryContextPack;
168
233
  /**
@@ -173,7 +238,7 @@ export declare class TurnRunner {
173
238
  resolveMemoryActorModel(options: TurnOptions | undefined): string;
174
239
  protected createAgent(input: AgentConfigInput, onControlResult?: (result: TurnRunnerControlResult) => void): Agent;
175
240
  protected createMemoryTransform(): (messages: AgentMessage[]) => Promise<AgentMessage[]>;
176
- private readonly wireGuardHorizon;
241
+ protected readonly wireGuardHorizon: WireGuardHorizon;
177
242
  getSkills(): Promise<readonly Skill[]>;
178
243
  /** System-prompt files (AGENTS.md by default) that resolved on disk for this session. */
179
244
  getResolvedAgentFiles(): Promise<readonly TurnAgentFile[]>;
@@ -201,6 +266,17 @@ export declare class TurnRunner {
201
266
  protected recordUsage(usage?: TurnTokenUsage | Usage): void;
202
267
  protected emitAgentEvent(event: AgentEvent): void;
203
268
  protected emitParentAgentEvent(event: AgentEvent): void;
269
+ /**
270
+ * Emit a `usage` event reflecting the latest `this.turnUsage`. Reuses the
271
+ * most recent parent context-window snapshot for the bar/breakdown so
272
+ * mid-turn ticks (parent worker finish, state-agent finish) surface cost
273
+ * without jittering the parent context fields. No-ops when no usage has
274
+ * been recorded yet or before the first parent emission — both are only
275
+ * possible during construction/teardown or in test harnesses; a real
276
+ * parent worker always sets the snapshot before its terminal usage is
277
+ * recorded.
278
+ */
279
+ protected emitTurnUsage(): void;
204
280
  /**
205
281
  * Estimate the per-segment occupancy of the parent agent's input before
206
282
  * reconciliation with provider `totalTokens`. System prompt and memory
@@ -1 +1 @@
1
- {"version":3,"file":"turn-runner.d.ts","sourceRoot":"","sources":["../../../src/turn-runner/turn-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"turn-runner.d.ts","sourceRoot":"","sources":["../../../src/turn-runner/turn-runner.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { Agent, } from "@earendil-works/pi-agent-core";
2
- import { getEnvApiKey } from "@earendil-works/pi-ai";
2
+ import { getEnvApiKey, isContextOverflow, } from "@earendil-works/pi-ai";
3
3
  import dedent from "dedent";
4
4
  import { assistantText } from "../core/serializer.js";
5
5
  import { toXML } from "../lib/xml.js";
6
- import { createObservationalContextTransform, DEFAULT_EFFECTIVE_CONTEXT, estimateTokens, resolveObservationalMemorySettings, updateObservationalMemory, } from "../memory/observational.js";
6
+ import { createObservationalContextTransform, DEFAULT_EFFECTIVE_CONTEXT, estimateTokens, resolveObservationalMemorySettings, stripObservationalContextMessages, updateObservationalMemory, } from "../memory/observational.js";
7
7
  import { rebuildMemoryContextPack } from "../memory/context-pack.js";
8
8
  import { createEmbeddingClient } from "../memory/embedding.js";
9
9
  import { loadStoredMemory } from "../memory/storage.js";
@@ -11,7 +11,7 @@ import { MemoryContextCache } from "../memory/store.js";
11
11
  import { DEFAULT_CLI_MEMORY_MODEL, DEFAULT_CLI_MODEL, resolveModelName, } from "../model-resolution/resolver.js";
12
12
  import { agentEventToTurnEvents, agentMessageText } from "./agent-events.js";
13
13
  import { createStateMachineSystemPromptLayer } from "./prompts.js";
14
- import { calculateWireBytes, createInitialHorizon } from "./wire-shaping.js";
14
+ import { applyEvictionHorizon, calculateWireBytes, createInitialHorizon, findEvictionHorizon, } from "./wire-shaping.js";
15
15
  import { createDefaultTurnRunnerTools, createTurnRunnerTools, formatCarriedTodosReminder, isTurnRunnerControlResult, } from "./tools.js";
16
16
  import { connectMcpServers } from "./mcp.js";
17
17
  import { SkillContext } from "./skill-context.js";
@@ -125,6 +125,18 @@ export class TurnRunner {
125
125
  started = false;
126
126
  /** Aggregates model usage across parent agents, state agents, and memory work for one turn chain. */
127
127
  turnUsage;
128
+ /**
129
+ * Snapshot of the latest parent assistant `message_end`'s bar fields.
130
+ * State-agent and terminal emissions reuse these so the bar/breakdown
131
+ * does not jitter mid-turn when only a state agent advanced cost.
132
+ *
133
+ * Always set by the time a state agent runs in production: the parent
134
+ * worker selects a state via a real LLM call, which emits `message_end`
135
+ * and populates this. Exposed as `protected` for test harnesses that
136
+ * stub `runAgentWorker` past the real parent path and need to seed the
137
+ * snapshot before driving a state-agent emission.
138
+ */
139
+ lastParentUsageSnapshot;
128
140
  /** Ensures persisted memory hydrates once before the first turn that needs it. */
129
141
  memoryLoaded = false;
130
142
  /** MCP servers connected during start(). Disposed on runner.dispose(). */
@@ -215,7 +227,16 @@ export class TurnRunner {
215
227
  terminal = await this.drainQueuedTurnCommands(terminal);
216
228
  terminal = { ...terminal, state: this.snapshotState(terminal.state) };
217
229
  if (this.turnUsage) {
218
- terminal = { ...terminal, usage: this.turnUsage };
230
+ terminal = {
231
+ ...terminal,
232
+ usage: this.turnUsage,
233
+ ...(this.lastParentUsageSnapshot
234
+ ? {
235
+ effectiveContextWindow: this.lastParentUsageSnapshot.effectiveContextWindow,
236
+ contextWindowUsage: this.lastParentUsageSnapshot.contextWindowUsage,
237
+ }
238
+ : {}),
239
+ };
219
240
  }
220
241
  this.setState(terminal.state);
221
242
  this.emit(terminal);
@@ -616,8 +637,6 @@ export class TurnRunner {
616
637
  });
617
638
  let unsubscribe;
618
639
  const finish = () => {
619
- const usage = usageFromMessages(agent.state.messages);
620
- this.recordUsage(usage);
621
640
  if (control.type === "ask_user_question") {
622
641
  return { type: "ask", questions: control.questions };
623
642
  }
@@ -641,6 +660,11 @@ export class TurnRunner {
641
660
  return { type: "failed", error: String(error) };
642
661
  }
643
662
  finally {
663
+ // Record state-agent usage on every exit path — success, error, or
664
+ // interrupt — so partial work still flows into the turn aggregate
665
+ // and ticks the sidebar cost via the emitted `usage` event.
666
+ this.recordUsage(usageFromMessages(agent.state.messages));
667
+ this.emitTurnUsage();
644
668
  unsubscribe?.();
645
669
  }
646
670
  },
@@ -876,6 +900,17 @@ export class TurnRunner {
876
900
  let interruptedDuringPrompt;
877
901
  try {
878
902
  await agent.prompt(input.prompt, input.images);
903
+ // Single-shot recovery: if the provider rejected the first attempt
904
+ // with a context-overflow error, advance the sticky wire-shaping
905
+ // horizon so the next send carries roughly the newer half of
906
+ // history, then resume the same turn via `agent.continue()`.
907
+ // Continuing (rather than re-prompting) keeps the existing user
908
+ // message at the tail instead of appending a duplicate. A
909
+ // still-too-big second attempt falls through as `failed` — no
910
+ // further retries.
911
+ if (this.tryRecoverFromContextOverflow(agent)) {
912
+ await agent.continue();
913
+ }
879
914
  }
880
915
  catch (error) {
881
916
  interruptedDuringPrompt = this.consumeInterruptedTerminal();
@@ -926,11 +961,89 @@ export class TurnRunner {
926
961
  this.parentAgentRunning = running;
927
962
  this.snapshotActiveAgentState();
928
963
  }
964
+ /**
965
+ * Records the parent worker's per-call usage into the running turn
966
+ * aggregate and emits a `usage` event so consumers see cost tick after
967
+ * each parent agent boundary. Recording at the worker boundary (instead
968
+ * of per `message_end`) keeps the same behavior when test harnesses
969
+ * stub `runAgentWorker` and supply `terminal.usage` directly without
970
+ * running a real pi `Agent`.
971
+ */
929
972
  async runAgentWorkerWithUsage(input) {
930
973
  const result = await this.runAgentWorker(input);
931
974
  this.recordUsage(result.terminal.usage);
975
+ this.emitTurnUsage();
932
976
  return result;
933
977
  }
978
+ /**
979
+ * Inspect the most recent assistant message after a parent prompt and,
980
+ * when it carries a provider context-overflow error, mutate the agent
981
+ * state and the sticky `wireGuardHorizon` so that a subsequent re-prompt
982
+ * sends roughly the newer half of observable history.
983
+ *
984
+ * Returns `true` only when recovery actually happened — meaning the
985
+ * horizon advanced past at least one observable message. Callers use
986
+ * the return value as a single-shot gate: invoke once after the first
987
+ * `agent.prompt(...)` and, on `true`, resume the turn via
988
+ * `agent.continue()` exactly once. The helper never inspects the
989
+ * failing message again, so a second overflow on the retry falls
990
+ * through naturally as a `failed` turn.
991
+ *
992
+ * Mutations on success:
993
+ * - pops the failure assistant message that pi-agent pushed for the
994
+ * overflow (an empty-text marker with `stopReason: "error"` and
995
+ * `errorMessage`) so the retry's transcript does not carry it.
996
+ * `agent.continue()`'s own run lifecycle resets `errorMessage`
997
+ * before the retry, so we do not clear it here;
998
+ * - advances `this.wireGuardHorizon.evictionHorizon` to the smallest
999
+ * value at which `findEvictionHorizon` reports the dispatched list
1000
+ * shrinks to at most `floor(n / 2)` observable messages, where `n`
1001
+ * excludes the failure message itself.
1002
+ *
1003
+ * Emits one informational `system` event describing the compaction so
1004
+ * surfaces can show a notice. The message reports the *actual*
1005
+ * post-eviction drop count (after `MIN_HISTORY_TAIL` clamping and
1006
+ * orphan-head skipping), not the half-of-n target.
1007
+ *
1008
+ * Returns `false` when:
1009
+ * - the parent agent did not fail (`errorMessage` is unset);
1010
+ * - the failure is not a context overflow (rate limit, transport
1011
+ * error, etc. — left as-is for the caller to surface);
1012
+ * - no horizon advance is possible (e.g. the existing horizon already
1013
+ * covers every evictable message, or the history is too short to
1014
+ * satisfy `MIN_HISTORY_TAIL`). In those cases retrying with the
1015
+ * same context would still overflow, so we accept the failure
1016
+ * instead of paying a second pointless request.
1017
+ */
1018
+ tryRecoverFromContextOverflow(agent) {
1019
+ if (!agent.state.errorMessage)
1020
+ return false;
1021
+ const messages = agent.state.messages;
1022
+ const lastMessage = messages[messages.length - 1];
1023
+ if (!lastMessage || lastMessage.role !== "assistant")
1024
+ return false;
1025
+ if (!isContextOverflow(lastMessage, agent.state.model.contextWindow))
1026
+ return false;
1027
+ // Exclude the failure assistant message from the half-history
1028
+ // calculation; only "real" prior turns should count toward the
1029
+ // observable population the cut targets.
1030
+ const observable = stripObservationalContextMessages(messages.slice(0, -1));
1031
+ const target = Math.floor(observable.length / 2);
1032
+ const previousHorizon = this.wireGuardHorizon.evictionHorizon;
1033
+ const newHorizon = findEvictionHorizon(observable, previousHorizon, (candidate) => candidate.length <= target);
1034
+ if (newHorizon === previousHorizon)
1035
+ return false;
1036
+ messages.pop();
1037
+ this.wireGuardHorizon.evictionHorizon = newHorizon;
1038
+ const remaining = applyEvictionHorizon(observable, newHorizon).length;
1039
+ const dropped = observable.length - remaining;
1040
+ this.emit({
1041
+ type: "system",
1042
+ level: "info",
1043
+ message: `Context overflow: dropped ${dropped} older message${dropped === 1 ? "" : "s"} and retrying.`,
1044
+ });
1045
+ return true;
1046
+ }
934
1047
  async updateMemoryAfterAgentRun(messages, options) {
935
1048
  if (this.config.memoryDbPath === undefined) {
936
1049
  return;
@@ -1033,7 +1146,9 @@ export class TurnRunner {
1033
1146
  }
1034
1147
  // Sticky across all turns within this runner instance. Resets on
1035
1148
  // session resume (new runner). Mutated in place by the memory transform
1036
- // when either the token or byte budget triggers eviction.
1149
+ // when either the token or byte budget triggers eviction, and by
1150
+ // `runAgentWorker` on a provider context-overflow error so the retry
1151
+ // sends the newer half of history.
1037
1152
  wireGuardHorizon = createInitialHorizon();
1038
1153
  async getSkills() {
1039
1154
  await this.ensureSkillsLoaded();
@@ -1127,12 +1242,35 @@ export class TurnRunner {
1127
1242
  this.emitAgentEvent(event);
1128
1243
  if (event.type !== "message_end" || event.message.role !== "assistant")
1129
1244
  return;
1130
- const estimated = this.estimateContextWindowUsage();
1131
- this.emit({
1132
- type: "context_usage",
1133
- usage: event.message.usage,
1245
+ // Cache the parent's latest bar/breakdown so subsequent state-agent and
1246
+ // terminal emissions can reuse it without rescaling against a stale base.
1247
+ // Usage *recording* and `usage` event emission happen at worker / state-agent
1248
+ // boundaries (see `runAgentWorkerWithUsage` and `createStateAgentHandle`)
1249
+ // instead of per message, so test harnesses that stub `runAgentWorker`
1250
+ // — without ever firing `message_end` — still get correct accounting.
1251
+ this.lastParentUsageSnapshot = {
1134
1252
  effectiveContextWindow: this.effectiveContextWindow(),
1135
- contextWindowUsage: scaleContextWindowUsageToTotalTokens(estimated, event.message.usage.totalTokens),
1253
+ contextWindowUsage: scaleContextWindowUsageToTotalTokens(this.estimateContextWindowUsage(), event.message.usage.totalTokens),
1254
+ };
1255
+ }
1256
+ /**
1257
+ * Emit a `usage` event reflecting the latest `this.turnUsage`. Reuses the
1258
+ * most recent parent context-window snapshot for the bar/breakdown so
1259
+ * mid-turn ticks (parent worker finish, state-agent finish) surface cost
1260
+ * without jittering the parent context fields. No-ops when no usage has
1261
+ * been recorded yet or before the first parent emission — both are only
1262
+ * possible during construction/teardown or in test harnesses; a real
1263
+ * parent worker always sets the snapshot before its terminal usage is
1264
+ * recorded.
1265
+ */
1266
+ emitTurnUsage() {
1267
+ if (!this.turnUsage || !this.lastParentUsageSnapshot)
1268
+ return;
1269
+ this.emit({
1270
+ type: "usage",
1271
+ usage: this.turnUsage,
1272
+ effectiveContextWindow: this.lastParentUsageSnapshot.effectiveContextWindow,
1273
+ contextWindowUsage: this.lastParentUsageSnapshot.contextWindowUsage,
1136
1274
  });
1137
1275
  }
1138
1276
  /**