@ashx-j/lunr 0.2.22 → 0.2.23

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 (132) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/README.md +5 -3
  3. package/dist/builtin-extensions/lunr-browser.d.ts +7 -1
  4. package/dist/builtin-extensions/lunr-browser.d.ts.map +1 -1
  5. package/dist/builtin-extensions/lunr-browser.js +116 -3
  6. package/dist/builtin-extensions/lunr-browser.js.map +1 -1
  7. package/dist/builtin-extensions/pi-subagents/src/extension/index.d.ts.map +1 -1
  8. package/dist/builtin-extensions/pi-subagents/src/extension/index.js +1 -1
  9. package/dist/builtin-extensions/pi-subagents/src/extension/index.js.map +1 -1
  10. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts +2 -0
  11. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.d.ts.map +1 -1
  12. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js +9 -0
  13. package/dist/builtin-extensions/pi-subagents/src/runs/background/subagent-wait.js.map +1 -1
  14. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.d.ts.map +1 -1
  15. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js +41 -3
  16. package/dist/builtin-extensions/pi-subagents/src/runs/background/wait-tool.js.map +1 -1
  17. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.d.ts.map +1 -1
  18. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js +4 -0
  19. package/dist/builtin-extensions/pi-subagents/src/runs/foreground/subagent-executor.js.map +1 -1
  20. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts +1 -1
  21. package/dist/builtin-extensions/pi-subagents/src/tui/communication.d.ts.map +1 -1
  22. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js +3 -2
  23. package/dist/builtin-extensions/pi-subagents/src/tui/communication.js.map +1 -1
  24. package/dist/core/agent-session.d.ts +19 -0
  25. package/dist/core/agent-session.d.ts.map +1 -1
  26. package/dist/core/agent-session.js +230 -103
  27. package/dist/core/agent-session.js.map +1 -1
  28. package/dist/core/settings-manager.d.ts +4 -0
  29. package/dist/core/settings-manager.d.ts.map +1 -1
  30. package/dist/core/settings-manager.js +9 -0
  31. package/dist/core/settings-manager.js.map +1 -1
  32. package/dist/core/subagent-wait-interruption.d.ts +11 -0
  33. package/dist/core/subagent-wait-interruption.d.ts.map +1 -0
  34. package/dist/core/subagent-wait-interruption.js +19 -0
  35. package/dist/core/subagent-wait-interruption.js.map +1 -0
  36. package/dist/core/system-prompt.d.ts.map +1 -1
  37. package/dist/core/system-prompt.js +3 -1
  38. package/dist/core/system-prompt.js.map +1 -1
  39. package/dist/core/tools/render-utils.d.ts +3 -3
  40. package/dist/core/tools/render-utils.d.ts.map +1 -1
  41. package/dist/core/tools/render-utils.js +3 -3
  42. package/dist/core/tools/render-utils.js.map +1 -1
  43. package/dist/modes/interactive/components/assistant-message.d.ts +10 -2
  44. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  45. package/dist/modes/interactive/components/assistant-message.js +29 -5
  46. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  47. package/dist/modes/interactive/components/copyable-text.d.ts +2 -6
  48. package/dist/modes/interactive/components/copyable-text.d.ts.map +1 -1
  49. package/dist/modes/interactive/components/copyable-text.js +26 -35
  50. package/dist/modes/interactive/components/copyable-text.js.map +1 -1
  51. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  52. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  53. package/dist/modes/interactive/components/settings-selector.js +13 -0
  54. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  55. package/dist/modes/interactive/components/thinking-tail.d.ts +9 -2
  56. package/dist/modes/interactive/components/thinking-tail.d.ts.map +1 -1
  57. package/dist/modes/interactive/components/thinking-tail.js +43 -1
  58. package/dist/modes/interactive/components/thinking-tail.js.map +1 -1
  59. package/dist/modes/interactive/components/tool-execution.d.ts +4 -3
  60. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  61. package/dist/modes/interactive/components/tool-execution.js +34 -45
  62. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  63. package/dist/modes/interactive/interactive-mode.d.ts +6 -0
  64. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  65. package/dist/modes/interactive/interactive-mode.js +118 -39
  66. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  67. package/dist/modes/interactive/theme/theme.d.ts +1 -0
  68. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  69. package/dist/modes/interactive/theme/theme.js +23 -0
  70. package/dist/modes/interactive/theme/theme.js.map +1 -1
  71. package/dist/node-runtime/{agent-session-services-NQ6GKOIK.js → agent-session-services-GZVSOGYR.js} +7 -7
  72. package/dist/node-runtime/{builtin-extensions-GVC6IFDU.js → builtin-extensions-QVCXNQT4.js} +3 -3
  73. package/dist/node-runtime/{chunk-6B2POMK7.js → chunk-6VYZ5UFP.js} +1 -1
  74. package/dist/node-runtime/{chunk-VJPTNWAP.js → chunk-DD5YWFSJ.js} +1 -1
  75. package/dist/node-runtime/{chunk-TDL7UWJ7.js → chunk-DQMGU675.js} +173 -57
  76. package/dist/node-runtime/{chunk-V2A7CEXK.js → chunk-EKVFP6YF.js} +2 -2
  77. package/dist/node-runtime/{chunk-5BNJ4JUH.js → chunk-GJ2RDBRL.js} +1 -1
  78. package/dist/node-runtime/{chunk-GNN7H3B7.js → chunk-GS42T6MX.js} +1 -1
  79. package/dist/node-runtime/{chunk-PC2Z5TKZ.js → chunk-HMBGROQK.js} +3 -3
  80. package/dist/node-runtime/{chunk-GJSAD4AB.js → chunk-HPUP7E4T.js} +10 -10
  81. package/dist/node-runtime/{chunk-IVXYUAJE.js → chunk-IF24A3FH.js} +1 -1
  82. package/dist/node-runtime/{chunk-BFNXONG3.js → chunk-LFZDVKSP.js} +2 -2
  83. package/dist/node-runtime/{chunk-EQ63ANHL.js → chunk-LLUIPGDR.js} +210 -125
  84. package/dist/node-runtime/{chunk-ORH324EP.js → chunk-PCEW76PM.js} +3 -3
  85. package/dist/node-runtime/{chunk-WADV2VDS.js → chunk-QAZOULTU.js} +7 -0
  86. package/dist/node-runtime/{chunk-6427XAWG.js → chunk-QH6YL7VK.js} +3 -3
  87. package/dist/node-runtime/{chunk-7QWNYZDI.js → chunk-RDDAZOMU.js} +16 -0
  88. package/dist/node-runtime/{chunk-QDGKKKUM.js → chunk-RIR5EDDJ.js} +1 -1
  89. package/dist/node-runtime/{chunk-H3XF4UVQ.js → chunk-RWTKOC3B.js} +1 -1
  90. package/dist/node-runtime/{chunk-IQIEU7SB.js → chunk-TVJUOJZJ.js} +2 -2
  91. package/dist/node-runtime/{chunk-UAFLNHSH.js → chunk-W64JC4E7.js} +8 -8
  92. package/dist/node-runtime/{chunk-LMBNLFXQ.js → chunk-X3URCYCU.js} +4 -4
  93. package/dist/node-runtime/{chunk-VSSXXL36.js → chunk-YDO2F2IA.js} +2 -2
  94. package/dist/node-runtime/{chunk-IWOWXRWU.js → chunk-YHQ3NBB3.js} +15 -15
  95. package/dist/node-runtime/cli-runtime.js +1 -1
  96. package/dist/node-runtime/{command-3JHHXOPX.js → command-PDVTBRWA.js} +3 -3
  97. package/dist/node-runtime/{commands-2JVNFGMQ.js → commands-XDCFGIGW.js} +5 -5
  98. package/dist/node-runtime/{export-html-KBFVV63J.js → export-html-KSOIMVPI.js} +1 -1
  99. package/dist/node-runtime/{extension-input-K24TVKVW.js → extension-input-E7BJZ35H.js} +4 -4
  100. package/dist/node-runtime/{extension-selector-SPNF7EDR.js → extension-selector-WU42XDTU.js} +4 -4
  101. package/dist/node-runtime/{gateway-VFO6SFKK.js → gateway-AYWM5DIO.js} +7 -7
  102. package/dist/node-runtime/index.js +17 -17
  103. package/dist/node-runtime/{install-cli-C3CF7O7N.js → install-cli-3BO4MMQ6.js} +1 -1
  104. package/dist/node-runtime/{interactive-mode-LOM6AIF6.js → interactive-mode-4MFRKAHG.js} +13 -13
  105. package/dist/node-runtime/{interactive-view-IDSCPPK7.js → interactive-view-TUZHCQM3.js} +5 -5
  106. package/dist/node-runtime/{lunr-browser-YNW7FTYX.js → lunr-browser-RYFIIVJN.js} +91 -4
  107. package/dist/node-runtime/{lunr-cron-BKHGNBKT.js → lunr-cron-YWXEPZMQ.js} +4 -4
  108. package/dist/node-runtime/main.js +14 -14
  109. package/dist/node-runtime/{mobile-commands-HMP25WBC.js → mobile-commands-LVHDAUDP.js} +4 -4
  110. package/dist/node-runtime/{package-manager-cli-VCK4E2RC.js → package-manager-cli-6GT3Z3CK.js} +9 -9
  111. package/dist/node-runtime/{pi-subagents-FEUDLJOE.js → pi-subagents-CDWK2AKY.js} +44 -10
  112. package/dist/node-runtime/rpc-entry.js +14 -14
  113. package/dist/node-runtime/{rpc-mode-P5ODXPEG.js → rpc-mode-O3XV4SID.js} +2 -2
  114. package/dist/node-runtime/{session-selector-LHRMJOKT.js → session-selector-GIM4DHQ2.js} +4 -4
  115. package/dist/node-runtime/{settings-manager-UUZ6NUXI.js → settings-manager-6VEMXRDL.js} +1 -1
  116. package/dist/node-runtime/{setup-NRXVZBLJ.js → setup-5SR2J35A.js} +1 -1
  117. package/dist/node-runtime/{subagent-executor-MLUMBWCP.js → subagent-executor-M5VWB3D3.js} +8 -4
  118. package/dist/node-runtime/{theme-U7IGOA7O.js → theme-UOO5RVFN.js} +1 -1
  119. package/dist/node-runtime/{update-cli-4TP25CNW.js → update-cli-UVKJWRRJ.js} +1 -1
  120. package/docs/features.md +2 -0
  121. package/docs/settings.md +1 -0
  122. package/docs/usage.md +2 -2
  123. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  124. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  125. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  126. package/examples/extensions/gondolin/package-lock.json +2 -2
  127. package/examples/extensions/gondolin/package.json +1 -1
  128. package/examples/extensions/sandbox/package-lock.json +2 -2
  129. package/examples/extensions/sandbox/package.json +1 -1
  130. package/examples/extensions/with-deps/package-lock.json +2 -2
  131. package/examples/extensions/with-deps/package.json +1 -1
  132. package/package.json +4 -4
