@bastani/atomic 0.9.16-alpha.7 → 0.9.16-alpha.8

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 +19 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  3. package/dist/builtin/intercom/README.md +4 -4
  4. package/dist/builtin/intercom/broker/broker.ts +617 -22
  5. package/dist/builtin/intercom/broker/client-message-validation.ts +9 -0
  6. package/dist/builtin/intercom/broker/client.ts +200 -10
  7. package/dist/builtin/intercom/broker/pending-send-registry.ts +4 -0
  8. package/dist/builtin/intercom/broker/send-handler.ts +90 -36
  9. package/dist/builtin/intercom/broker/send-signature.ts +20 -8
  10. package/dist/builtin/intercom/group.ts +85 -0
  11. package/dist/builtin/intercom/index.bundle.mjs +680 -53
  12. package/dist/builtin/intercom/package.json +1 -1
  13. package/dist/builtin/intercom/session-target.ts +54 -0
  14. package/dist/builtin/intercom/skills/intercom/SKILL.md +18 -3
  15. package/dist/builtin/intercom/source-ownership.ts +31 -0
  16. package/dist/builtin/intercom/types.ts +115 -0
  17. package/dist/builtin/mcp/index.bundle.mjs +109 -35
  18. package/dist/builtin/mcp/package.json +1 -1
  19. package/dist/builtin/subagents/package.json +1 -1
  20. package/dist/builtin/subagents/src/extension/index.bundle.mjs +173 -51
  21. package/dist/builtin/web-access/index.bundle.mjs +109 -35
  22. package/dist/builtin/web-access/package.json +1 -1
  23. package/dist/builtin/workflows/CHANGELOG.md +15 -0
  24. package/dist/builtin/workflows/README.md +40 -37
  25. package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
  26. package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +133 -154
  27. package/dist/builtin/workflows/builtin/chunk-29wrp38a.js +199 -0
  28. package/dist/builtin/workflows/builtin/chunk-2dqb5s2q.js +602 -0
  29. package/dist/builtin/workflows/builtin/chunk-4febxsv4.js +264 -0
  30. package/dist/builtin/workflows/builtin/chunk-5n10x7j2.js +69730 -0
  31. package/dist/builtin/workflows/builtin/chunk-5wgwscd0.js +4 -0
  32. package/dist/builtin/workflows/builtin/chunk-6fqs7c01.js +155 -0
  33. package/dist/builtin/workflows/builtin/chunk-7430zyas.js +126 -0
  34. package/dist/builtin/workflows/builtin/chunk-7at6dnkr.js +33 -0
  35. package/dist/builtin/workflows/builtin/chunk-82ha8p41.js +175 -0
  36. package/dist/builtin/workflows/builtin/chunk-bfkmzv9h.js +156 -0
  37. package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
  38. package/dist/builtin/workflows/builtin/chunk-cdtd3m3w.js +529 -0
  39. package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
  40. package/dist/builtin/workflows/builtin/chunk-hdpj1dkw.js +2447 -0
  41. package/dist/builtin/workflows/builtin/chunk-hzzn6adg.js +221 -0
  42. package/dist/builtin/workflows/builtin/chunk-nqr34qp3.js +1061 -0
  43. package/dist/builtin/workflows/builtin/chunk-qwzvgxnq.js +404 -0
  44. package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
  45. package/dist/builtin/workflows/builtin/chunk-v04c5qmd.js +1207 -0
  46. package/dist/builtin/workflows/builtin/chunk-wpckd35c.js +12 -0
  47. package/dist/builtin/workflows/builtin/chunk-x2ghn0je.js +4110 -0
  48. package/dist/builtin/workflows/builtin/chunk-zf28603f.js +1080 -0
  49. package/dist/builtin/workflows/builtin/classify-and-act.js +12 -0
  50. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +10 -0
  51. package/dist/builtin/workflows/builtin/generate-and-filter.js +12 -0
  52. package/dist/builtin/workflows/builtin/goal.js +16 -0
  53. package/dist/builtin/workflows/builtin/index.js +49 -0
  54. package/dist/builtin/workflows/builtin/loop-until-done.js +12 -0
  55. package/dist/builtin/workflows/builtin/open-claude-design.js +11 -0
  56. package/dist/builtin/workflows/builtin/ralph.js +16 -0
  57. package/dist/builtin/workflows/builtin/steering-context.d.ts +6 -0
  58. package/dist/builtin/workflows/builtin/steering-context.js +7 -0
  59. package/dist/builtin/workflows/builtin/tournament.js +13 -0
  60. package/dist/builtin/workflows/package.json +10 -7
  61. package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
  62. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1228 -428
  63. package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +956 -427
  64. package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +403 -0
  65. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +327 -0
  66. package/dist/builtin/workflows/src/shared/budget.d.ts +67 -0
  67. package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +60 -0
  68. package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
  69. package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
  70. package/dist/core/agent-session-custom-message-commit.js +12 -5
  71. package/dist/core/agent-session-custom-message-commit.js.map +1 -1
  72. package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
  73. package/dist/core/agent-session-persistent-custom-messages.js +2 -0
  74. package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
  75. package/dist/core/agent-session.d.ts.map +1 -1
  76. package/dist/core/agent-session.js +2 -1
  77. package/dist/core/agent-session.js.map +1 -1
  78. package/dist/core/auth-storage.d.ts +2 -0
  79. package/dist/core/auth-storage.d.ts.map +1 -1
  80. package/dist/core/auth-storage.js +4 -0
  81. package/dist/core/auth-storage.js.map +1 -1
  82. package/dist/core/builtin-install-layout.d.ts +1 -1
  83. package/dist/core/builtin-install-layout.d.ts.map +1 -1
  84. package/dist/core/builtin-install-layout.js +1 -1
  85. package/dist/core/builtin-install-layout.js.map +1 -1
  86. package/dist/core/codex-fast-mode.d.ts +10 -7
  87. package/dist/core/codex-fast-mode.d.ts.map +1 -1
  88. package/dist/core/codex-fast-mode.js +31 -13
  89. package/dist/core/codex-fast-mode.js.map +1 -1
  90. package/dist/core/extensions/context-types.d.ts +35 -0
  91. package/dist/core/extensions/context-types.d.ts.map +1 -1
  92. package/dist/core/extensions/context-types.js.map +1 -1
  93. package/dist/core/extensions/index.d.ts +1 -1
  94. package/dist/core/extensions/index.d.ts.map +1 -1
  95. package/dist/core/extensions/index.js.map +1 -1
  96. package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
  97. package/dist/core/extensions/loader-virtual-modules.js +6 -1
  98. package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
  99. package/dist/core/model-runtime.d.ts +2 -0
  100. package/dist/core/model-runtime.d.ts.map +1 -1
  101. package/dist/core/model-runtime.js +4 -0
  102. package/dist/core/model-runtime.js.map +1 -1
  103. package/dist/core/runtime-credentials.d.ts +1 -0
  104. package/dist/core/runtime-credentials.d.ts.map +1 -1
  105. package/dist/core/runtime-credentials.js +8 -0
  106. package/dist/core/runtime-credentials.js.map +1 -1
  107. package/dist/core/sdk.d.ts.map +1 -1
  108. package/dist/core/sdk.js +5 -5
  109. package/dist/core/sdk.js.map +1 -1
  110. package/dist/core/session-manager-storage.d.ts +2 -0
  111. package/dist/core/session-manager-storage.d.ts.map +1 -1
  112. package/dist/core/session-manager-storage.js +4 -2
  113. package/dist/core/session-manager-storage.js.map +1 -1
  114. package/dist/core/slash-commands.js +1 -1
  115. package/dist/core/slash-commands.js.map +1 -1
  116. package/dist/core/workflow-stage-admission.d.ts +6 -1
  117. package/dist/core/workflow-stage-admission.d.ts.map +1 -1
  118. package/dist/core/workflow-stage-admission.js +8 -9
  119. package/dist/core/workflow-stage-admission.js.map +1 -1
  120. package/dist/index.d.ts +0 -1
  121. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  122. package/dist/modes/interactive/components/footer.js +1 -1
  123. package/dist/modes/interactive/components/footer.js.map +1 -1
  124. package/dist/modes/interactive/interactive-autocomplete.js +1 -1
  125. package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  126. package/dist/modes/interactive/interactive-startup.js +1 -1
  127. package/dist/modes/interactive/interactive-startup.js.map +1 -1
  128. package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -0
  129. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  130. package/dist/modes/interactive-engine/isolated-runtime.js +69 -10
  131. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  132. package/dist/modes/rpc/rpc-client-api.d.ts +18 -2
  133. package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
  134. package/dist/modes/rpc/rpc-client-api.js +33 -5
  135. package/dist/modes/rpc/rpc-client-api.js.map +1 -1
  136. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  137. package/dist/modes/rpc/rpc-command-handler.js +8 -4
  138. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  139. package/dist/modes/rpc/rpc-types.d.ts +13 -0
  140. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  141. package/dist/modes/rpc/rpc-types.js.map +1 -1
  142. package/docs/intercom.md +15 -6
  143. package/docs/packages.md +2 -2
  144. package/docs/providers.md +8 -3
  145. package/docs/quickstart.md +2 -2
  146. package/docs/rpc.md +21 -4
  147. package/docs/settings.md +6 -4
  148. package/docs/subagents.md +1 -1
  149. package/docs/usage.md +1 -1
  150. package/docs/workflows.md +108 -239
  151. package/npm-shrinkwrap.json +32 -32
  152. package/package.json +9 -13
  153. package/dist/builtin/workflows/ambient.d.ts +0 -61
  154. package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
  155. package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
  156. package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
  157. package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
  158. package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
  159. package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
  160. package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
  161. package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
  162. package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
  163. package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
  164. package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
  165. package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
  166. package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
  167. package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
  168. package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
  169. package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
  170. package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
  171. package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -217
  172. package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
  173. package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
  174. package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
  175. package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
  176. package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
  177. package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
  178. package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
  179. package/dist/builtin/workflows/builtin/goal.ts +0 -78
  180. package/dist/builtin/workflows/builtin/index.ts +0 -16
  181. package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
  182. package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
  183. package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
  184. package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
  185. package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
  186. package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
  187. package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
  188. package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
  189. package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
  190. package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
  191. package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
  192. package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
  193. package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
  194. package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
  195. package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
  196. package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -104
  197. package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -459
  198. package/dist/builtin/workflows/builtin/ralph.ts +0 -82
  199. package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
  200. package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
  201. package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
  202. package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
  203. package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
  204. package/dist/builtin/workflows/builtin/tournament.ts +0 -73
  205. package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
  206. package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
  207. package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
