@code-yeongyu/senpi 2026.7.9-2 → 2026.7.9

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 (207) hide show
  1. package/CHANGELOG.md +1 -25
  2. package/README.md +1 -1
  3. package/dist/cli/args.js +3 -3
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/cli/config-selector.d.ts +2 -4
  6. package/dist/cli/config-selector.d.ts.map +1 -1
  7. package/dist/cli/config-selector.js +1 -1
  8. package/dist/cli/config-selector.js.map +1 -1
  9. package/dist/core/agent-session.d.ts +3 -18
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +36 -153
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/compaction/compaction.d.ts +2 -1
  14. package/dist/core/compaction/compaction.d.ts.map +1 -1
  15. package/dist/core/compaction/compaction.js +79 -54
  16. package/dist/core/compaction/compaction.js.map +1 -1
  17. package/dist/core/extensions/builtin/goal/continuation.js +1 -1
  18. package/dist/core/extensions/builtin/goal/continuation.js.map +1 -1
  19. package/dist/core/extensions/builtin/goal/index.d.ts.map +1 -1
  20. package/dist/core/extensions/builtin/goal/index.js +0 -1
  21. package/dist/core/extensions/builtin/goal/index.js.map +1 -1
  22. package/dist/core/extensions/builtin/import-repro.d.ts.map +1 -1
  23. package/dist/core/extensions/builtin/import-repro.js +6 -100
  24. package/dist/core/extensions/builtin/import-repro.js.map +1 -1
  25. package/dist/core/extensions/builtin/mcp/connection.d.ts +0 -1
  26. package/dist/core/extensions/builtin/mcp/connection.d.ts.map +1 -1
  27. package/dist/core/extensions/builtin/mcp/connection.js +0 -15
  28. package/dist/core/extensions/builtin/mcp/connection.js.map +1 -1
  29. package/dist/core/extensions/builtin/mcp/service.d.ts.map +1 -1
  30. package/dist/core/extensions/builtin/mcp/service.js +1 -3
  31. package/dist/core/extensions/builtin/mcp/service.js.map +1 -1
  32. package/dist/core/extensions/index.d.ts +1 -1
  33. package/dist/core/extensions/index.d.ts.map +1 -1
  34. package/dist/core/extensions/index.js.map +1 -1
  35. package/dist/core/extensions/runner.d.ts +3 -4
  36. package/dist/core/extensions/runner.d.ts.map +1 -1
  37. package/dist/core/extensions/runner.js +24 -30
  38. package/dist/core/extensions/runner.js.map +1 -1
  39. package/dist/core/extensions/types.d.ts +3 -23
  40. package/dist/core/extensions/types.d.ts.map +1 -1
  41. package/dist/core/extensions/types.js.map +1 -1
  42. package/dist/core/model-registry.d.ts +0 -3
  43. package/dist/core/model-registry.d.ts.map +1 -1
  44. package/dist/core/model-registry.js +3 -20
  45. package/dist/core/model-registry.js.map +1 -1
  46. package/dist/core/package-manager.d.ts +1 -4
  47. package/dist/core/package-manager.d.ts.map +1 -1
  48. package/dist/core/package-manager.js +26 -68
  49. package/dist/core/package-manager.js.map +1 -1
  50. package/dist/core/resource-loader.d.ts +2 -2
  51. package/dist/core/resource-loader.d.ts.map +1 -1
  52. package/dist/core/resource-loader.js +7 -6
  53. package/dist/core/resource-loader.js.map +1 -1
  54. package/dist/core/sdk.d.ts +1 -1
  55. package/dist/core/sdk.d.ts.map +1 -1
  56. package/dist/core/sdk.js +2 -9
  57. package/dist/core/sdk.js.map +1 -1
  58. package/dist/core/session-manager.d.ts.map +1 -1
  59. package/dist/core/session-manager.js +2 -11
  60. package/dist/core/session-manager.js.map +1 -1
  61. package/dist/core/settings-manager.d.ts +0 -5
  62. package/dist/core/settings-manager.d.ts.map +1 -1
  63. package/dist/core/settings-manager.js +0 -8
  64. package/dist/core/settings-manager.js.map +1 -1
  65. package/dist/core/slash-commands.d.ts +0 -1
  66. package/dist/core/slash-commands.d.ts.map +1 -1
  67. package/dist/core/slash-commands.js +3 -3
  68. package/dist/core/slash-commands.js.map +1 -1
  69. package/dist/index.d.ts +1 -1
  70. package/dist/index.d.ts.map +1 -1
  71. package/dist/index.js.map +1 -1
  72. package/dist/main.d.ts +2 -2
  73. package/dist/main.d.ts.map +1 -1
  74. package/dist/main.js +0 -1
  75. package/dist/main.js.map +1 -1
  76. package/dist/modes/interactive/components/config-selector.d.ts +3 -34
  77. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  78. package/dist/modes/interactive/components/config-selector.js +24 -272
  79. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  80. package/dist/modes/interactive/components/footer.d.ts +0 -4
  81. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  82. package/dist/modes/interactive/components/footer.js +2 -5
  83. package/dist/modes/interactive/components/footer.js.map +1 -1
  84. package/dist/modes/interactive/components/oauth-selector.d.ts +1 -3
  85. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  86. package/dist/modes/interactive/components/oauth-selector.js +6 -16
  87. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  88. package/dist/modes/interactive/components/settings-selector.d.ts +0 -2
  89. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  90. package/dist/modes/interactive/components/settings-selector.js +0 -10
  91. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  92. package/dist/modes/interactive/interactive-mode.d.ts +0 -10
  93. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  94. package/dist/modes/interactive/interactive-mode.js +37 -261
  95. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  96. package/dist/modes/print-mode.js +1 -1
  97. package/dist/modes/print-mode.js.map +1 -1
  98. package/dist/modes/rpc/rpc-client.d.ts +6 -6
  99. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  100. package/dist/modes/rpc/rpc-client.js +3 -3
  101. package/dist/modes/rpc/rpc-client.js.map +1 -1
  102. package/dist/package-manager-cli.d.ts +2 -2
  103. package/dist/package-manager-cli.d.ts.map +1 -1
  104. package/dist/package-manager-cli.js +17 -64
  105. package/dist/package-manager-cli.js.map +1 -1
  106. package/dist/utils/clipboard-image.js +1 -1
  107. package/dist/utils/clipboard-image.js.map +1 -1
  108. package/docs/extensions.md +9 -33
  109. package/docs/models.md +4 -4
  110. package/docs/packages.md +10 -7
  111. package/docs/rpc.md +3 -13
  112. package/docs/sdk.md +0 -22
  113. package/docs/settings.md +0 -1
  114. package/docs/usage.md +1 -1
  115. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  116. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  117. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  118. package/examples/extensions/gondolin/package-lock.json +2 -2
  119. package/examples/extensions/gondolin/package.json +1 -1
  120. package/examples/extensions/reload-runtime.ts +2 -2
  121. package/examples/extensions/sandbox/package-lock.json +2 -2
  122. package/examples/extensions/sandbox/package.json +1 -1
  123. package/examples/extensions/with-deps/package-lock.json +2 -2
  124. package/examples/extensions/with-deps/package.json +1 -1
  125. package/examples/sdk/README.md +1 -1
  126. package/node_modules/@code-yeongyu/senpi-codemode/package.json +3 -3
  127. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  128. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +2 -37
  129. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  130. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.d.ts.map +1 -1
  131. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.js +0 -2
  132. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-repo.js.map +1 -1
  133. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.d.ts +0 -1
  134. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.d.ts.map +1 -1
  135. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.js +0 -7
  136. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl-storage.js.map +1 -1
  137. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts +4 -18
  138. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.d.ts.map +1 -1
  139. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js +37 -72
  140. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/session.js.map +1 -1
  141. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts +0 -2
  142. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  143. package/node_modules/@earendil-works/pi-agent-core/dist/harness/types.js.map +1 -1
  144. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts +0 -2
  145. package/node_modules/@earendil-works/pi-agent-core/dist/index.d.ts.map +1 -1
  146. package/node_modules/@earendil-works/pi-agent-core/dist/index.js +0 -2
  147. package/node_modules/@earendil-works/pi-agent-core/dist/index.js.map +1 -1
  148. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  149. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  150. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +1 -2
  151. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  152. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +1 -1
  153. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
  154. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.d.ts.map +1 -1
  155. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js +1 -4
  156. package/node_modules/@earendil-works/pi-ai/dist/api/transform-messages.js.map +1 -1
  157. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +195 -446
  158. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  159. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts +0 -84
  160. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
  161. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js +0 -72
  162. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.models.js.map +1 -1
  163. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js +4 -4
  164. package/node_modules/@earendil-works/pi-ai/dist/providers/github-copilot.models.js.map +1 -1
  165. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts +0 -63
  166. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.d.ts.map +1 -1
  167. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js +0 -54
  168. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex.models.js.map +1 -1
  169. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts +0 -84
  170. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.d.ts.map +1 -1
  171. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js +0 -72
  172. package/node_modules/@earendil-works/pi-ai/dist/providers/openai.models.js.map +1 -1
  173. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +63 -138
  174. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
  175. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +76 -136
  176. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  177. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +0 -77
  178. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  179. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +0 -71
  180. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  181. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts +44 -0
  182. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
  183. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js +45 -9
  184. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  185. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts +44 -0
  186. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
  187. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js +45 -9
  188. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  189. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts +44 -0
  190. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
  191. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js +45 -9
  192. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  193. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  194. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +0 -3
  195. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  196. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  197. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  198. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  199. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +1 -22
  200. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  201. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  202. package/npm-shrinkwrap.json +14 -14
  203. package/package.json +6 -6
  204. package/dist/core/cache-stats.d.ts +0 -49
  205. package/dist/core/cache-stats.d.ts.map +0 -1
  206. package/dist/core/cache-stats.js +0 -101
  207. package/dist/core/cache-stats.js.map +0 -1