@@ -34,6 +34,7 @@ import { expandPromptTemplate } from "./prompt-templates.js";
34
34
  import { rollbackSnapshotBeforeWrite } from "./rollback.js";
35
35
  import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-manager.js";
36
36
  import { createSyntheticSourceInfo } from "./source-info.js";
37
+ import { registerSubagentWaitInterruptionOwner, } from "./subagent-wait-interruption.js";
37
38
  import { buildSystemPrompt } from "./system-prompt.js";
38
39
  import { measureStartup } from "./timings.js";
39
40
  import { TODO_TOOL_NAMES } from "./todo-settings.js";
@@ -90,6 +91,11 @@ export class AgentSession {
90
91
  _isAgentRunActive = false;
91
92
  _idleWaitPromise;
92
93
  _resolveIdleWait;
94
+ _activePromptRun;
95
+ _waitPromptHandoff;
96
+ _waitPromptAcceptance = Promise.resolve();
97
+ _waitPromptGeneration = 0;
98
+ _unregisterSubagentWaitInterruptionOwners = [];
93
99
  /** Tracks pending steering messages for UI display. Removed when delivered. */
94
100
  _steeringMessages = [];
95
101
  /** Tracks pending follow-up messages for UI display. Removed when delivered. */
@@ -161,6 +167,10 @@ export class AgentSession {
161
167
  this._excludedToolNames = config.excludedToolNames ? new Set(config.excludedToolNames) : undefined;
162
168
  this._baseToolsOverride = config.baseToolsOverride;
163
169
  this._sessionStartEvent = config.sessionStartEvent ?? { type: "session_start", reason: "startup" };
170
+ const waitInterruptionOwner = { register: () => this._registerSubagentWaitInterruption() };
171
+ for (const identity of new Set([this.sessionId, this.sessionFile].filter((value) => !!value))) {
172
+ this._unregisterSubagentWaitInterruptionOwners.push(registerSubagentWaitInterruptionOwner(identity, waitInterruptionOwner));
173
+ }
164
174
  // Always subscribe to agent events for internal handling
165
175
  // (session persistence, extensions, auto-compaction, retry logic)
166
176
  this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
@@ -644,6 +654,8 @@ export class AgentSession {
644
654
  transferring = false;
645
655
  setTransferring(value) {
646
656
  this.transferring = value;
657
+ if (value)
658
+ this._invalidateWaitPromptHandoffs("Session transfer interrupted the pending prompt.");
647
659
  }
648
660
  assertCanStartWork() {
649
661
  this.sessionManager.assertWritable();
@@ -651,6 +663,9 @@ export class AgentSession {
651
663
  throw new Error("Session transfer is in progress. Wait or reclaim the session.");
652
664
  }
653
665
  dispose() {
666
+ this._invalidateWaitPromptHandoffs("Session closed before the pending prompt could run.");
667
+ for (const unregister of this._unregisterSubagentWaitInterruptionOwners.splice(0))
668
+ unregister();
654
669
  try {
655
670
  this.abortRetry();
656
671
  this.abortCompaction();
@@ -690,6 +705,10 @@ export class AgentSession {
690
705
  get isIdle() {
691
706
  return !this._isAgentRunActive;
692
707
  }
708
+ /** Whether normal Enter is still being reserved for an interrupted wait handoff. */
709
+ get isWaitPromptHandoffActive() {
710
+ return this._waitPromptHandoff?.accepting === true;
711
+ }
693
712
  /** Current effective system prompt (includes any per-turn extension modifications) */
694
713
  get systemPrompt() {
695
714
  return this.agent.state.systemPrompt;
@@ -885,24 +904,67 @@ export class AgentSession {
885
904
  // =========================================================================
886
905
  // Prompting
887
906
  // =========================================================================
907
+ _registerSubagentWaitInterruption() {
908
+ const run = this._activePromptRun;
909
+ const ownerSignal = this.agent.signal;
910
+ const wait = run && ownerSignal ? { controller: new AbortController(), interrupted: false, ownerSignal } : undefined;
911
+ if (run && wait) {
912
+ run.waits.add(wait);
913
+ if (run.gracefulStopRequested) {
914
+ wait.interrupted = true;
915
+ wait.controller.abort();
916
+ }
917
+ }
918
+ const signal = wait?.controller.signal ?? new AbortController().signal;
919
+ return {
920
+ signal,
921
+ wasInterrupted: () => wait?.interrupted === true,
922
+ unregister: () => {
923
+ if (wait)
924
+ run?.waits.delete(wait);
925
+ },
926
+ };
927
+ }
928
+ _interruptSubagentWaits(run, ownerSignal) {
929
+ for (const wait of run.waits) {
930
+ if (wait.ownerSignal !== ownerSignal)
931
+ continue;
932
+ wait.interrupted = true;
933
+ wait.controller.abort();
934
+ }
935
+ }
936
+ _invalidateWaitPromptHandoffs(message) {
937
+ this._waitPromptGeneration++;
938
+ const handoff = this._waitPromptHandoff;
939
+ this._waitPromptHandoff = undefined;
940
+ if (!handoff)
941
+ return;
942
+ const error = new Error(message);
943
+ for (const reservation of handoff.reservations.splice(0))
944
+ reservation.reject(error);
945
+ }
888
946
  async _runAgentPrompt(messages) {
947
+ const run = { waits: new Set(), gracefulStopRequested: false };
948
+ this._activePromptRun = run;
889
949
  this._isAgentRunActive = true;
890
950
  try {
891
951
  await this.agent.prompt(messages);
892
- while (await this._handlePostAgentRun()) {
952
+ while (await this._handlePostAgentRun(run)) {
893
953
  await this.agent.continue();
894
954
  }
895
955
  }
896
956
  finally {
957
+ if (this._activePromptRun === run)
958
+ this._activePromptRun = undefined;
897
959
  this._systemPromptOverride = undefined;
898
960
  this._flushPendingBashMessages();
899
961
  await this._emitAgentSettled();
900
962
  }
901
963
  }
902
- async _handlePostAgentRun() {
964
+ async _handlePostAgentRun(run) {
903
965
  const msg = this._lastAssistantMessage;
904
966
  this._lastAssistantMessage = undefined;
905
- if (!msg) {
967
+ if (!msg || run.gracefulStopRequested) {
906
968
  return false;
907
969
  }
908
970
  // lunr: quota-dead or auth-invalid keys rotate immediately — same-key backoff
@@ -944,130 +1006,193 @@ export class AgentSession {
944
1006
  */
945
1007
  async prompt(text, options) {
946
1008
  this.assertCanStartWork();
947
- const expandPromptTemplates = options?.expandPromptTemplates ?? true;
948
1009
  const preflightResult = options?.preflightResult;
1010
+ let prepared;
949
1011
  let messages;
950
1012
  try {
951
- // Handle extension commands first (execute immediately, even during streaming)
952
- // Extension commands manage their own LLM interaction via pi.sendMessage()
953
- if (expandPromptTemplates && text.startsWith("/")) {
954
- const handled = await this._tryExecuteExtensionCommand(text);
955
- if (handled) {
956
- // Extension command executed, no prompt to send
957
- preflightResult?.(true);
958
- return;
959
- }
960
- }
961
- // Emit input event for extension interception (before skill/template expansion)
962
- let currentText = text;
963
- let currentImages = options?.images;
964
- if (this._extensionRunner.hasHandlers("input")) {
965
- const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive", this.isStreaming ? options?.streamingBehavior : undefined);
966
- if (inputResult.action === "handled") {
967
- preflightResult?.(true);
968
- return;
969
- }
970
- if (inputResult.action === "transform") {
971
- currentText = inputResult.text;
972
- currentImages = inputResult.images ?? currentImages;
973
- }
974
- }
975
- // Expand skill commands (/skill:name args) and prompt templates (/template args)
976
- let expandedText = currentText;
977
- if (expandPromptTemplates) {
978
- expandedText = this._expandSkillCommand(expandedText);
979
- expandedText = expandPromptTemplate(expandedText, [...this.promptTemplates]);
1013
+ prepared = await this._preparePromptInput(text, options, this.isStreaming ? options?.streamingBehavior : undefined);
1014
+ if (!prepared) {
1015
+ preflightResult?.(true);
1016
+ return;
980
1017
  }
981
- // If streaming, queue via steer() or followUp() based on option
982
1018
  if (this.isStreaming) {
983
1019
  if (!options?.streamingBehavior) {
984
1020
  throw new Error("Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.");
985
1021
  }
986
1022
  if (options.streamingBehavior === "followUp") {
987
- await this._queueFollowUp(expandedText, currentImages);
1023
+ await this._queueFollowUp(prepared.text, prepared.images);
988
1024
  }
989
1025
  else {
990
- await this._queueSteer(expandedText, currentImages);
1026
+ await this._queueSteer(prepared.text, prepared.images);
991
1027
  }
992
1028
  preflightResult?.(true);
993
1029
  return;
994
1030
  }
995
- // Flush any pending bash messages before the new prompt
996
- this._flushPendingBashMessages();
997
- // Validate model
998
- if (!this.model) {
999
- throw new Error(formatNoModelSelectedMessage());
1000
- }
1001
- const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) ||
1002
- (await this._modelRuntime.checkAuth(this.model.provider)) !== undefined;
1003
- if (!hasConfiguredAuth) {
1004
- const isOAuth = this._modelRuntime.isUsingOAuth(this.model.provider);
1005
- if (isOAuth) {
1006
- throw new Error(`Authentication failed for "${this.model.provider}". ` +
1007
- `Credentials may have expired or network is unavailable. ` +
1008
- `Run '/login ${this.model.provider}' to re-authenticate.`);
1009
- }
1010
- throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
1011
- }
1012
- // Check if we need to compact before sending (catches aborted responses).
1013
- // The user's new prompt is sent below, so do not call agent.continue() here.
1014
- const lastAssistant = this._findLastAssistantMessage();
1015
- if (lastAssistant) {
1016
- await this._checkCompaction(lastAssistant, false);
1017
- }
1018
- // Build messages array (custom message if any, then user message)
1019
- messages = [];
1020
- // Add user message
1021
- const userContent = [{ type: "text", text: expandedText }];
1022
- if (currentImages) {
1023
- userContent.push(...currentImages);
1024
- }
1025
- messages.push({
1031
+ messages = await this._createPromptMessages(prepared);
1032
+ }
1033
+ catch (error) {
1034
+ preflightResult?.(false);
1035
+ throw error;
1036
+ }
1037
+ preflightResult?.(true);
1038
+ await this._runAgentPrompt(messages);
1039
+ }
1040
+ async _preparePromptInput(text, options, streamingBehavior) {
1041
+ const expandPromptTemplates = options?.expandPromptTemplates ?? true;
1042
+ if (expandPromptTemplates && text.startsWith("/") && (await this._tryExecuteExtensionCommand(text))) {
1043
+ return undefined;
1044
+ }
1045
+ let currentText = text;
1046
+ let currentImages = options?.images;
1047
+ if (this._extensionRunner.hasHandlers("input")) {
1048
+ const inputResult = await this._extensionRunner.emitInput(currentText, currentImages, options?.source ?? "interactive", streamingBehavior);
1049
+ if (inputResult.action === "handled")
1050
+ return undefined;
1051
+ if (inputResult.action === "transform") {
1052
+ currentText = inputResult.text;
1053
+ currentImages = inputResult.images ?? currentImages;
1054
+ }
1055
+ }
1056
+ if (expandPromptTemplates) {
1057
+ currentText = this._expandSkillCommand(currentText);
1058
+ currentText = expandPromptTemplate(currentText, [...this.promptTemplates]);
1059
+ }
1060
+ return { text: currentText, images: currentImages };
1061
+ }
1062
+ async _createPromptMessages(input) {
1063
+ this._flushPendingBashMessages();
1064
+ if (!this.model)
1065
+ throw new Error(formatNoModelSelectedMessage());
1066
+ const hasConfiguredAuth = this._modelRuntime.hasConfiguredAuth(this.model.provider) ||
1067
+ (await this._modelRuntime.checkAuth(this.model.provider)) !== undefined;
1068
+ if (!hasConfiguredAuth) {
1069
+ if (this._modelRuntime.isUsingOAuth(this.model.provider)) {
1070
+ throw new Error(`Authentication failed for "${this.model.provider}". ` +
1071
+ `Credentials may have expired or network is unavailable. ` +
1072
+ `Run '/login ${this.model.provider}' to re-authenticate.`);
1073
+ }
1074
+ throw new Error(formatNoApiKeyFoundMessage(this.model.provider));
1075
+ }
1076
+ const lastAssistant = this._findLastAssistantMessage();
1077
+ if (lastAssistant)
1078
+ await this._checkCompaction(lastAssistant, false);
1079
+ const userContent = [{ type: "text", text: input.text }];
1080
+ if (input.images)
1081
+ userContent.push(...input.images);
1082
+ const messages = [
1083
+ {
1026
1084
  role: "user",
1027
1085
  content: userContent,
1028
1086
  timestamp: Date.now(),
1029
- });
1030
- // Inject any pending "nextTurn" messages as context alongside the user message
1031
- for (const msg of this._pendingNextTurnMessages) {
1032
- messages.push(msg);
1033
- }
1034
- this._pendingNextTurnMessages = [];
1035
- // Emit before_agent_start extension event
1036
- const result = await this._extensionRunner.emitBeforeAgentStart(expandedText, currentImages, this._baseSystemPrompt, this._baseSystemPromptOptions);
1037
- // Add all custom messages from extensions
1038
- if (result?.messages) {
1039
- for (const msg of result.messages) {
1040
- messages.push({
1041
- role: "custom",
1042
- customType: msg.customType,
1043
- // Untyped extensions can pass null/missing content; normalize at ingestion.
1044
- content: msg.content ?? [],
1045
- display: msg.display,
1046
- details: msg.details,
1047
- timestamp: Date.now(),
1048
- });
1049
- }
1050
- }
1051
- // Apply extension-modified system prompt, or reset to base
1052
- if (result?.systemPrompt !== undefined) {
1053
- this._systemPromptOverride = result.systemPrompt;
1054
- this.agent.state.systemPrompt = this._withSystemPromptAppend(result.systemPrompt);
1055
- }
1056
- else {
1057
- // Ensure we're using the base prompt (in case previous turn had modifications)
1058
- this._systemPromptOverride = undefined;
1059
- this.agent.state.systemPrompt = this._withSystemPromptAppend(this._baseSystemPrompt);
1087
+ },
1088
+ ...this._pendingNextTurnMessages,
1089
+ ];
1090
+ this._pendingNextTurnMessages = [];
1091
+ const result = await this._extensionRunner.emitBeforeAgentStart(input.text, input.images, this._baseSystemPrompt, this._baseSystemPromptOptions);
1092
+ if (result?.messages) {
1093
+ for (const msg of result.messages) {
1094
+ messages.push({
1095
+ role: "custom",
1096
+ customType: msg.customType,
1097
+ content: msg.content ?? [],
1098
+ display: msg.display,
1099
+ details: msg.details,
1100
+ timestamp: Date.now(),
1101
+ });
1060
1102
  }
1061
1103
  }
1104
+ if (result?.systemPrompt !== undefined) {
1105
+ this._systemPromptOverride = result.systemPrompt;
1106
+ this.agent.state.systemPrompt = this._withSystemPromptAppend(result.systemPrompt);
1107
+ }
1108
+ else {
1109
+ this._systemPromptOverride = undefined;
1110
+ this.agent.state.systemPrompt = this._withSystemPromptAppend(this._baseSystemPrompt);
1111
+ }
1112
+ return messages;
1113
+ }
1114
+ async interruptSubagentWaitWithPrompt(text, options) {
1115
+ const acceptance = this._waitPromptAcceptance.then(() => this._reserveWaitPrompt(text, options));
1116
+ this._waitPromptAcceptance = acceptance.then(() => { }, () => { });
1117
+ return acceptance;
1118
+ }
1119
+ async _reserveWaitPrompt(text, options) {
1120
+ this.assertCanStartWork();
1121
+ const activeRun = this._activePromptRun;
1122
+ const existing = this._waitPromptHandoff;
1123
+ const activeWait = activeRun?.waits.values().next().value;
1124
+ const run = existing?.accepting ? existing.run : activeWait ? activeRun : undefined;
1125
+ const ownerSignal = existing?.accepting ? existing.ownerSignal : activeWait?.ownerSignal;
1126
+ if (!run || !ownerSignal)
1127
+ return undefined;
1128
+ const handoff = existing?.run === run && existing.accepting
1129
+ ? existing
1130
+ : {
1131
+ run,
1132
+ ownerSignal,
1133
+ generation: this._waitPromptGeneration,
1134
+ reservations: [],
1135
+ draining: false,
1136
+ accepting: true,
1137
+ };
1138
+ this._waitPromptHandoff = handoff;
1139
+ let prepared;
1140
+ try {
1141
+ prepared = await this._preparePromptInput(text, options, undefined);
1142
+ }
1062
1143
  catch (error) {
1063
- preflightResult?.(false);
1144
+ if (handoff.reservations.length === 0 && this._waitPromptHandoff === handoff) {
1145
+ this._waitPromptHandoff = undefined;
1146
+ }
1064
1147
  throw error;
1065
1148
  }
1066
- if (!messages) {
1067
- return;
1149
+ if (!prepared) {
1150
+ if (handoff.reservations.length === 0 && this._waitPromptHandoff === handoff) {
1151
+ this._waitPromptHandoff = undefined;
1152
+ }
1153
+ return { completion: Promise.resolve() };
1068
1154
  }
1069
- preflightResult?.(true);
1070
- await this._runAgentPrompt(messages);
1155
+ let resolveCompletion = () => { };
1156
+ let rejectCompletion = (_error) => { };
1157
+ const completion = new Promise((resolve, reject) => {
1158
+ resolveCompletion = resolve;
1159
+ rejectCompletion = reject;
1160
+ });
1161
+ handoff.reservations.push({ input: prepared, resolve: resolveCompletion, reject: rejectCompletion });
1162
+ if (!run.gracefulStopRequested && this.agent.requestGracefulStop(handoff.ownerSignal)) {
1163
+ run.gracefulStopRequested = true;
1164
+ }
1165
+ this._interruptSubagentWaits(run, handoff.ownerSignal);
1166
+ if (!handoff.draining) {
1167
+ handoff.draining = true;
1168
+ void this._drainWaitPromptHandoff(handoff);
1169
+ }
1170
+ return { completion };
1171
+ }
1172
+ async _drainWaitPromptHandoff(handoff) {
1173
+ await this.waitForIdle();
1174
+ while (this._waitPromptHandoff === handoff &&
1175
+ handoff.generation === this._waitPromptGeneration &&
1176
+ handoff.reservations.length > 0) {
1177
+ const reservation = handoff.reservations[0];
1178
+ try {
1179
+ this.assertCanStartWork();
1180
+ const messages = await this._createPromptMessages(reservation.input);
1181
+ handoff.accepting = false;
1182
+ await this._runAgentPrompt(messages);
1183
+ reservation.resolve();
1184
+ }
1185
+ catch (error) {
1186
+ reservation.reject(error);
1187
+ }
1188
+ finally {
1189
+ if (handoff.reservations[0] === reservation)
1190
+ handoff.reservations.shift();
1191
+ }
1192
+ }
1193
+ handoff.accepting = false;
1194
+ if (this._waitPromptHandoff === handoff)
1195
+ this._waitPromptHandoff = undefined;
1071
1196
  }
1072
1197
  /**
1073
1198
  * Try to execute an extension command. Returns true if command was found and executed.
@@ -1320,6 +1445,7 @@ export class AgentSession {
1320
1445
  * Abort current operation and wait for agent to become idle.
1321
1446
  */
1322
1447
  async abort() {
1448
+ this._invalidateWaitPromptHandoffs("The active run was aborted before the pending prompt could run.");
1323
1449
  this.abortRetry();
1324
1450
  this.agent.abort();
1325
1451
  await this.waitForIdle();
@@ -2339,6 +2465,7 @@ export class AgentSession {
2339
2465
  });
2340
2466
  }
2341
2467
  async reload(options) {
2468
+ this._invalidateWaitPromptHandoffs("Extensions reloaded before the pending prompt could run.");
2342
2469
  const previousFlagValues = this._extensionRunner.getFlagValues();
2343
2470
  await emitSessionShutdownEvent(this._extensionRunner, { type: "session_shutdown", reason: "reload" });
2344
2471
  await this.settingsManager.reload();