@@ -3854,10 +3854,10 @@ function hasAssistantMessage(entries) {
3854
3854
  return entries.some((entry) => entry.type === "message" && entry.message.role === "assistant");
3855
3855
  }
3856
3856
  function persistAppendedEntry(filePath, entries, entry, flushed) {
3857
- if (!hasAssistantMessage(entries))
3858
- return false;
3859
3857
  if (flushed)
3860
3858
  appendSessionEntry(filePath, entry);
3859
+ else if (!hasAssistantMessage(entries))
3860
+ return false;
3861
3861
  else
3862
3862
  appendSessionEntries(filePath, entries);
3863
3863
  return true;
@@ -9925,6 +9925,8 @@ function appendDurableDisplayCard(session, message, delivery) {
9925
9925
  const card = { ...message, excludeFromContext: true };
9926
9926
  const admitted = message;
9927
9927
  const intentEntryId = session.sessionManager.appendCustomMessageEntry(card.customType, card.content, card.display, card.details, true, { delivery }, admitted.stageAdmissionKey);
9928
+ if (admitted.stageAdmissionKey !== undefined)
9929
+ session.sessionManager.flush();
9928
9930
  session.agent.state.messages.push(card);
9929
9931
  return { card, intentEntryId };
9930
9932
  }
@@ -10150,12 +10152,17 @@ var init_agent_session_persistent_custom_messages = __esm(() => {
10150
10152
  });
10151
10153
 
10152
10154
  // src/core/agent-session-custom-message-commit.ts
10155
+ function appendDurableStageAdmission(session, message) {
10156
+ session._appendCustomMessage(message);
10157
+ if (message.stageAdmissionKey !== undefined)
10158
+ session.sessionManager?.flush();
10159
+ }
10153
10160
  async function commitAdmittedCustomMessage(session, appMessage, options) {
10154
10161
  const owner = resolveWorkflowStageDeliveryTarget(session);
10155
10162
  if (owner !== session)
10156
10163
  return commitAdmittedCustomMessage(owner, appMessage, options);
10157
10164
  const self = session;
10158
- const useProtectedReconciliation = options?.persistWhenStreaming === true && options.triggerTurn === true && options.excludeFromContext !== true;
10165
+ const useProtectedReconciliation = options?.persistWhenStreaming === true && options.excludeFromContext !== true && (options.triggerTurn === true || options.stageAdmissionKey !== undefined);
10159
10166
  if (options?.deliverAs === "nextTurn") {
10160
10167
  self._pendingNextTurnMessages.push(appMessage);
10161
10168
  } else if (self._queuedMessagesPaused) {
@@ -10169,20 +10176,20 @@ async function commitAdmittedCustomMessage(session, appMessage, options) {
10169
10176
  } else if (self.isStreaming) {
10170
10177
  self._pendingCustomMessages.push(appMessage);
10171
10178
  } else {
10172
- self._appendCustomMessage(appMessage);
10179
+ appendDurableStageAdmission(self, appMessage);
10173
10180
  }
10174
10181
  } else if (options?.deliverAs === "interrupt" && options.triggerTurn) {
10175
10182
  const interrupt = self._enqueueInterruptCustomMessage(appMessage, options);
10176
10183
  self._workflowStageAdmission?.trackAdmittedWork(interrupt);
10177
10184
  interrupt.catch(() => {});
10178
10185
  } else if (self.isStreaming && options?.excludeFromContext === true && options.triggerTurn !== true && options.deliverAs === undefined) {
10179
- self._appendCustomMessage(appMessage);
10186
+ appendDurableStageAdmission(self, appMessage);
10180
10187
  } else if (self.isStreaming && options?.triggerTurn === false) {
10181
10188
  self._pendingCustomMessages.push(appMessage);
10182
10189
  } else if (self.isStreaming && useProtectedReconciliation) {
10183
10190
  await queueProtectedStreamingCustomMessage(self, appMessage, options?.deliverAs === "followUp" ? "followUp" : "steer");
10184
10191
  } else if (self.isStreaming && options?.persistWhenStreaming === true) {
10185
- self._appendCustomMessage(appMessage);
10192
+ appendDurableStageAdmission(self, appMessage);
10186
10193
  } else if (self.isStreaming && options?.triggerTurn !== false) {
10187
10194
  self._queueAgentMessage(appMessage, options?.deliverAs === "followUp" ? "followUp" : "steer");
10188
10195
  } else if (options?.triggerTurn) {
@@ -10205,7 +10212,7 @@ async function commitAdmittedCustomMessage(session, appMessage, options) {
10205
10212
  self._continueQueuedAgentMessages().catch(() => {});
10206
10213
  }
10207
10214
  } else {
10208
- self._appendCustomMessage(appMessage);
10215
+ appendDurableStageAdmission(self, appMessage);
10209
10216
  }
10210
10217
  }
10211
10218
  function _commitAdmittedCustomMessage(appMessage, options) {
@@ -21607,11 +21614,20 @@ import {
21607
21614
  function isCodexFastModeSupportedProvider(provider) {
21608
21615
  return provider === "openai" || provider === "openai-codex";
21609
21616
  }
21610
- function isCodexFastModeSupportedModel(model) {
21611
- return isCodexFastModeSupportedProvider(model.provider) || model.api === "openai-codex-responses";
21617
+ function isGitHubCopilotModel(model) {
21618
+ return model.provider === "github-copilot";
21612
21619
  }
21613
- function hasSupportedCodexFastModeModel(models) {
21614
- return models.some(isCodexFastModeSupportedModel);
21620
+ function isGitHubCopilotFastModeSupportedModel(model, credential) {
21621
+ if (!isGitHubCopilotModel(model) || credential?.type !== "oauth")
21622
+ return false;
21623
+ const fastModelIds = credential.fastModelIds;
21624
+ return Array.isArray(fastModelIds) && fastModelIds.every((modelId) => typeof modelId === "string") && fastModelIds.includes(`${model.id}-fast`);
21625
+ }
21626
+ function isCodexFastModeSupportedModel(model, copilotCredential) {
21627
+ return isCodexFastModeSupportedProvider(model.provider) || model.api === "openai-codex-responses" || model.id !== undefined && isGitHubCopilotFastModeSupportedModel({ provider: model.provider, id: model.id }, copilotCredential);
21628
+ }
21629
+ function hasSupportedCodexFastModeModel(models, copilotCredential) {
21630
+ return models.some((model) => isCodexFastModeSupportedModel(model, copilotCredential));
21615
21631
  }
21616
21632
  function isWorkflowStageOrchestrationContext(context) {
21617
21633
  return context?.kind === "workflow-stage";
@@ -21622,11 +21638,11 @@ function getCodexFastModeScope(context) {
21622
21638
  function isCodexFastModeEnabledForScope(settings, scope) {
21623
21639
  return settings[scope];
21624
21640
  }
21625
- function shouldApplyCodexFastModeForScope(model, settings, scope) {
21626
- return isCodexFastModeSupportedModel(model) && isCodexFastModeEnabledForScope(settings, scope);
21641
+ function shouldApplyCodexFastModeForScope(model, settings, scope, copilotCredential) {
21642
+ return isCodexFastModeSupportedModel(model, copilotCredential) && isCodexFastModeEnabledForScope(settings, scope);
21627
21643
  }
21628
- function shouldApplyCodexFastMode(model, settings, context) {
21629
- return shouldApplyCodexFastModeForScope(model, settings, getCodexFastModeScope(context));
21644
+ function shouldApplyCodexFastMode(model, settings, context, copilotCredential) {
21645
+ return shouldApplyCodexFastModeForScope(model, settings, getCodexFastModeScope(context), copilotCredential);
21630
21646
  }
21631
21647
  function formatCodexFastModeModelLabel(modelName, enabled) {
21632
21648
  return enabled ? `${modelName} fast` : modelName;
@@ -21767,7 +21783,7 @@ class FooterComponent {
21767
21783
  pwd += ` • ${sessionName}`;
21768
21784
  const modelName = state.model?.id || "no-model";
21769
21785
  const fastModeSettings = this.session.settingsManager.getCodexFastModeSettings();
21770
- const fastModeEnabled = state.model ? shouldApplyCodexFastMode(state.model, fastModeSettings, this.session.orchestrationContext) : false;
21786
+ const fastModeEnabled = state.model ? shouldApplyCodexFastMode(state.model, fastModeSettings, this.session.orchestrationContext, this.session.modelRuntime.getCredentialSnapshot?.("github-copilot")) : false;
21771
21787
  let modelLabel2 = modelName;
21772
21788
  if (state.model?.reasoning) {
21773
21789
  const thinkingLevel = state.thinkingLevel || "off";
@@ -39355,14 +39371,18 @@ import { AsyncLocalStorage } from "node:async_hooks";
39355
39371
 
39356
39372
  class WorkflowStageAdmissionBoundary {
39357
39373
  open = true;
39358
- completed = new Set;
39374
+ completed;
39359
39375
  inFlight = new Map;
39360
39376
  pending = new Set;
39361
39377
  invocationContext = new AsyncLocalStorage;
39362
39378
  closePromise;
39363
39379
  drainAdmittedWork;
39364
- constructor(drainAdmittedWork = async () => {}) {
39365
- this.drainAdmittedWork = drainAdmittedWork;
39380
+ constructor(drainAdmittedWork = undefined, completedKeys = []) {
39381
+ this.drainAdmittedWork = drainAdmittedWork ?? (async () => {});
39382
+ this.completed = new Set(completedKeys);
39383
+ }
39384
+ static restore(entries, drainAdmittedWork) {
39385
+ return new WorkflowStageAdmissionBoundary(drainAdmittedWork, Array.from(entries).flatMap((entry) => entry.type === "custom_message" && typeof entry.stageAdmissionKey === "string" ? [entry.stageAdmissionKey] : []));
39366
39386
  }
39367
39387
  admit(key, deliver, routeLate) {
39368
39388
  if (key !== undefined) {
@@ -39601,7 +39621,7 @@ class AgentSessionBase {
39601
39621
  this._subagentPolicy = config.subagentPolicy;
39602
39622
  this._systemPromptTransform = config.systemPromptTransform;
39603
39623
  const stageContext = config.orchestrationContext?.kind === "workflow-stage" ? config.orchestrationContext : undefined;
39604
- this._workflowStageAdmission = stageContext?.messageAdmission?.boundary ?? (stageContext ? new WorkflowStageAdmissionBoundary : undefined);
39624
+ this._workflowStageAdmission = stageContext?.messageAdmission?.boundary ?? (stageContext ? WorkflowStageAdmissionBoundary.restore(this.sessionManager.getBranch()) : undefined);
39605
39625
  if (this._workflowStageAdmission && stageContext && stageContext.messageAdmission === undefined) {
39606
39626
  stageContext.messageAdmission = {
39607
39627
  boundary: this._workflowStageAdmission,
@@ -46560,6 +46580,31 @@ class RemoteQueuePause {
46560
46580
  var init_remote_queue_pause = () => {};
46561
46581
 
46562
46582
  // src/modes/interactive-engine/isolated-runtime.ts
46583
+ import { clampThinkingLevel as clampThinkingLevel5 } from "@bastani/pi-ai/compat";
46584
+ function applyPersistedModelDefault(session, model, alreadyInScope) {
46585
+ session.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
46586
+ if (alreadyInScope || session.scopedModels.length === 0)
46587
+ return;
46588
+ const enabledModels = session.settingsManager.getEnabledModels();
46589
+ if (!enabledModels?.length)
46590
+ return;
46591
+ const modelReference = `${model.provider}/${model.id}`;
46592
+ if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
46593
+ return;
46594
+ session.settingsManager.setEnabledModels([...enabledModels, modelReference]);
46595
+ }
46596
+ function thinkingPersistTarget(result) {
46597
+ if (!result.provider || !result.modelId)
46598
+ return;
46599
+ return { provider: result.provider, modelId: result.modelId };
46600
+ }
46601
+ function applyPersistedThinkingDefault(session, level, target) {
46602
+ if (target) {
46603
+ session.settingsManager.setModelThinkingLevel(target.provider, target.modelId, level);
46604
+ return;
46605
+ }
46606
+ session.settingsManager.setDefaultThinkingLevel(level);
46607
+ }
46563
46608
  var IsolatedInteractiveRuntime;
46564
46609
  var init_isolated_runtime = __esm(() => {
46565
46610
  init_agent_session_runtime();
@@ -46578,6 +46623,7 @@ var init_isolated_runtime = __esm(() => {
46578
46623
  steeringMessages = [];
46579
46624
  followUpMessages = [];
46580
46625
  queueUpdateGeneration = 0;
46626
+ thinkingEpoch = 0;
46581
46627
  pendingQueueClear;
46582
46628
  engineCallbackActive = false;
46583
46629
  queuePause;
@@ -46942,43 +46988,56 @@ var init_isolated_runtime = __esm(() => {
46942
46988
  },
46943
46989
  setModel: {
46944
46990
  configurable: true,
46945
- value: async (model) => {
46946
- const selected = await this.client.setModel(model.provider, model.id);
46947
- session.agent.state.model = session.modelRuntime.getModel(selected.provider, selected.id) ?? model;
46991
+ value: async (model, options) => {
46992
+ const selected = await this.client.setModel(model.provider, model.id, options);
46993
+ const nextModel = session.modelRuntime.getModel(selected.provider, selected.id) ?? model;
46994
+ session.agent.state.model = nextModel;
46948
46995
  this.resolveModelFallback();
46996
+ if (options?.persist === true)
46997
+ await this.syncPersistedModelCatalog(session, nextModel);
46949
46998
  }
46950
46999
  },
46951
47000
  setThinkingLevel: {
46952
47001
  configurable: true,
46953
- value: (level) => {
46954
- session.agent.state.thinkingLevel = level;
46955
- this.dispatchBestEffort("set thinking level", this.client.setThinkingLevel(level));
47002
+ value: (level, options) => {
47003
+ const availableLevels = session.getAvailableThinkingLevels();
47004
+ const effectiveLevel = availableLevels.includes(level) ? level : session.model ? clampThinkingLevel5(session.model, level) : "off";
47005
+ session.agent.state.thinkingLevel = effectiveLevel;
47006
+ const epoch = ++this.thinkingEpoch;
47007
+ this.dispatchBestEffort("set thinking level", this.client.setThinkingLevelAck(level, options).then((result) => {
47008
+ this.applyThinkingAck(session, epoch, result, options?.persist === true);
47009
+ }));
46956
47010
  }
46957
47011
  },
46958
47012
  cycleModel: {
46959
47013
  configurable: true,
46960
- value: async (direction) => {
47014
+ value: async (direction, options) => {
46961
47015
  const previousModel = session.model;
46962
- const result = await this.client.cycleModel(direction);
47016
+ const result = await this.client.cycleModel(direction, options);
46963
47017
  if (!result)
46964
47018
  return;
46965
47019
  const model = session.modelRuntime.getModel(result.model.provider, result.model.id) ?? result.model;
46966
47020
  session.agent.state.model = model;
46967
47021
  session.agent.state.thinkingLevel = result.thinkingLevel;
46968
47022
  this.resolveModelFallbackAfterExplicitModelSelection(previousModel, model);
47023
+ if (options?.persist === true)
47024
+ await this.syncPersistedModelCatalog(session, model);
46969
47025
  return { ...result, model };
46970
47026
  }
46971
47027
  },
46972
47028
  cycleThinkingLevel: {
46973
47029
  configurable: true,
46974
- value: () => {
47030
+ value: (options) => {
46975
47031
  const levels = session.getAvailableThinkingLevels();
46976
47032
  if (levels.length <= 1)
46977
47033
  return;
46978
47034
  const current = levels.indexOf(session.thinkingLevel);
46979
47035
  const level = levels[(current + 1) % levels.length];
46980
47036
  session.agent.state.thinkingLevel = level;
46981
- this.dispatchBestEffort("cycle thinking level", this.client.setThinkingLevel(level));
47037
+ const epoch = ++this.thinkingEpoch;
47038
+ this.dispatchBestEffort("cycle thinking level", this.client.setThinkingLevelAck(level, options).then((result) => {
47039
+ this.applyThinkingAck(session, epoch, result, options?.persist === true);
47040
+ }));
46982
47041
  return level;
46983
47042
  }
46984
47043
  },
@@ -47022,6 +47081,14 @@ var init_isolated_runtime = __esm(() => {
47022
47081
  this.engineCallbackActive = false;
47023
47082
  }
47024
47083
  }
47084
+ applyThinkingAck(session, epoch, result, persist) {
47085
+ if (persist) {
47086
+ applyPersistedThinkingDefault(session, result.level, thinkingPersistTarget(result));
47087
+ }
47088
+ if (epoch === this.thinkingEpoch) {
47089
+ session.agent.state.thinkingLevel = result.level;
47090
+ }
47091
+ }
47025
47092
  dispatchBestEffort(label, operation) {
47026
47093
  operation.catch((error) => {
47027
47094
  if (this.health.isRecovering())
@@ -47062,6 +47129,12 @@ var init_isolated_runtime = __esm(() => {
47062
47129
  }
47063
47130
  });
47064
47131
  }
47132
+ async syncPersistedModelCatalog(session, model) {
47133
+ const alreadyInScope = session.scopedModels.some((scoped) => scoped.model.provider === model.provider && scoped.model.id === model.id);
47134
+ const catalog = await this.client.requestInternal({ type: "get_available_models" });
47135
+ this.remoteModelCatalog.apply(catalog);
47136
+ applyPersistedModelDefault(session, model, alreadyInScope);
47137
+ }
47065
47138
  refreshSessionView() {
47066
47139
  const session = super.session;
47067
47140
  const sessionFile = session.sessionFile;
@@ -47101,6 +47174,7 @@ var init_isolated_runtime = __esm(() => {
47101
47174
  session.agent.state.model = event.model;
47102
47175
  break;
47103
47176
  case "thinking_level_changed":
47177
+ this.thinkingEpoch += 1;
47104
47178
  session.agent.state.thinkingLevel = event.level;
47105
47179
  break;
47106
47180
  case "session_info_changed":
@@ -48314,7 +48388,7 @@ var init_slash_commands = __esm(() => {
48314
48388
  { name: "tree", description: "Navigate session tree (switch branches)" },
48315
48389
  { name: "thinking", description: "Set thinking level", argumentHint: "<level>" },
48316
48390
  { name: "scoped-models", description: "Enable/disable models for ctrl+p cycling" },
48317
- { name: "fast", description: "Configure Codex fast mode for chat and workflows" },
48391
+ { name: "fast", description: "Configure OpenAI fast mode for chat and workflows in supported models" },
48318
48392
  { name: "export", description: "Export session (HTML default, or specify path: .html/.jsonl)" },
48319
48393
  { name: "import", description: "Import and resume a session from a JSONL file" },
48320
48394
  { name: "share", description: "Share session as a secret GitHub gist" },
@@ -49766,7 +49840,7 @@ var init_interactive_autocomplete = __esm(() => {
49766
49840
  return [...this.session.modelRuntime.getAvailableSnapshot()];
49767
49841
  };
49768
49842
  InteractiveModeBase.prototype.hasCodexFastModeSupportedModels = function() {
49769
- return hasSupportedCodexFastModeModel(this.getCodexFastModeCandidateModels());
49843
+ return hasSupportedCodexFastModeModel(this.getCodexFastModeCandidateModels(), this.session.modelRuntime.getCredentialSnapshot?.("github-copilot"));
49770
49844
  };
49771
49845
  InteractiveModeBase.prototype.buildRemoteSlashCommands = function(localCommands) {
49772
49846
  const remote = getInteractiveEngineRemoteCommands(this.runtimeHost);
@@ -50454,7 +50528,7 @@ var init_interactive_startup = __esm(() => {
50454
50528
  if (!model) {
50455
50529
  return modelLabel2;
50456
50530
  }
50457
- const fastModeEnabled = shouldApplyCodexFastMode(model, this.session.settingsManager.getCodexFastModeSettings(), this.session.orchestrationContext);
50531
+ const fastModeEnabled = shouldApplyCodexFastMode(model, this.session.settingsManager.getCodexFastModeSettings(), this.session.orchestrationContext, this.session.modelRuntime.getCredentialSnapshot?.("github-copilot"));
50458
50532
  return formatCodexFastModeModelLabel(modelLabel2, fastModeEnabled);
50459
50533
  };
50460
50534
  InteractiveModeBase.prototype.getStartupIdentityText = function(maxWidth, gap = 0, manifestoPhase = 4) {
@@ -54969,7 +55043,7 @@ var init_interactive_selectors = __esm(() => {
54969
55043
  });
54970
55044
 
54971
55045
  // src/modes/interactive/interactive-model-routing.ts
54972
- import { clampThinkingLevel as clampThinkingLevel5 } from "@bastani/pi-ai/compat";
55046
+ import { clampThinkingLevel as clampThinkingLevel6 } from "@bastani/pi-ai/compat";
54973
55047
  function resolveThinkingSelectorDefault(rawDefault, availableLevels, model) {
54974
55048
  if (rawDefault === undefined)
54975
55049
  return;
@@ -54977,7 +55051,7 @@ function resolveThinkingSelectorDefault(rawDefault, availableLevels, model) {
54977
55051
  return rawDefault;
54978
55052
  if (!model)
54979
55053
  return availableLevels.includes("off") ? "off" : availableLevels[0];
54980
- const clamped = clampThinkingLevel5(model, rawDefault);
55054
+ const clamped = clampThinkingLevel6(model, rawDefault);
54981
55055
  if (availableLevels.includes(clamped))
54982
55056
  return clamped;
54983
55057
  return availableLevels.includes("off") ? "off" : availableLevels[0];
@@ -57195,6 +57269,12 @@ function isAttachment(value) {
57195
57269
  return false;
57196
57270
  return attachment.language === undefined || typeof attachment.language === "string";
57197
57271
  }
57272
+ function isMessageSource(value) {
57273
+ if (typeof value !== "object" || value === null || Array.isArray(value))
57274
+ return false;
57275
+ const source = value;
57276
+ return typeof source.subagentRunId === "string" && (source.subagentAgent === undefined || typeof source.subagentAgent === "string") && (source.subagentIndex === undefined || typeof source.subagentIndex === "number");
57277
+ }
57198
57278
  function isMessage(value) {
57199
57279
  if (typeof value !== "object" || value === null)
57200
57280
  return false;
@@ -57207,6 +57287,8 @@ function isMessage(value) {
57207
57287
  return false;
57208
57288
  if (message.replyError !== undefined && typeof message.replyError !== "string")
57209
57289
  return false;
57290
+ if (message.source !== undefined && !isMessageSource(message.source))
57291
+ return false;
57210
57292
  if (typeof message.content !== "object" || message.content === null)
57211
57293
  return false;
57212
57294
  const content = message.content;
@@ -57240,6 +57322,7 @@ var init_client = __esm(() => {
57240
57322
  init_pending_send_registry();
57241
57323
  BROKER_SOCKET = getBrokerSocketPath();
57242
57324
  IntercomClient = class IntercomClient extends EventEmitter2 {
57325
+ returnAddress;
57243
57326
  socket = null;
57244
57327
  _sessionId = null;
57245
57328
  _supervisorSessionId = null;
@@ -57247,9 +57330,16 @@ var init_client = __esm(() => {
57247
57330
  pendingSends = new PendingSendRegistry;
57248
57331
  pendingLists = new Map;
57249
57332
  pendingPresence = new Map;
57333
+ pendingLiveWorkflowStageRoutes = new Map;
57250
57334
  pendingSupervisorAuthorizations = new Map;
57251
57335
  disconnecting = false;
57252
57336
  disconnectError = null;
57337
+ constructor(returnAddress = randomUUID8()) {
57338
+ super();
57339
+ if (returnAddress.length === 0)
57340
+ throw new Error("Intercom return address must not be empty");
57341
+ this.returnAddress = returnAddress;
57342
+ }
57253
57343
  failPending(error) {
57254
57344
  this.pendingSends.rejectAll(error);
57255
57345
  for (const pending of this.pendingLists.values())
@@ -57258,9 +57348,12 @@ var init_client = __esm(() => {
57258
57348
  pending.reject(error);
57259
57349
  for (const pending of this.pendingPresence.values())
57260
57350
  pending.reject(error);
57351
+ for (const pending of this.pendingLiveWorkflowStageRoutes.values())
57352
+ pending.reject(error);
57261
57353
  this.pendingLists.clear();
57262
57354
  this.pendingSupervisorAuthorizations.clear();
57263
57355
  this.pendingPresence.clear();
57356
+ this.pendingLiveWorkflowStageRoutes.clear();
57264
57357
  }
57265
57358
  get sessionId() {
57266
57359
  return this._sessionId;
@@ -57386,6 +57479,7 @@ var init_client = __esm(() => {
57386
57479
  writeMessage(socket, {
57387
57480
  type: "register",
57388
57481
  session,
57482
+ returnAddress: this.returnAddress,
57389
57483
  ...supervisor ? { supervisor } : {},
57390
57484
  ...supervisorOwnerToken ? { supervisorOwnerToken } : {}
57391
57485
  });
@@ -57460,6 +57554,58 @@ var init_client = __esm(() => {
57460
57554
  this.emit("message", from, message, channel);
57461
57555
  break;
57462
57556
  }
57557
+ case "pending_stage_message": {
57558
+ const { requestId, from, senderRegistrationName, senderReturnAddress, runId, stageKey, message, live } = brokerMessage;
57559
+ if (typeof requestId !== "string" || !isSessionInfo(from) || senderRegistrationName !== undefined && typeof senderRegistrationName !== "string" || senderReturnAddress !== undefined && typeof senderReturnAddress !== "string" || typeof runId !== "string" || typeof stageKey !== "string" || !isMessage(message) || live !== undefined && typeof live !== "boolean") {
57560
+ throw new Error("Invalid pending-stage message event");
57561
+ }
57562
+ this.emit("pending_stage_message", {
57563
+ requestId,
57564
+ from,
57565
+ ...senderRegistrationName === undefined ? {} : { senderRegistrationName },
57566
+ ...senderReturnAddress === undefined ? {} : { senderReturnAddress },
57567
+ runId,
57568
+ stageKey,
57569
+ message,
57570
+ ...live === true ? { live: true } : {}
57571
+ });
57572
+ break;
57573
+ }
57574
+ case "pending_stage_notification": {
57575
+ const { requestId, from, message } = brokerMessage;
57576
+ if (typeof requestId !== "string" || !isSessionInfo(from) || !isMessage(message)) {
57577
+ throw new Error("Invalid pending-stage notification event");
57578
+ }
57579
+ this.emit("pending_stage_notification", {
57580
+ requestId,
57581
+ from,
57582
+ message
57583
+ });
57584
+ break;
57585
+ }
57586
+ case "live_workflow_stage_route_registered": {
57587
+ const { requestId } = brokerMessage;
57588
+ if (typeof requestId !== "string")
57589
+ throw new Error("Invalid live workflow-stage route registration");
57590
+ const pending = this.pendingLiveWorkflowStageRoutes.get(requestId);
57591
+ if (!pending)
57592
+ return;
57593
+ this.pendingLiveWorkflowStageRoutes.delete(requestId);
57594
+ pending.resolve();
57595
+ break;
57596
+ }
57597
+ case "queued": {
57598
+ const { messageId, attemptId, runId, stageKey, position } = brokerMessage;
57599
+ if (typeof messageId !== "string" || attemptId !== undefined && typeof attemptId !== "string" || typeof runId !== "string" || typeof stageKey !== "string" || typeof position !== "number" || position < 1) {
57600
+ throw new Error("Invalid queued message");
57601
+ }
57602
+ const result = { id: messageId, delivered: false, queued: true, runId, stageKey, position };
57603
+ if (attemptId === undefined)
57604
+ this.pendingSends.resolveLegacy(messageId, result);
57605
+ else
57606
+ this.pendingSends.resolve(messageId, attemptId, result);
57607
+ break;
57608
+ }
57463
57609
  case "delivered": {
57464
57610
  const { messageId, attemptId } = brokerMessage;
57465
57611
  if (typeof messageId !== "string" || attemptId !== undefined && typeof attemptId !== "string") {
@@ -57473,11 +57619,16 @@ var init_client = __esm(() => {
57473
57619
  break;
57474
57620
  }
57475
57621
  case "delivery_failed": {
57476
- const { messageId, attemptId, reason } = brokerMessage;
57477
- if (typeof messageId !== "string" || attemptId !== undefined && typeof attemptId !== "string" || typeof reason !== "string") {
57622
+ const { messageId, attemptId, reason, reasonCode } = brokerMessage;
57623
+ if (typeof messageId !== "string" || attemptId !== undefined && typeof attemptId !== "string" || typeof reason !== "string" || reasonCode !== undefined && reasonCode !== "message_id_conflict") {
57478
57624
  throw new Error("Invalid delivery_failed message");
57479
57625
  }
57480
- const result = { id: messageId, delivered: false, reason };
57626
+ const result = {
57627
+ id: messageId,
57628
+ delivered: false,
57629
+ reason,
57630
+ ...reasonCode === undefined ? {} : { reasonCode }
57631
+ };
57481
57632
  if (attemptId === undefined)
57482
57633
  this.pendingSends.resolveLegacy(messageId, result);
57483
57634
  else
@@ -57656,13 +57807,61 @@ var init_client = __esm(() => {
57656
57807
  }
57657
57808
  });
57658
57809
  }
57810
+ registerPendingStageRoute(runId, group, capability) {
57811
+ writeMessage(this.requireActiveSocket(), { type: "register_pending_stage_route", runId, group, capability });
57812
+ }
57813
+ registerLiveWorkflowStageRoute(runId, stageKeys, capability) {
57814
+ let socket;
57815
+ try {
57816
+ socket = this.requireActiveSocket();
57817
+ } catch (error) {
57818
+ return Promise.reject(toError(error));
57819
+ }
57820
+ const requestId = randomUUID8();
57821
+ return new Promise((resolve15, reject) => {
57822
+ this.pendingLiveWorkflowStageRoutes.set(requestId, { resolve: resolve15, reject });
57823
+ try {
57824
+ writeMessage(socket, {
57825
+ type: "register_live_workflow_stage_route",
57826
+ requestId,
57827
+ runId,
57828
+ stageKeys: [...stageKeys],
57829
+ capability
57830
+ });
57831
+ } catch (error) {
57832
+ this.pendingLiveWorkflowStageRoutes.delete(requestId);
57833
+ reject(toError(error));
57834
+ }
57835
+ });
57836
+ }
57837
+ respondPendingStageMessage(requestId, result) {
57838
+ const socket = this.requireActiveSocket();
57839
+ writeMessage(socket, result.outcome === "queued" ? { type: "pending_stage_message_result", requestId, outcome: "queued", position: result.position } : result.outcome === "refused" ? {
57840
+ type: "pending_stage_message_result",
57841
+ requestId,
57842
+ outcome: "refused",
57843
+ reason: result.reason,
57844
+ ...result.reasonCode === undefined ? {} : { reasonCode: result.reasonCode }
57845
+ } : { type: "pending_stage_message_result", requestId, outcome: result.outcome });
57846
+ }
57847
+ respondPendingStageNotification(requestId, delivered) {
57848
+ writeMessage(this.requireActiveSocket(), { type: "pending_stage_notification_result", requestId, delivered });
57849
+ }
57659
57850
  send(to, options) {
57660
57851
  return this.sendFrame("send", to, options);
57661
57852
  }
57853
+ sendPendingStageNotification(runId, capability, to, senderRegistrationName, options, senderReturnAddress) {
57854
+ return this.sendFrame("send_pending_stage_notification", to, options, {
57855
+ runId,
57856
+ capability,
57857
+ ...senderRegistrationName === undefined ? {} : { senderRegistrationName },
57858
+ ...senderReturnAddress === undefined ? {} : { senderReturnAddress }
57859
+ });
57860
+ }
57662
57861
  sendToSupervisor(to, options) {
57663
57862
  return this.sendFrame("supervisor_send", to, options);
57664
57863
  }
57665
- sendFrame(type, to, options) {
57864
+ sendFrame(type, to, options, extra = undefined) {
57666
57865
  let socket;
57667
57866
  try {
57668
57867
  socket = this.requireActiveSocket();
@@ -57688,7 +57887,7 @@ var init_client = __esm(() => {
57688
57887
  content: { text: options.text, attachments: options.attachments }
57689
57888
  };
57690
57889
  try {
57691
- writeMessage(socket, { type, to, message, attemptId: acquired.attempt.attemptId });
57890
+ writeMessage(socket, { type, to, message, attemptId: acquired.attempt.attemptId, ...extra });
57692
57891
  } catch (error) {
57693
57892
  this.pendingSends.reject(acquired.attempt, toError(error));
57694
57893
  }
@@ -59216,6 +59415,10 @@ Use this to communicate findings, request help, or coordinate work with other se
59216
59415
  Sessions belong to an intercom group and can ONLY message sessions in the same group;
59217
59416
  cross-group sends are rejected by the broker. Ungrouped sessions share the "default" group.
59218
59417
 
59418
+ For send, live session names and exact full session IDs remain supported. For a known
59419
+ workflow stage, use the exact \`<runId>:<stageKey>\` target; send messages to pending stages
59420
+ queue automatically.
59421
+
59219
59422
  Usage:
59220
59423
  intercom({ action: "list" }) → List sessions in your group
59221
59424
  intercom({ action: "list", group: "name" }) → Read-only peek at another group's sessions
@@ -59236,7 +59439,7 @@ does not grant cross-group access: contact_supervisor is the only cross-group pa
59236
59439
  description: "Action: 'list', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'"
59237
59440
  }),
59238
59441
  to: Type14.Optional(Type14.String({
59239
- description: "Exact session name or exact full session ID (for 'send', 'ask', or targeted 'reply')"
59442
+ description: "Live session name, exact full session ID, or exact `<runId>:<stageKey>` for a known workflow stage; send messages to pending stages queue automatically (for 'send', 'ask', or targeted 'reply')"
59240
59443
  })),
59241
59444
  message: Type14.Optional(Type14.String({
59242
59445
  description: "Message to send (for 'send', 'ask', or 'reply' action)"
@@ -59435,6 +59638,26 @@ ${message}${attachmentText}`);
59435
59638
  attachments,
59436
59639
  replyTo
59437
59640
  });
59641
+ if (result.queued === true) {
59642
+ pi.appendEntry("intercom_sent", {
59643
+ to,
59644
+ message: { text: message, attachments, replyTo },
59645
+ messageId: result.id,
59646
+ timestamp: Date.now()
59647
+ });
59648
+ return {
59649
+ content: [{ type: "text", text: `Message queued for ${to}` }],
59650
+ isError: false,
59651
+ details: {
59652
+ messageId: result.id,
59653
+ delivered: false,
59654
+ queued: true,
59655
+ runId: result.runId,
59656
+ stageKey: result.stageKey,
59657
+ position: result.position
59658
+ }
59659
+ };
59660
+ }
59438
59661
  if (!result.delivered) {
59439
59662
  const errorText = result.reason ?? "Session may not exist or has disconnected.";
59440
59663
  return {
@@ -59553,10 +59776,16 @@ ${message}${attachmentText}`);
59553
59776
  if (!sendResult.delivered) {
59554
59777
  const errorText = sendResult.reason ?? "Session may not exist or has disconnected.";
59555
59778
  wait.cancel(new Error(`Message to "${to}" was not delivered: ${errorText}`));
59779
+ const pendingStageAskRefusal = errorText.startsWith("Cannot ask a workflow stage whose session has not initialized.");
59556
59780
  return {
59557
59781
  content: [{ type: "text", text: `Message to "${to}" was not delivered: ${errorText}` }],
59558
59782
  isError: true,
59559
- details: { error: true }
59783
+ details: pendingStageAskRefusal ? {
59784
+ error: true,
59785
+ refusal: "pending_stage_ask_unsupported",
59786
+ recommendedAction: "send",
59787
+ reason: errorText
59788
+ } : { error: true }
59560
59789
  };
59561
59790
  }
59562
59791
  pi.appendEntry("intercom_sent", {
@@ -60127,6 +60356,13 @@ function registerIntercomLifecycle(pi, deps) {
60127
60356
  console.error(`Intercom failed to disconnect during ${reason.toLowerCase()}; continuing cleanup:`, error);
60128
60357
  }
60129
60358
  }
60359
+ if (deps.disconnectAuxiliaryClients) {
60360
+ try {
60361
+ await deps.disconnectAuxiliaryClients();
60362
+ } catch (error) {
60363
+ console.error(`Intercom failed to disconnect auxiliary clients during ${reason.toLowerCase()}; continuing cleanup:`, error);
60364
+ }
60365
+ }
60130
60366
  deps.restoreIntercomSessionIdEnv?.();
60131
60367
  deps.setRuntimeContext(null);
60132
60368
  deps.setCurrentSessionId(null);
@@ -60921,12 +61157,27 @@ function createIncomingMessageSender(input2) {
60921
61157
  }
60922
61158
  const baseOptions = {
60923
61159
  stageAdmissionKey: `intercom:${entry.message.id}`,
61160
+ persistWhenStreaming: true,
60924
61161
  ...stageAdmissionBarrier ? { stageAdmissionBarrier } : {}
60925
61162
  };
60926
61163
  const options = delivery === "trigger" ? { ...baseOptions, triggerTurn: true } : delivery === "followUp" ? { ...baseOptions, deliverAs: "followUp" } : baseOptions;
60927
61164
  return Promise.resolve(input2.pi.sendMessage(buildIncomingCustomMessage(entry), options));
60928
61165
  };
60929
61166
  }
61167
+ function framePendingStageTimestamp(timestamp) {
61168
+ const date = new Date(timestamp);
61169
+ return Number.isNaN(date.getTime()) ? String(timestamp) : date.toISOString();
61170
+ }
61171
+ function framePreStartPendingStageMessage(entry) {
61172
+ return {
61173
+ ...entry,
61174
+ bodyText: `**Messages received before you started**
61175
+
61176
+ Sent: ${framePendingStageTimestamp(entry.message.timestamp)}
61177
+
61178
+ ${entry.bodyText}`
61179
+ };
61180
+ }
60930
61181
  function buildIncomingCustomMessage(entry) {
60931
61182
  const senderDisplay = entry.from.name || entry.from.id;
60932
61183
  const replyInstruction = entry.replyCommand ? `
@@ -61016,7 +61267,28 @@ class InboundIdleQueue {
61016
61267
  class InboundMessageAdmission {
61017
61268
  delivered = new DeliveredMessageCache;
61018
61269
  pending = new Map;
61270
+ persistentlyDelivered = new Set;
61271
+ restore(entries) {
61272
+ this.persistentlyDelivered.clear();
61273
+ for (const value of entries) {
61274
+ if (typeof value !== "object" || value === null)
61275
+ continue;
61276
+ const entry = value;
61277
+ if (entry.customType !== "intercom_message" || typeof entry.stageAdmissionKey !== "string")
61278
+ continue;
61279
+ if (typeof entry.details !== "object" || entry.details === null)
61280
+ continue;
61281
+ const details = entry.details;
61282
+ if (!isSessionInfo(details.from) || !isMessage(details.message))
61283
+ continue;
61284
+ if (entry.stageAdmissionKey !== `intercom:${details.message.id}`)
61285
+ continue;
61286
+ this.persistentlyDelivered.add(details.message.id);
61287
+ }
61288
+ }
61019
61289
  admit(from, message) {
61290
+ if (this.persistentlyDelivered.has(message.id))
61291
+ return { kind: "duplicate" };
61020
61292
  const signature = JSON.stringify({ from: from.id, message });
61021
61293
  if (this.delivered.lookup(message.id, signature) !== "miss")
61022
61294
  return { kind: "duplicate" };
@@ -61052,6 +61324,7 @@ class InboundMessageAdmission {
61052
61324
  return;
61053
61325
  this.pending.delete(reservation.messageId);
61054
61326
  this.delivered.record(reservation.messageId, reservation.signature);
61327
+ this.persistentlyDelivered.add(reservation.messageId);
61055
61328
  pending.resolve();
61056
61329
  }
61057
61330
  release(reservation, error = new Error("Inbound message admission released")) {
@@ -61391,6 +61664,18 @@ __export(exports_index_heavy, {
61391
61664
  default: () => piIntercomExtension
61392
61665
  });
61393
61666
  import { appendFileSync as appendFileSync2 } from "node:fs";
61667
+ function isPendingStageUndeliverableEvent(value) {
61668
+ if (typeof value !== "object" || value === null)
61669
+ return false;
61670
+ const event = value;
61671
+ return typeof event.runId === "string" && typeof event.handled === "boolean" && typeof event.senderId === "string" && (event.senderRegistrationName === undefined || typeof event.senderRegistrationName === "string") && (event.senderReturnAddress === undefined || typeof event.senderReturnAddress === "string") && typeof event.messageId === "string" && typeof event.notificationId === "string" && typeof event.reason === "string";
61672
+ }
61673
+ function isPendingStageRouteRegistrationEvent(value) {
61674
+ if (typeof value !== "object" || value === null)
61675
+ return false;
61676
+ const event = value;
61677
+ return typeof event.runId === "string" && event.runId.length > 0 && typeof event.group === "string" && typeof event.capability === "string" && event.capability.length > 0;
61678
+ }
61394
61679
  function piIntercomExtension(pi, testOverrides = {}) {
61395
61680
  const inheritedIntercomSessionId = process.env[INTERCOM_SESSION_ID_ENV];
61396
61681
  const restoreIntercomSessionIdEnv = () => {
@@ -61400,6 +61685,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
61400
61685
  process.env[INTERCOM_SESSION_ID_ENV] = inheritedIntercomSessionId;
61401
61686
  };
61402
61687
  let client = null;
61688
+ let clientRegistrationGroup = null;
61403
61689
  const config = loadConfig2();
61404
61690
  const legacyChildOrchestratorMetadata = readChildOrchestratorMetadata();
61405
61691
  let runtimeContext = null;
@@ -61426,6 +61712,8 @@ function piIntercomExtension(pi, testOverrides = {}) {
61426
61712
  const foregroundDetachHandoff = new ForegroundDetachHandoff(pi);
61427
61713
  const pendingIdleMessages = new InboundIdleQueue;
61428
61714
  const inboundDeliveries = new InboundMessageAdmission;
61715
+ const pendingStageRoutes = new Map;
61716
+ const pendingStageRouteClients = new Map;
61429
61717
  const supervisorAuthorizations = new SupervisorAuthorizationRegistry;
61430
61718
  let inboundFlushTimer = null;
61431
61719
  function rejectReplyWaiter(error) {
@@ -61591,7 +61879,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
61591
61879
  }).catch(() => {});
61592
61880
  }
61593
61881
  testOverrides.captureInboundHandler?.(handleIncomingMessage);
61594
- function handleIncomingMessage(ctx, from, message, channel) {
61882
+ function handleIncomingMessage(ctx, from, message, channel, receivedBeforeStageStart = false) {
61595
61883
  const messageGeneration = runtimeGeneration;
61596
61884
  const liveContext = getLiveContext(ctx, messageGeneration);
61597
61885
  if (!liveContext) {
@@ -61601,7 +61889,11 @@ function piIntercomExtension(pi, testOverrides = {}) {
61601
61889
  const attachmentText = message.content.attachments?.length ? formatAttachments(message.content.attachments) : "";
61602
61890
  const bodyText = `${message.content.text}${attachmentText}`;
61603
61891
  const replyCommand = config.replyHint && message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
61604
- const entry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
61892
+ const rawEntry = { from, message, replyCommand, bodyText, ...channel ? { channel } : {} };
61893
+ const entry = receivedBeforeStageStart ? framePreStartPendingStageMessage(rawEntry) : rawEntry;
61894
+ if (receivedBeforeStageStart) {
61895
+ return sendIncomingMessage(entry, "prelude", messageGeneration, false);
61896
+ }
61605
61897
  const stageClosed = liveContext.orchestrationContext?.kind === "workflow-stage" && liveContext.orchestrationContext.messageAdmission?.isOpen() === false;
61606
61898
  if (stageClosed) {
61607
61899
  routeClosedWorkflowStageMessage(entry, inboundDeliveries, replyTracker, replyWaiters.pending(), () => sendIncomingMessage(entry, "trigger", messageGeneration, false), () => client, () => Boolean(getLiveContext(liveContext, messageGeneration)));
@@ -61639,7 +61931,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
61639
61931
  stageDelivery.then(commit, release);
61640
61932
  return;
61641
61933
  }
61642
- (async () => {
61934
+ return (async () => {
61643
61935
  try {
61644
61936
  const activeContext = getLiveContext(liveContext, messageGeneration);
61645
61937
  if (!activeContext) {
@@ -61695,6 +61987,110 @@ function piIntercomExtension(pi, testOverrides = {}) {
61695
61987
  }
61696
61988
  })();
61697
61989
  }
61990
+ function handlePendingStageMessage(nextClient, request, isCurrent) {
61991
+ if (!isCurrent())
61992
+ return;
61993
+ const event = { ...request, handled: false };
61994
+ try {
61995
+ pi.events.emit(PENDING_STAGE_MESSAGE_EVENT, event);
61996
+ } catch (error) {
61997
+ nextClient.respondPendingStageMessage(request.requestId, { outcome: "refused", reason: toError3(error).message });
61998
+ return;
61999
+ }
62000
+ if (!event.handled || event.completion === undefined) {
62001
+ nextClient.respondPendingStageMessage(request.requestId, {
62002
+ outcome: "refused",
62003
+ reason: "Session not found"
62004
+ });
62005
+ return;
62006
+ }
62007
+ event.completion.then((result) => nextClient.respondPendingStageMessage(request.requestId, result), (error) => nextClient.respondPendingStageMessage(request.requestId, {
62008
+ outcome: "refused",
62009
+ reason: toError3(error).message
62010
+ }));
62011
+ }
62012
+ async function admitPendingStageNotification(nextClient, request) {
62013
+ const messageGeneration = runtimeGeneration;
62014
+ const liveContext = client === nextClient ? getLiveContext() : null;
62015
+ if (liveContext === null)
62016
+ return false;
62017
+ const attachmentText = request.message.content.attachments?.length ? formatAttachments(request.message.content.attachments) : "";
62018
+ const bodyText = `${request.message.content.text}${attachmentText}`;
62019
+ const replyCommand = config.replyHint && request.message.expectsReply ? `intercom({ action: "reply", message: "..." })` : undefined;
62020
+ const entry = { from: request.from, message: request.message, replyCommand, bodyText };
62021
+ const admission = inboundDeliveries.admit(request.from, request.message);
62022
+ if (admission.kind === "duplicate")
62023
+ return true;
62024
+ if (admission.kind === "pending") {
62025
+ return admission.completion.then(() => true, () => false);
62026
+ }
62027
+ const reservation = admission.reservation;
62028
+ const commit = () => {
62029
+ inboundDeliveries.commit(reservation);
62030
+ };
62031
+ replyTracker = bindWorkflowReplyTracker(liveContext, replyTracker);
62032
+ if (routeIncomingReply(replyWaiters.pending(), request.from, request.message)) {
62033
+ commit();
62034
+ return true;
62035
+ }
62036
+ const replyContext = replyTracker.recordIncomingMessage(request.from, request.message);
62037
+ const release = createWorkflowStageDeliveryFailureHandler({
62038
+ entry,
62039
+ admission: inboundDeliveries,
62040
+ reservation,
62041
+ tracker: replyTracker,
62042
+ replyContext,
62043
+ currentClient: () => client,
62044
+ commit
62045
+ });
62046
+ const reject = async (error) => {
62047
+ await release(error);
62048
+ return false;
62049
+ };
62050
+ const stageClosed = liveContext.orchestrationContext?.kind === "workflow-stage" && liveContext.orchestrationContext.messageAdmission?.isOpen() === false;
62051
+ if (stageClosed)
62052
+ return reject(new Error("Workflow stage is closed before notification admission"));
62053
+ const stageDelivery = admitWorkflowStageInbound(liveContext, (admissionBarrier) => {
62054
+ replyTracker.queueTurnContext(replyContext);
62055
+ return retryStableDelivery({
62056
+ deliver: () => sendIncomingMessage(entry, "trigger", messageGeneration, false, undefined, admissionBarrier),
62057
+ isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
62058
+ });
62059
+ }, () => foregroundDetachHandoff.claim(request.from, request.message, messageGeneration, () => Boolean(getLiveContext(liveContext, messageGeneration))), release);
62060
+ if (stageDelivery !== false) {
62061
+ try {
62062
+ await stageDelivery;
62063
+ commit();
62064
+ return true;
62065
+ } catch (error) {
62066
+ return reject(error);
62067
+ }
62068
+ }
62069
+ try {
62070
+ const activeContext = getLiveContext(liveContext, messageGeneration);
62071
+ if (activeContext === null || !activeContext.isIdle()) {
62072
+ return reject(new Error("Intercom session is not ready for acknowledged notification delivery"));
62073
+ }
62074
+ replyTracker.queueTurnContext(replyContext);
62075
+ await retryStableDelivery({
62076
+ deliver: () => sendIncomingMessage(entry, "trigger", messageGeneration, false),
62077
+ isCurrent: () => Boolean(getLiveContext(liveContext, messageGeneration))
62078
+ });
62079
+ commit();
62080
+ return true;
62081
+ } catch (error) {
62082
+ return reject(error);
62083
+ }
62084
+ }
62085
+ function handlePendingStageNotification(nextClient, request) {
62086
+ admitPendingStageNotification(nextClient, request).catch(() => false).then((delivered) => {
62087
+ if (client !== nextClient || !nextClient.isConnected())
62088
+ return;
62089
+ try {
62090
+ nextClient.respondPendingStageNotification(request.requestId, delivered);
62091
+ } catch {}
62092
+ });
62093
+ }
61698
62094
  function attachClientHandlers(nextClient) {
61699
62095
  nextClient.on("message", (from, message, channel) => {
61700
62096
  const liveContext = getLiveContext();
@@ -61703,6 +62099,12 @@ function piIntercomExtension(pi, testOverrides = {}) {
61703
62099
  }
61704
62100
  handleIncomingMessage(liveContext, from, message, channel);
61705
62101
  });
62102
+ nextClient.on("pending_stage_message", (request) => {
62103
+ handlePendingStageMessage(nextClient, request, () => client === nextClient);
62104
+ });
62105
+ nextClient.on("pending_stage_notification", (request) => {
62106
+ handlePendingStageNotification(nextClient, request);
62107
+ });
61706
62108
  nextClient.on("peer_disconnected", (notice) => {
61707
62109
  if (client !== nextClient) {
61708
62110
  return;
@@ -61715,6 +62117,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
61715
62117
  }
61716
62118
  rejectReplyWaiter(new Error(`Disconnected while waiting for reply: ${error.message}`, { cause: error }));
61717
62119
  client = null;
62120
+ clientRegistrationGroup = null;
61718
62121
  if (process.env[INTERCOM_SESSION_ID_ENV] === nextClient.sessionId)
61719
62122
  restoreIntercomSessionIdEnv();
61720
62123
  if (!shuttingDown && !disposed) {
@@ -61738,6 +62141,132 @@ function piIntercomExtension(pi, testOverrides = {}) {
61738
62141
  ensureConnected("background").catch(() => {});
61739
62142
  }, reconnectDelayMs(reconnectAttempt));
61740
62143
  }
62144
+ function samePendingStageRoute(left, right) {
62145
+ return left !== undefined && normalizeGroup(left.group) === normalizeGroup(right.group) && left.capability === right.capability;
62146
+ }
62147
+ function pendingStageRouteClientIsCurrent(runId, state, context = runtimeContext, generation = runtimeGeneration) {
62148
+ return pendingStageRouteClients.get(runId) === state && samePendingStageRoute(pendingStageRoutes.get(runId), state.route) && Boolean(getLiveContext(context, generation));
62149
+ }
62150
+ function schedulePendingStageRouteReconnect(runId, state) {
62151
+ if (state.reconnectTimer || state.promise || !pendingStageRouteClientIsCurrent(runId, state))
62152
+ return;
62153
+ const scheduledGeneration = runtimeGeneration;
62154
+ state.reconnectTimer = setTimeout(() => {
62155
+ state.reconnectTimer = null;
62156
+ if (!pendingStageRouteClientIsCurrent(runId, state, runtimeContext, scheduledGeneration))
62157
+ return;
62158
+ state.reconnectAttempt += 1;
62159
+ ensurePendingStageRouteClient(runId, state.route).catch(() => {});
62160
+ }, reconnectDelayMs(state.reconnectAttempt));
62161
+ }
62162
+ function attachPendingStageRouteClientHandlers(runId, state, nextClient) {
62163
+ nextClient.on("pending_stage_message", (request) => {
62164
+ handlePendingStageMessage(nextClient, request, () => state.client === nextClient && pendingStageRouteClientIsCurrent(runId, state));
62165
+ });
62166
+ nextClient.on("disconnected", () => {
62167
+ if (state.client !== nextClient)
62168
+ return;
62169
+ state.client = null;
62170
+ schedulePendingStageRouteReconnect(runId, state);
62171
+ });
62172
+ nextClient.on("error", () => {});
62173
+ }
62174
+ async function ensurePendingStageRouteClient(runId, route) {
62175
+ const contextAtStart = getLiveContext();
62176
+ const generationAtStart = runtimeGeneration;
62177
+ if (!contextAtStart)
62178
+ throw new Error("Intercom runtime not initialized");
62179
+ let existing = pendingStageRouteClients.get(runId);
62180
+ if (existing && !samePendingStageRoute(existing.route, route)) {
62181
+ pendingStageRouteClients.delete(runId);
62182
+ if (existing.reconnectTimer)
62183
+ clearTimeout(existing.reconnectTimer);
62184
+ try {
62185
+ await existing.promise;
62186
+ } catch {}
62187
+ if (existing.client) {
62188
+ try {
62189
+ await existing.client.disconnect();
62190
+ } catch {}
62191
+ }
62192
+ existing = undefined;
62193
+ }
62194
+ const state = existing ?? {
62195
+ route,
62196
+ client: null,
62197
+ promise: null,
62198
+ reconnectTimer: null,
62199
+ reconnectAttempt: 0
62200
+ };
62201
+ if (!existing)
62202
+ pendingStageRouteClients.set(runId, state);
62203
+ if (state.client?.isConnected())
62204
+ return;
62205
+ if (state.promise)
62206
+ return state.promise;
62207
+ const promise = (async () => {
62208
+ await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
62209
+ const nextClient = new IntercomClient(`${currentSessionId}:pending-stage-route:${runId}`);
62210
+ state.client = nextClient;
62211
+ attachPendingStageRouteClientHandlers(runId, state, nextClient);
62212
+ await nextClient.connect({ ...buildRegistration(), name: undefined, group: normalizeGroup(route.group) }, undefined, undefined, readSubagentMessageSource(runtimeContext?.subagentPolicy));
62213
+ if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
62214
+ await nextClient.disconnect();
62215
+ throw new Error("Intercom runtime no longer active");
62216
+ }
62217
+ nextClient.registerPendingStageRoute(runId, normalizeGroup(route.group), route.capability);
62218
+ await nextClient.listSessions();
62219
+ if (!pendingStageRouteClientIsCurrent(runId, state, contextAtStart, generationAtStart)) {
62220
+ await nextClient.disconnect();
62221
+ throw new Error("Intercom runtime no longer active");
62222
+ }
62223
+ state.reconnectAttempt = 0;
62224
+ })();
62225
+ state.promise = promise;
62226
+ try {
62227
+ await promise;
62228
+ } catch (error) {
62229
+ const failedClient = state.client;
62230
+ state.client = null;
62231
+ if (failedClient) {
62232
+ try {
62233
+ await failedClient.disconnect();
62234
+ } catch {}
62235
+ }
62236
+ if (state.promise === promise)
62237
+ state.promise = null;
62238
+ schedulePendingStageRouteReconnect(runId, state);
62239
+ throw toError3(error);
62240
+ } finally {
62241
+ if (state.promise === promise)
62242
+ state.promise = null;
62243
+ }
62244
+ }
62245
+ async function disconnectPendingStageRouteClients() {
62246
+ const states = [...pendingStageRouteClients.values()];
62247
+ pendingStageRouteClients.clear();
62248
+ for (const state of states) {
62249
+ if (state.reconnectTimer)
62250
+ clearTimeout(state.reconnectTimer);
62251
+ try {
62252
+ await state.promise;
62253
+ } catch {}
62254
+ if (!state.client)
62255
+ continue;
62256
+ try {
62257
+ await state.client.disconnect();
62258
+ } catch {}
62259
+ state.client = null;
62260
+ }
62261
+ }
62262
+ async function registerPendingStageRoute(activeClient, runId, route) {
62263
+ const routeGroup = normalizeGroup(route.group);
62264
+ if (clientRegistrationGroup === routeGroup) {
62265
+ activeClient.registerPendingStageRoute(runId, routeGroup, route.capability);
62266
+ return;
62267
+ }
62268
+ await ensurePendingStageRouteClient(runId, { ...route, group: routeGroup });
62269
+ }
61741
62270
  async function ensureConnected(reason) {
61742
62271
  if (!config.enabled) {
61743
62272
  throw new Error("Intercom disabled");
@@ -61758,14 +62287,23 @@ function piIntercomExtension(pi, testOverrides = {}) {
61758
62287
  return reconnectPromise;
61759
62288
  }
61760
62289
  const nextReconnectPromise = (async () => {
61761
- const nextClient = new IntercomClient;
62290
+ const nextClient = new IntercomClient(currentSessionId);
62291
+ const registration = buildRegistration();
61762
62292
  client = nextClient;
61763
62293
  attachClientHandlers(nextClient);
61764
62294
  try {
61765
62295
  await spawnBrokerIfNeeded(config.brokerCommand, config.brokerArgs);
61766
62296
  const childMetadata = currentChildOrchestratorMetadata();
61767
- await nextClient.connect(buildRegistration(), childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy));
62297
+ await nextClient.connect(registration, childMetadata?.supervisor, supervisorAuthorizations.ownerToken, readSubagentMessageSource(runtimeContext?.subagentPolicy));
62298
+ clientRegistrationGroup = normalizeGroup(registration.group);
61768
62299
  await supervisorAuthorizations.restore(nextClient);
62300
+ for (const [runId, route] of pendingStageRoutes) {
62301
+ await registerPendingStageRoute(nextClient, runId, route);
62302
+ }
62303
+ const orchestration = contextAtStart.orchestrationContext;
62304
+ if (orchestration?.kind === "workflow-stage" && orchestration.pendingStageDelivery !== undefined) {
62305
+ await nextClient.registerLiveWorkflowStageRoute(orchestration.workflowRunId, [orchestration.workflowStageId, orchestration.workflowStageName], orchestration.pendingStageDelivery.routeCapability);
62306
+ }
61769
62307
  if (!getLiveContext(contextAtStart, generationAtStart)) {
61770
62308
  await nextClient.disconnect();
61771
62309
  throw new Error("Intercom runtime no longer active");
@@ -61779,6 +62317,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
61779
62317
  } catch (error) {
61780
62318
  if (client === nextClient) {
61781
62319
  client = null;
62320
+ clientRegistrationGroup = null;
61782
62321
  }
61783
62322
  if (reason === "background" && getLiveContext(contextAtStart, generationAtStart)) {
61784
62323
  scheduleReconnect();
@@ -61795,6 +62334,43 @@ function piIntercomExtension(pi, testOverrides = {}) {
61795
62334
  reconnectPromiseGeneration = generationAtStart;
61796
62335
  return nextReconnectPromise;
61797
62336
  }
62337
+ pi.events.on(PENDING_STAGE_ROUTE_EVENT, (payload) => {
62338
+ if (!isPendingStageRouteRegistrationEvent(payload))
62339
+ return;
62340
+ pendingStageRoutes.set(payload.runId, { group: payload.group, capability: payload.capability });
62341
+ const completion = ensureConnected("background").then((activeClient) => registerPendingStageRoute(activeClient, payload.runId, payload));
62342
+ payload.completion = completion;
62343
+ completion.catch(() => {});
62344
+ });
62345
+ async function pendingStageNotificationClient(runId) {
62346
+ const route = pendingStageRoutes.get(runId);
62347
+ if (route === undefined)
62348
+ throw new Error("Pending workflow route is unavailable");
62349
+ if (client?.isConnected() && clientRegistrationGroup === normalizeGroup(route.group))
62350
+ return client;
62351
+ await ensurePendingStageRouteClient(runId, route);
62352
+ const routeClient = pendingStageRouteClients.get(runId)?.client;
62353
+ if (!routeClient?.isConnected())
62354
+ throw new Error("Pending workflow route is disconnected");
62355
+ return routeClient;
62356
+ }
62357
+ pi.events.on(PENDING_STAGE_UNDELIVERABLE_EVENT, (payload) => {
62358
+ if (!isPendingStageUndeliverableEvent(payload) || payload.handled)
62359
+ return;
62360
+ payload.handled = true;
62361
+ const actionable = `Pending workflow stage could not receive intercom message: ${payload.reason}`;
62362
+ payload.completion = pendingStageNotificationClient(payload.runId).then((activeClient) => {
62363
+ const route = pendingStageRoutes.get(payload.runId);
62364
+ if (route === undefined)
62365
+ throw new Error("Pending workflow route is unavailable");
62366
+ return activeClient.sendPendingStageNotification(payload.runId, route.capability, payload.senderId, payload.senderRegistrationName, {
62367
+ text: actionable,
62368
+ replyTo: payload.messageId,
62369
+ replyError: actionable,
62370
+ messageId: payload.notificationId
62371
+ }, payload.senderReturnAddress);
62372
+ }).then((result) => result.delivered).catch(() => false);
62373
+ });
61798
62374
  registerSubagentRelay(pi, {
61799
62375
  runtimeGeneration: () => runtimeGeneration,
61800
62376
  runtimeStarted: () => runtimeStarted,
@@ -61810,8 +62386,11 @@ function piIntercomExtension(pi, testOverrides = {}) {
61810
62386
  registerIntercomLifecycle(pi, {
61811
62387
  config,
61812
62388
  client: () => client,
62389
+ disconnectAuxiliaryClients: disconnectPendingStageRouteClients,
61813
62390
  setClient: (value) => {
61814
62391
  client = value;
62392
+ if (value === null)
62393
+ clientRegistrationGroup = null;
61815
62394
  },
61816
62395
  setShuttingDown: (value) => {
61817
62396
  shuttingDown = value;
@@ -61837,6 +62416,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
61837
62416
  sessionHomeGroup = null;
61838
62417
  } else {
61839
62418
  sessionHomeGroup = resolveHomeGroup(config, value);
62419
+ inboundDeliveries.restore(value.sessionManager.getBranch());
61840
62420
  }
61841
62421
  runtimeContext = value;
61842
62422
  },
@@ -61868,6 +62448,13 @@ function piIntercomExtension(pi, testOverrides = {}) {
61868
62448
  restoreIntercomSessionIdEnv,
61869
62449
  currentStatus
61870
62450
  });
62451
+ pi.on("session_start", async (_event, ctx) => {
62452
+ const pendingStageDelivery = ctx.orchestrationContext?.kind === "workflow-stage" ? ctx.orchestrationContext.pendingStageDelivery : undefined;
62453
+ if (pendingStageDelivery === undefined)
62454
+ return;
62455
+ await ensureConnected("startup");
62456
+ await pendingStageDelivery.deliverPending((from, message) => handleIncomingMessage(ctx, from, message, undefined, true));
62457
+ });
61871
62458
  pi.registerMessageRenderer("intercom_message", (message, _options, theme2) => {
61872
62459
  const details = message.details;
61873
62460
  if (!details)
@@ -61900,7 +62487,7 @@ function piIntercomExtension(pi, testOverrides = {}) {
61900
62487
  syncPresenceIdentity
61901
62488
  });
61902
62489
  }
61903
- var INTERCOM_SESSION_ID_ENV;
62490
+ var INTERCOM_SESSION_ID_ENV, PENDING_STAGE_ROUTE_EVENT = "atomic:workflow-pending-stage-route", PENDING_STAGE_MESSAGE_EVENT = "atomic:workflow-pending-stage-message", PENDING_STAGE_UNDELIVERABLE_EVENT = "atomic:workflow-pending-stage-undeliverable";
61904
62491
  var init_index_heavy = __esm(() => {
61905
62492
  init_src();
61906
62493
  init_client();
@@ -62124,6 +62711,14 @@ function createHeavyProxy(pi, captured) {
62124
62711
  var SUBAGENT_CONTROL_INTERCOM_EVENT2 = "subagent:control-intercom";
62125
62712
  var SUBAGENT_SUPERVISOR_AUTHORIZATION_EVENT2 = "subagent:supervisor-authorization";
62126
62713
  var WORKFLOW_STAGE_LATE_MESSAGE_EVENT = "atomic:workflow-stage-late-message";
62714
+ var PENDING_STAGE_ROUTE_EVENT2 = "atomic:workflow-pending-stage-route";
62715
+ var PENDING_STAGE_UNDELIVERABLE_EVENT2 = "atomic:workflow-pending-stage-undeliverable";
62716
+ function isPendingStageUndeliverableRelay(value) {
62717
+ if (typeof value !== "object" || value === null)
62718
+ return false;
62719
+ const event = value;
62720
+ return typeof event.runId === "string" && typeof event.senderId === "string" && (event.senderRegistrationName === undefined || typeof event.senderRegistrationName === "string") && (event.senderReturnAddress === undefined || typeof event.senderReturnAddress === "string") && typeof event.messageId === "string" && typeof event.notificationId === "string" && typeof event.reason === "string";
62721
+ }
62127
62722
  function isCompletedStageAskRoute2(event) {
62128
62723
  return typeof event.workflowRunId === "string" && event.workflowRunId.length > 0 && typeof event.workflowStageId === "string" && event.workflowStageId.length > 0 && Array.isArray(event.messages) && event.messages.length > 0 && event.messages.every((message) => message.customType === "intercom_message" && typeof message.content === "string" && message.details?.message?.expectsReply === true);
62129
62724
  }
@@ -62349,8 +62944,11 @@ function intercom(pi, options = {}) {
62349
62944
  }
62350
62945
  const generation = ++lifecycleGeneration;
62351
62946
  sessionSnapshot = { event, ctx, generation, lease };
62352
- if (loadedHeavy)
62947
+ if (ctx.orchestrationContext?.kind === "workflow-stage" && ctx.orchestrationContext.pendingStageDelivery !== undefined) {
62948
+ await loadHeavy(ctx);
62949
+ } else if (loadedHeavy) {
62353
62950
  await ensureSessionStartReplayed(loadedHeavy.heavy, lease);
62951
+ }
62354
62952
  });
62355
62953
  pi.on("session_shutdown", async (event, ctx) => {
62356
62954
  const lease = activeLease;
@@ -62466,13 +63064,41 @@ function intercom(pi, options = {}) {
62466
63064
  return await forwarded.completion;
62467
63065
  });
62468
63066
  });
62469
- for (const eventName of [SUBAGENT_CONTROL_INTERCOM_EVENT2, SUBAGENT_RESULT_INTERCOM_EVENT3]) {
63067
+ pi.events.on(PENDING_STAGE_UNDELIVERABLE_EVENT2, (payload) => {
63068
+ if (!isPendingStageUndeliverableRelay(payload) || payload.handled === true)
63069
+ return;
63070
+ payload.handled = true;
63071
+ const forwarded = { ...payload, handled: false, completion: undefined };
63072
+ payload.completion = loadHeavy(latestLifecycleContext()).then(async (handle) => {
63073
+ handle.assertCurrent();
63074
+ await dispatchEventHandlers(handle.heavy, PENDING_STAGE_UNDELIVERABLE_EVENT2, forwarded);
63075
+ handle.assertCurrent();
63076
+ return forwarded.handled === true && forwarded.completion !== undefined ? await forwarded.completion : false;
63077
+ }).catch((error) => {
63078
+ console.error(`Intercom event relay failed (${PENDING_STAGE_UNDELIVERABLE_EVENT2}):`, error);
63079
+ return false;
63080
+ });
63081
+ });
63082
+ for (const eventName of [
63083
+ SUBAGENT_CONTROL_INTERCOM_EVENT2,
63084
+ SUBAGENT_RESULT_INTERCOM_EVENT3,
63085
+ PENDING_STAGE_ROUTE_EVENT2
63086
+ ]) {
62470
63087
  pi.events.on(eventName, (payload) => {
62471
- loadHeavy(latestLifecycleContext()).then(async (handle) => {
63088
+ const completion = loadHeavy(latestLifecycleContext()).then(async (handle) => {
62472
63089
  handle.assertCurrent();
62473
63090
  await dispatchEventHandlers(handle.heavy, eventName, payload);
62474
63091
  handle.assertCurrent();
62475
- }).catch((error) => {
63092
+ if (eventName === PENDING_STAGE_ROUTE_EVENT2 && payload && typeof payload === "object") {
63093
+ const routeCompletion = payload.completion;
63094
+ if (routeCompletion !== undefined && routeCompletion !== completion)
63095
+ await routeCompletion;
63096
+ }
63097
+ });
63098
+ if (eventName === PENDING_STAGE_ROUTE_EVENT2 && payload && typeof payload === "object") {
63099
+ payload.completion = completion;
63100
+ }
63101
+ completion.catch((error) => {
62476
63102
  rejectLazyResultRelay(pi, eventName, payload, error);
62477
63103
  console.error(`Intercom event relay failed (${eventName}):`, error);
62478
63104
  });
@@ -62497,6 +63123,7 @@ function intercom(pi, options = {}) {
62497
63123
  description: `Send a message to another local agent session running on this machine.
62498
63124
  Use this to communicate findings, request help, or coordinate work with other sessions.
62499
63125
  Sessions belong to an intercom group and can ONLY message sessions in the same group; cross-group sends are rejected by the broker. Ungrouped sessions share the "default" group.
63126
+ For send, live session names and exact full session IDs remain supported. For a known workflow stage, use the exact \`<runId>:<stageKey>\` target; send messages to pending stages queue automatically.
62500
63127
  Usage:
62501
63128
  intercom({ action: "list" }) → List sessions in your group
62502
63129
  intercom({ action: "list", group: "name" }) → Read-only peek at another group's sessions
@@ -62512,7 +63139,7 @@ Usage:
62512
63139
  promptSnippet: "Use to coordinate with other local agent sessions in your intercom group: list peers, send updates, ask for help, or check intercom connectivity. Groups are isolated; you can only message sessions in your own group.",
62513
63140
  parameters: Type15.Object({
62514
63141
  action: Type15.String({ description: "Action: 'list', 'join', 'leave', 'send', 'ask', 'reply', 'pending', or 'status'" }),
62515
- to: Type15.Optional(Type15.String({ description: "Exact session name or exact full session ID (for 'send', 'ask', or targeted 'reply')" })),
63142
+ to: Type15.Optional(Type15.String({ description: "Live session name, exact full session ID, or exact `<runId>:<stageKey>` for a known workflow stage; send messages to pending stages queue automatically (for 'send', 'ask', or targeted 'reply')" })),
62516
63143
  message: Type15.Optional(Type15.String({ description: "Message to send (for 'send', 'ask', or 'reply' action)" })),
62517
63144
  attachments: Type15.Optional(Type15.Array(Type15.Object({
62518
63145
  type: Type15.Union([Type15.Literal("file"), Type15.Literal("snippet"), Type15.Literal("context")]),