@@ -89,7 +89,6 @@ export class AgentSession {
89
89
  constructor(config) {
90
90
  this._eventListeners = [];
91
91
  this._agentEventQueue = Promise.resolve();
92
- this._isAgentRunActive = false;
93
92
  /** Tracks pending steering messages for UI display. Removed when delivered. */
94
93
  this._steeringMessages = [];
95
94
  /** Tracks pending follow-up messages for UI display. Removed when delivered. */
@@ -218,11 +217,11 @@ export class AgentSession {
218
217
  };
219
218
  }
220
219
  async _emitBeforeToolCallHooks(toolCall, args) {
221
- await this._agentEventQueue;
222
220
  const runner = this._extensionRunner;
223
221
  if (!runner.hasHandlers("tool_call")) {
224
222
  return undefined;
225
223
  }
224
+ await this._agentEventQueue;
226
225
  try {
227
226
  return await runner.emitToolCall({
228
227
  type: "tool_call",
@@ -324,47 +323,6 @@ export class AgentSession {
324
323
  this.abortBranchSummary();
325
324
  this._incrementMessageRevision();
326
325
  }
327
- _getIdleWaitPromise() {
328
- if (!this._idleWaitPromise) {
329
- this._idleWaitPromise = new Promise((resolve) => {
330
- this._resolveIdleWait = resolve;
331
- });
332
- }
333
- return this._idleWaitPromise;
334
- }
335
- _resolveIdleWaitIfIdle() {
336
- if (this._isAgentRunActive || !this._resolveIdleWait) {
337
- return;
338
- }
339
- const resolve = this._resolveIdleWait;
340
- this._idleWaitPromise = undefined;
341
- this._resolveIdleWait = undefined;
342
- resolve();
343
- }
344
- async _emitAgentSettled() {
345
- if (!this._isAgentRunActive) {
346
- this._resolveIdleWaitIfIdle();
347
- return;
348
- }
349
- this._isAgentRunActive = false;
350
- try {
351
- await this._extensionRunner.emit({ type: "agent_settled" });
352
- this._emit({ type: "agent_settled" });
353
- }
354
- finally {
355
- this._resolveIdleWaitIfIdle();
356
- }
357
- }
358
- async _promptAgent(messages) {
359
- this._isAgentRunActive = true;
360
- try {
361
- await this.agent.prompt(messages);
362
- }
363
- catch (error) {
364
- await this._emitAgentSettled();
365
- throw error;
366
- }
367
- }
368
326
  _createRetryPromiseForAgentEnd(event) {
369
327
  if (event.type !== "agent_end" || this._retryPromise) {
370
328
  return;
@@ -390,34 +348,6 @@ export class AgentSession {
390
348
  }
391
349
  return undefined;
392
350
  }
393
- _agentEndAllowsQueuedContinuation(messages) {
394
- let lastAssistantIndex = -1;
395
- for (let index = messages.length - 1; index >= 0; index--) {
396
- if (messages[index]?.role === "assistant") {
397
- lastAssistantIndex = index;
398
- break;
399
- }
400
- }
401
- if (lastAssistantIndex === -1) {
402
- return false;
403
- }
404
- const lastAssistant = messages[lastAssistantIndex];
405
- if (lastAssistant?.role !== "assistant") {
406
- return false;
407
- }
408
- if (lastAssistant.stopReason === "aborted" || lastAssistant.stopReason === "error") {
409
- return false;
410
- }
411
- for (let index = lastAssistantIndex + 1; index < messages.length; index++) {
412
- const message = messages[index];
413
- if (message?.role === "toolResult" &&
414
- message.isError &&
415
- message.content.some((content) => content.type === "text" && /\babort(?:ed)?\b/i.test(content.text))) {
416
- return false;
417
- }
418
- }
419
- return true;
420
- }
421
351
  _willRetryAfterAgentEnd(messages) {
422
352
  const settings = this.settingsManager.getRetrySettings();
423
353
  if (!settings.enabled) {
@@ -500,8 +430,6 @@ export class AgentSession {
500
430
  }
501
431
  }
502
432
  // Check auto-retry and auto-compaction after agent completes
503
- let launchedContinuation = false;
504
- const allowsQueuedContinuation = event.type === "agent_end" ? this._agentEndAllowsQueuedContinuation(event.messages) : false;
505
433
  if (event.type === "agent_end" && this._lastAssistantMessage) {
506
434
  const msg = this._lastAssistantMessage;
507
435
  this._lastAssistantMessage = undefined;
@@ -512,16 +440,10 @@ export class AgentSession {
512
440
  return; // Retry was initiated, don't proceed to compaction
513
441
  }
514
442
  this._resolveRetry();
515
- launchedContinuation = await this._checkCompaction(msg);
443
+ await this._checkCompaction(msg);
516
444
  }
517
445
  if (event.type === "agent_end") {
518
446
  this._flushPendingBashMessages();
519
- if (!launchedContinuation && allowsQueuedContinuation && this.agent.hasQueuedMessages()) {
520
- launchedContinuation = await this._continueAgentAfterCurrentRun();
521
- }
522
- if (!launchedContinuation) {
523
- await this._emitAgentSettled();
524
- }
525
447
  }
526
448
  }
527
449
  /** Resolve the pending retry promise */
@@ -615,16 +537,7 @@ export class AgentSession {
615
537
  };
616
538
  const replacement = await this._extensionRunner.emitMessageEnd(extensionEvent);
617
539
  if (replacement) {
618
- // Untyped extension handlers can return messages with null/missing content;
619
- // normalize so it never enters agent state or session history.
620
- const normalized = (replacement.role === "user" ||
621
- replacement.role === "assistant" ||
622
- replacement.role === "toolResult" ||
623
- replacement.role === "custom") &&
624
- replacement.content == null
625
- ? { ...replacement, content: [] }
626
- : replacement;
627
- this._replaceMessageInPlace(event.message, normalized);
540
+ this._replaceMessageInPlace(event.message, replacement);
628
541
  }
629
542
  }
630
543
  else if (event.type === "tool_execution_start") {
@@ -731,13 +644,9 @@ export class AgentSession {
731
644
  get serviceTier() {
732
645
  return this._currentServiceTier;
733
646
  }
734
- /** Whether the session is currently processing an agent run or post-run continuation. */
647
+ /** Whether agent is currently streaming a response */
735
648
  get isStreaming() {
736
- return this._isAgentRunActive;
737
- }
738
- /** Whether the session has no active agent run, retry, auto-compaction, or queued continuation. */
739
- get isIdle() {
740
- return !this._isAgentRunActive;
649
+ return this.agent.state.isStreaming;
741
650
  }
742
651
  /** Current effective system prompt (includes any per-turn extension modifications) */
743
652
  get systemPrompt() {
@@ -1078,8 +987,7 @@ export class AgentSession {
1078
987
  messages.push({
1079
988
  role: "custom",
1080
989
  customType: msg.customType,
1081
- // Untyped extensions can pass null/missing content; normalize at ingestion.
1082
- content: msg.content ?? [],
990
+ content: msg.content,
1083
991
  display: msg.display,
1084
992
  details: msg.details,
1085
993
  timestamp: Date.now(),
@@ -1105,9 +1013,8 @@ export class AgentSession {
1105
1013
  return;
1106
1014
  }
1107
1015
  preflightResult?.(true);
1108
- await this._promptAgent(messages);
1016
+ await this.agent.prompt(messages);
1109
1017
  await this.waitForRetry();
1110
- await this.waitForIdle();
1111
1018
  if (shouldWaitForSessionWork) {
1112
1019
  await this._waitForSettledSessionWork();
1113
1020
  }
@@ -1337,8 +1244,7 @@ export class AgentSession {
1337
1244
  const appMessage = {
1338
1245
  role: "custom",
1339
1246
  customType: message.customType,
1340
- // Untyped extensions can pass null/missing content; normalize at ingestion.
1341
- content: message.content ?? [],
1247
+ content: message.content,
1342
1248
  display: message.display,
1343
1249
  details: message.details,
1344
1250
  timestamp: Date.now(),
@@ -1355,7 +1261,7 @@ export class AgentSession {
1355
1261
  }
1356
1262
  }
1357
1263
  else if (options?.triggerTurn) {
1358
- await this._promptAgent(appMessage);
1264
+ await this.agent.prompt(appMessage);
1359
1265
  }
1360
1266
  else {
1361
1267
  this.agent.state.messages.push(appMessage);
@@ -1446,7 +1352,7 @@ export class AgentSession {
1446
1352
  }
1447
1353
  const abortPromise = (async () => {
1448
1354
  this.agent.abort();
1449
- await this.waitForIdle();
1355
+ await this.agent.waitForIdle();
1450
1356
  })();
1451
1357
  this._userAbortPromise = abortPromise;
1452
1358
  try {
@@ -1458,12 +1364,6 @@ export class AgentSession {
1458
1364
  }
1459
1365
  }
1460
1366
  }
1461
- async waitForIdle() {
1462
- if (this.isIdle) {
1463
- return;
1464
- }
1465
- await this._getIdleWaitPromise();
1466
- }
1467
1367
  // =========================================================================
1468
1368
  // Model Management
1469
1369
  // =========================================================================
@@ -1948,10 +1848,10 @@ export class AgentSession {
1948
1848
  async _checkCompaction(assistantMessage, skipAbortedCheck = true, requestReason) {
1949
1849
  const settings = this.settingsManager.getCompactionSettings();
1950
1850
  if (!settings.enabled)
1951
- return false;
1851
+ return;
1952
1852
  // Skip if message was aborted (user cancelled) - unless skipAbortedCheck is false
1953
1853
  if (skipAbortedCheck && assistantMessage.stopReason === "aborted")
1954
- return false;
1854
+ return;
1955
1855
  const contextWindow = this.model?.contextWindow ?? 0;
1956
1856
  // Skip overflow check if the message came from a different model.
1957
1857
  // This handles the case where user switched from a smaller-context model (e.g. opus)
@@ -1965,7 +1865,7 @@ export class AgentSession {
1965
1865
  const compactionEntry = getLatestCompactionEntry(this.sessionManager.getBranch());
1966
1866
  const assistantIsFromBeforeCompaction = compactionEntry !== null && assistantMessage.timestamp <= new Date(compactionEntry.timestamp).getTime();
1967
1867
  if (assistantIsFromBeforeCompaction) {
1968
- return false;
1868
+ return;
1969
1869
  }
1970
1870
  // Case 1: Overflow - LLM returned context overflow error.
1971
1871
  // If the saved assistant provider differs from the currently selected provider alias,
@@ -1977,7 +1877,8 @@ export class AgentSession {
1977
1877
  if (isContextOverflow(assistantMessage, contextWindow) && (sameModel || currentContextNeedsCompaction)) {
1978
1878
  const willRetry = assistantMessage.stopReason !== "stop";
1979
1879
  if (!willRetry) {
1980
- return await this._runAutoCompaction("overflow", false);
1880
+ await this._runAutoCompaction("overflow", false);
1881
+ return;
1981
1882
  }
1982
1883
  if (this._overflowRecoveryAttempted) {
1983
1884
  const errorMessage = "Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.";
@@ -1992,7 +1893,7 @@ export class AgentSession {
1992
1893
  if (requestReason === "pre_prompt") {
1993
1894
  throw new Error(errorMessage);
1994
1895
  }
1995
- return false;
1896
+ return;
1996
1897
  }
1997
1898
  this._overflowRecoveryAttempted = true;
1998
1899
  // Remove the error message from agent state (it IS saved to session for history,
@@ -2006,9 +1907,9 @@ export class AgentSession {
2006
1907
  await this._runPrePromptCompaction(assistantMessage, skipAbortedCheck, "overflow", willRetry);
2007
1908
  }
2008
1909
  else {
2009
- return await this._runAutoCompaction("overflow", willRetry);
1910
+ await this._runAutoCompaction("overflow", willRetry);
2010
1911
  }
2011
- return false;
1912
+ return;
2012
1913
  }
2013
1914
  // Case 2: Threshold - context is getting large
2014
1915
  // For error messages or all-zero usage messages, estimate from the last valid response.
@@ -2020,7 +1921,7 @@ export class AgentSession {
2020
1921
  const messages = filterContextExcludedMessages(this.agent.state.messages);
2021
1922
  const estimate = estimateContextTokens(messages);
2022
1923
  if (estimate.lastUsageIndex === null)
2023
- return false; // No usage data at all
1924
+ return; // No usage data at all
2024
1925
  // Verify the usage source is post-compaction. Kept pre-compaction messages
2025
1926
  // have stale usage reflecting the old (larger) context and would falsely
2026
1927
  // trigger compaction right after one just finished.
@@ -2028,7 +1929,7 @@ export class AgentSession {
2028
1929
  if (compactionEntry &&
2029
1930
  usageMsg.role === "assistant" &&
2030
1931
  usageMsg.timestamp <= new Date(compactionEntry.timestamp).getTime()) {
2031
- return false;
1932
+ return;
2032
1933
  }
2033
1934
  contextTokens = estimate.tokens;
2034
1935
  }
@@ -2040,10 +1941,9 @@ export class AgentSession {
2040
1941
  await this._runPrePromptCompaction(assistantMessage, skipAbortedCheck);
2041
1942
  }
2042
1943
  else {
2043
- return await this._runAutoCompaction("threshold", false);
1944
+ await this._runAutoCompaction("threshold", false);
2044
1945
  }
2045
1946
  }
2046
- return false;
2047
1947
  }
2048
1948
  async _runPrePromptCompaction(lastAssistantMessage, skipAbortedCheck, reason = "pre_prompt", willRetry = false) {
2049
1949
  this._emit({ type: "compaction_start", reason });
@@ -2356,7 +2256,7 @@ export class AgentSession {
2356
2256
  }, {
2357
2257
  getModel: () => this.model,
2358
2258
  getServiceTier: () => this.serviceTier,
2359
- isIdle: () => this.isIdle,
2259
+ isIdle: () => !this.isStreaming,
2360
2260
  isProjectTrusted: () => this.settingsManager.isProjectTrusted(),
2361
2261
  getSignal: () => this.agent.signal,
2362
2262
  abort: () => {
@@ -2693,7 +2593,6 @@ export class AgentSession {
2693
2593
  const attempt = this._retryAttempt;
2694
2594
  this._retryAttempt = 0;
2695
2595
  this._retryAbortController = undefined;
2696
- await this._emitAgentSettled();
2697
2596
  this._emit({
2698
2597
  type: "auto_retry_end",
2699
2598
  success: false,
@@ -3050,44 +2949,28 @@ export class AgentSession {
3050
2949
  return "";
3051
2950
  }
3052
2951
  /**
3053
- * Get session statistics. Aggregates over ALL session entries (including
3054
- * history that was compacted away), so token/cost totals reflect what was
3055
- * actually billed across the session.
2952
+ * Get session statistics.
3056
2953
  */
3057
2954
  getSessionStats() {
3058
- let userMessages = 0;
3059
- let assistantMessages = 0;
3060
- let toolResults = 0;
3061
- let totalMessages = 0;
2955
+ const state = this.state;
2956
+ const userMessages = state.messages.filter((m) => m.role === "user").length;
2957
+ const assistantMessages = state.messages.filter((m) => m.role === "assistant").length;
2958
+ const toolResults = state.messages.filter((m) => m.role === "toolResult").length;
3062
2959
  let toolCalls = 0;
3063
2960
  let totalInput = 0;
3064
2961
  let totalOutput = 0;
3065
2962
  let totalCacheRead = 0;
3066
2963
  let totalCacheWrite = 0;
3067
2964
  let totalCost = 0;
3068
- for (const entry of this.sessionManager.getEntries()) {
3069
- if (entry.type !== "message")
3070
- continue;
3071
- totalMessages++;
3072
- const message = entry.message;
3073
- if (message.role === "user") {
3074
- userMessages++;
3075
- }
3076
- else if (message.role === "toolResult") {
3077
- toolResults++;
3078
- }
3079
- else if (message.role === "assistant") {
3080
- assistantMessages++;
2965
+ for (const message of state.messages) {
2966
+ if (message.role === "assistant") {
3081
2967
  const assistantMsg = message;
3082
- if (Array.isArray(assistantMsg.content)) {
3083
- toolCalls += assistantMsg.content.filter((c) => c.type === "toolCall").length;
3084
- }
3085
- const usage = assistantMsg.usage;
3086
- totalInput += usage.input;
3087
- totalOutput += usage.output;
3088
- totalCacheRead += usage.cacheRead;
3089
- totalCacheWrite += usage.cacheWrite;
3090
- totalCost += usage.cost.total;
2968
+ toolCalls += assistantMsg.content.filter((c) => c.type === "toolCall").length;
2969
+ totalInput += assistantMsg.usage.input;
2970
+ totalOutput += assistantMsg.usage.output;
2971
+ totalCacheRead += assistantMsg.usage.cacheRead;
2972
+ totalCacheWrite += assistantMsg.usage.cacheWrite;
2973
+ totalCost += assistantMsg.usage.cost.total;
3091
2974
  }
3092
2975
  }
3093
2976
  return {
@@ -3097,7 +2980,7 @@ export class AgentSession {
3097
2980
  assistantMessages,
3098
2981
  toolCalls,
3099
2982
  toolResults,
3100
- totalMessages,
2983
+ totalMessages: state.messages.length,
3101
2984
  tokens: {
3102
2985
  input: totalInput,
3103
2986
  output: totalOutput,