@bastani/atomic 0.9.16-alpha.7 → 0.9.16-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +4 -4
- package/dist/builtin/intercom/broker/broker.ts +617 -22
- package/dist/builtin/intercom/broker/client-message-validation.ts +9 -0
- package/dist/builtin/intercom/broker/client.ts +200 -10
- package/dist/builtin/intercom/broker/pending-send-registry.ts +4 -0
- package/dist/builtin/intercom/broker/send-handler.ts +90 -36
- package/dist/builtin/intercom/broker/send-signature.ts +20 -8
- package/dist/builtin/intercom/group.ts +85 -0
- package/dist/builtin/intercom/index.bundle.mjs +746 -55
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/session-target.ts +54 -0
- package/dist/builtin/intercom/skills/intercom/SKILL.md +18 -3
- package/dist/builtin/intercom/source-ownership.ts +31 -0
- package/dist/builtin/intercom/types.ts +115 -0
- package/dist/builtin/mcp/index.bundle.mjs +175 -37
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +239 -53
- package/dist/builtin/web-access/index.bundle.mjs +175 -37
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +15 -0
- package/dist/builtin/workflows/README.md +40 -37
- package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
- package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +133 -154
- package/dist/builtin/workflows/builtin/chunk-17zk6ffd.js +69794 -0
- package/dist/builtin/workflows/builtin/chunk-29wrp38a.js +199 -0
- package/dist/builtin/workflows/builtin/chunk-2dqb5s2q.js +602 -0
- package/dist/builtin/workflows/builtin/chunk-4febxsv4.js +264 -0
- package/dist/builtin/workflows/builtin/chunk-5wgwscd0.js +4 -0
- package/dist/builtin/workflows/builtin/chunk-6fqs7c01.js +155 -0
- package/dist/builtin/workflows/builtin/chunk-7430zyas.js +126 -0
- package/dist/builtin/workflows/builtin/chunk-7at6dnkr.js +33 -0
- package/dist/builtin/workflows/builtin/chunk-82ha8p41.js +175 -0
- package/dist/builtin/workflows/builtin/chunk-8v8wmb7z.js +529 -0
- package/dist/builtin/workflows/builtin/chunk-bfkmzv9h.js +156 -0
- package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
- package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
- package/dist/builtin/workflows/builtin/chunk-h5e65g7g.js +1080 -0
- package/dist/builtin/workflows/builtin/chunk-hzzn6adg.js +221 -0
- package/dist/builtin/workflows/builtin/chunk-nqr34qp3.js +1061 -0
- package/dist/builtin/workflows/builtin/chunk-qe6bfpbd.js +1207 -0
- package/dist/builtin/workflows/builtin/chunk-qwzvgxnq.js +404 -0
- package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
- package/dist/builtin/workflows/builtin/chunk-rbnj9621.js +2447 -0
- package/dist/builtin/workflows/builtin/chunk-wpckd35c.js +12 -0
- package/dist/builtin/workflows/builtin/chunk-x2ghn0je.js +4110 -0
- package/dist/builtin/workflows/builtin/classify-and-act.js +12 -0
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.js +10 -0
- package/dist/builtin/workflows/builtin/generate-and-filter.js +12 -0
- package/dist/builtin/workflows/builtin/goal.js +16 -0
- package/dist/builtin/workflows/builtin/index.js +49 -0
- package/dist/builtin/workflows/builtin/loop-until-done.js +12 -0
- package/dist/builtin/workflows/builtin/open-claude-design.js +11 -0
- package/dist/builtin/workflows/builtin/ralph.js +16 -0
- package/dist/builtin/workflows/builtin/steering-context.d.ts +6 -0
- package/dist/builtin/workflows/builtin/steering-context.js +7 -0
- package/dist/builtin/workflows/builtin/tournament.js +13 -0
- package/dist/builtin/workflows/package.json +10 -7
- package/dist/builtin/workflows/src/authoring/typebox-defaults.d.ts +41 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1294 -430
- package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +1022 -429
- package/dist/builtin/workflows/src/shared/authoring-contract-stage.d.ts +403 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +327 -0
- package/dist/builtin/workflows/src/shared/budget.d.ts +67 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +60 -0
- package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
- package/dist/core/agent-session-custom-message-commit.d.ts.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +12 -5
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +2 -0
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +2 -0
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -0
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/builtin-install-layout.d.ts +1 -1
- package/dist/core/builtin-install-layout.d.ts.map +1 -1
- package/dist/core/builtin-install-layout.js +1 -1
- package/dist/core/builtin-install-layout.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +10 -7
- package/dist/core/codex-fast-mode.d.ts.map +1 -1
- package/dist/core/codex-fast-mode.js +31 -13
- package/dist/core/codex-fast-mode.js.map +1 -1
- package/dist/core/extensions/agent-events.d.ts +15 -0
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/extensions/api-types.d.ts +3 -1
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/api-types.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +35 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/event-types.d.ts +2 -2
- package/dist/core/extensions/event-types.d.ts.map +1 -1
- package/dist/core/extensions/event-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +6 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +6 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +65 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/model-runtime.d.ts +2 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +4 -0
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/runtime-credentials.d.ts +1 -0
- package/dist/core/runtime-credentials.d.ts.map +1 -1
- package/dist/core/runtime-credentials.js +8 -0
- package/dist/core/runtime-credentials.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +5 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-storage.d.ts +2 -0
- package/dist/core/session-manager-storage.d.ts.map +1 -1
- package/dist/core/session-manager-storage.js +4 -2
- package/dist/core/session-manager-storage.js.map +1 -1
- package/dist/core/slash-commands.js +1 -1
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/workflow-stage-admission.d.ts +6 -1
- package/dist/core/workflow-stage-admission.d.ts.map +1 -1
- package/dist/core/workflow-stage-admission.js +8 -9
- package/dist/core/workflow-stage-admission.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.js +1 -1
- package/dist/modes/interactive/interactive-extension-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +1 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +69 -10
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +18 -2
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +33 -5
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +8 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +13 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/extensions.md +19 -0
- package/docs/intercom.md +15 -6
- package/docs/packages.md +2 -2
- package/docs/providers.md +8 -3
- package/docs/quickstart.md +2 -2
- package/docs/rpc.md +21 -4
- package/docs/settings.md +6 -4
- package/docs/subagents.md +1 -1
- package/docs/usage.md +1 -1
- package/docs/workflows.md +108 -239
- package/npm-shrinkwrap.json +32 -32
- package/package.json +9 -13
- package/dist/builtin/workflows/ambient.d.ts +0 -61
- package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
- package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
- package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
- package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
- package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
- package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
- package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
- package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
- package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
- package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
- package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
- package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -217
- package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
- package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
- package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
- package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
- package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
- package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
- package/dist/builtin/workflows/builtin/goal.ts +0 -78
- package/dist/builtin/workflows/builtin/index.ts +0 -16
- package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
- package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
- package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
- package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
- package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
- package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
- package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
- package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
- package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -104
- package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -459
- package/dist/builtin/workflows/builtin/ralph.ts +0 -82
- package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
- package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
- package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
- package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
- package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
- package/dist/builtin/workflows/builtin/tournament.ts +0 -73
- package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
- package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
- package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
|
@@ -4589,10 +4589,10 @@ function hasAssistantMessage(entries) {
|
|
|
4589
4589
|
return entries.some((entry) => entry.type === "message" && entry.message.role === "assistant");
|
|
4590
4590
|
}
|
|
4591
4591
|
function persistAppendedEntry(filePath, entries, entry, flushed) {
|
|
4592
|
-
if (!hasAssistantMessage(entries))
|
|
4593
|
-
return false;
|
|
4594
4592
|
if (flushed)
|
|
4595
4593
|
appendSessionEntry(filePath, entry);
|
|
4594
|
+
else if (!hasAssistantMessage(entries))
|
|
4595
|
+
return false;
|
|
4596
4596
|
else
|
|
4597
4597
|
appendSessionEntries(filePath, entries);
|
|
4598
4598
|
return true;
|
|
@@ -10723,6 +10723,8 @@ function appendDurableDisplayCard(session, message, delivery) {
|
|
|
10723
10723
|
const card = { ...message, excludeFromContext: true };
|
|
10724
10724
|
const admitted = message;
|
|
10725
10725
|
const intentEntryId = session.sessionManager.appendCustomMessageEntry(card.customType, card.content, card.display, card.details, true, { delivery }, admitted.stageAdmissionKey);
|
|
10726
|
+
if (admitted.stageAdmissionKey !== undefined)
|
|
10727
|
+
session.sessionManager.flush();
|
|
10726
10728
|
session.agent.state.messages.push(card);
|
|
10727
10729
|
return { card, intentEntryId };
|
|
10728
10730
|
}
|
|
@@ -10948,12 +10950,17 @@ var init_agent_session_persistent_custom_messages = __esm(() => {
|
|
|
10948
10950
|
});
|
|
10949
10951
|
|
|
10950
10952
|
// src/core/agent-session-custom-message-commit.ts
|
|
10953
|
+
function appendDurableStageAdmission(session, message) {
|
|
10954
|
+
session._appendCustomMessage(message);
|
|
10955
|
+
if (message.stageAdmissionKey !== undefined)
|
|
10956
|
+
session.sessionManager?.flush();
|
|
10957
|
+
}
|
|
10951
10958
|
async function commitAdmittedCustomMessage(session, appMessage, options) {
|
|
10952
10959
|
const owner = resolveWorkflowStageDeliveryTarget(session);
|
|
10953
10960
|
if (owner !== session)
|
|
10954
10961
|
return commitAdmittedCustomMessage(owner, appMessage, options);
|
|
10955
10962
|
const self = session;
|
|
10956
|
-
const useProtectedReconciliation = options?.persistWhenStreaming === true && options.triggerTurn === true
|
|
10963
|
+
const useProtectedReconciliation = options?.persistWhenStreaming === true && options.excludeFromContext !== true && (options.triggerTurn === true || options.stageAdmissionKey !== undefined);
|
|
10957
10964
|
if (options?.deliverAs === "nextTurn") {
|
|
10958
10965
|
self._pendingNextTurnMessages.push(appMessage);
|
|
10959
10966
|
} else if (self._queuedMessagesPaused) {
|
|
@@ -10967,20 +10974,20 @@ async function commitAdmittedCustomMessage(session, appMessage, options) {
|
|
|
10967
10974
|
} else if (self.isStreaming) {
|
|
10968
10975
|
self._pendingCustomMessages.push(appMessage);
|
|
10969
10976
|
} else {
|
|
10970
|
-
self
|
|
10977
|
+
appendDurableStageAdmission(self, appMessage);
|
|
10971
10978
|
}
|
|
10972
10979
|
} else if (options?.deliverAs === "interrupt" && options.triggerTurn) {
|
|
10973
10980
|
const interrupt = self._enqueueInterruptCustomMessage(appMessage, options);
|
|
10974
10981
|
self._workflowStageAdmission?.trackAdmittedWork(interrupt);
|
|
10975
10982
|
interrupt.catch(() => {});
|
|
10976
10983
|
} else if (self.isStreaming && options?.excludeFromContext === true && options.triggerTurn !== true && options.deliverAs === undefined) {
|
|
10977
|
-
self
|
|
10984
|
+
appendDurableStageAdmission(self, appMessage);
|
|
10978
10985
|
} else if (self.isStreaming && options?.triggerTurn === false) {
|
|
10979
10986
|
self._pendingCustomMessages.push(appMessage);
|
|
10980
10987
|
} else if (self.isStreaming && useProtectedReconciliation) {
|
|
10981
10988
|
await queueProtectedStreamingCustomMessage(self, appMessage, options?.deliverAs === "followUp" ? "followUp" : "steer");
|
|
10982
10989
|
} else if (self.isStreaming && options?.persistWhenStreaming === true) {
|
|
10983
|
-
self
|
|
10990
|
+
appendDurableStageAdmission(self, appMessage);
|
|
10984
10991
|
} else if (self.isStreaming && options?.triggerTurn !== false) {
|
|
10985
10992
|
self._queueAgentMessage(appMessage, options?.deliverAs === "followUp" ? "followUp" : "steer");
|
|
10986
10993
|
} else if (options?.triggerTurn) {
|
|
@@ -11003,7 +11010,7 @@ async function commitAdmittedCustomMessage(session, appMessage, options) {
|
|
|
11003
11010
|
self._continueQueuedAgentMessages().catch(() => {});
|
|
11004
11011
|
}
|
|
11005
11012
|
} else {
|
|
11006
|
-
self
|
|
11013
|
+
appendDurableStageAdmission(self, appMessage);
|
|
11007
11014
|
}
|
|
11008
11015
|
}
|
|
11009
11016
|
function _commitAdmittedCustomMessage(appMessage, options) {
|
|
@@ -13310,6 +13317,8 @@ class ExtensionRunner {
|
|
|
13310
13317
|
shortcutDiagnostics = [];
|
|
13311
13318
|
commandDiagnostics = [];
|
|
13312
13319
|
staleMessage;
|
|
13320
|
+
uiPromptBinding = 0;
|
|
13321
|
+
activeUIPrompt;
|
|
13313
13322
|
constructor(extensions, runtime, cwd, sessionManager, modelRegistry, orchestrationContext, subagentPolicy) {
|
|
13314
13323
|
this.extensions = extensions;
|
|
13315
13324
|
this.runtime = runtime;
|
|
@@ -13404,9 +13413,71 @@ class ExtensionRunner {
|
|
|
13404
13413
|
this.reloadHandler = async () => {};
|
|
13405
13414
|
}
|
|
13406
13415
|
setUIContext(uiContext, mode = "print") {
|
|
13407
|
-
this.
|
|
13416
|
+
this.endActiveUIPrompt();
|
|
13417
|
+
const binding = ++this.uiPromptBinding;
|
|
13418
|
+
this.uiContext = uiContext ? this.wrapUIPromptContext(uiContext, binding) : noOpUIContext;
|
|
13408
13419
|
this.mode = mode;
|
|
13409
13420
|
}
|
|
13421
|
+
wrapUIPromptContext(ui, binding) {
|
|
13422
|
+
return {
|
|
13423
|
+
...ui,
|
|
13424
|
+
select: (title, options, opts) => this.withUIPrompt(binding, "select", title, () => ui.select(title, options, opts)),
|
|
13425
|
+
confirm: (title, message, opts) => this.withUIPrompt(binding, "confirm", title, () => ui.confirm(title, message, opts)),
|
|
13426
|
+
input: (title, placeholder, opts) => this.withUIPrompt(binding, "input", title, () => ui.input(title, placeholder, opts)),
|
|
13427
|
+
editor: (title, prefill, opts) => this.withUIPrompt(binding, "editor", title, () => ui.editor(title, prefill, opts)),
|
|
13428
|
+
custom: (factory, options) => this.withUIPrompt(binding, "custom", undefined, () => ui.custom(factory, options))
|
|
13429
|
+
};
|
|
13430
|
+
}
|
|
13431
|
+
withUIPrompt(binding, kind, title, run) {
|
|
13432
|
+
if (binding !== this.uiPromptBinding)
|
|
13433
|
+
return run();
|
|
13434
|
+
let prompt = this.activeUIPrompt;
|
|
13435
|
+
if (!prompt) {
|
|
13436
|
+
prompt = { depth: 0, kind, title };
|
|
13437
|
+
this.activeUIPrompt = prompt;
|
|
13438
|
+
this.emitUIPromptEvent({
|
|
13439
|
+
type: "ui_prompt_start",
|
|
13440
|
+
reason: "ui_prompt",
|
|
13441
|
+
kind,
|
|
13442
|
+
...title === undefined ? {} : { title }
|
|
13443
|
+
});
|
|
13444
|
+
}
|
|
13445
|
+
prompt.depth += 1;
|
|
13446
|
+
let finished = false;
|
|
13447
|
+
const finish = () => {
|
|
13448
|
+
if (finished)
|
|
13449
|
+
return;
|
|
13450
|
+
finished = true;
|
|
13451
|
+
if (this.activeUIPrompt !== prompt)
|
|
13452
|
+
return;
|
|
13453
|
+
prompt.depth -= 1;
|
|
13454
|
+
if (prompt.depth === 0)
|
|
13455
|
+
this.endActiveUIPrompt(prompt);
|
|
13456
|
+
};
|
|
13457
|
+
try {
|
|
13458
|
+
return run().finally(finish);
|
|
13459
|
+
} catch (error) {
|
|
13460
|
+
finish();
|
|
13461
|
+
throw error;
|
|
13462
|
+
}
|
|
13463
|
+
}
|
|
13464
|
+
endActiveUIPrompt(prompt = this.activeUIPrompt) {
|
|
13465
|
+
if (!prompt || this.activeUIPrompt !== prompt)
|
|
13466
|
+
return;
|
|
13467
|
+
this.activeUIPrompt = undefined;
|
|
13468
|
+
prompt.depth = 0;
|
|
13469
|
+
this.emitUIPromptEvent({
|
|
13470
|
+
type: "ui_prompt_end",
|
|
13471
|
+
reason: "ui_prompt",
|
|
13472
|
+
kind: prompt.kind,
|
|
13473
|
+
...prompt.title === undefined ? {} : { title: prompt.title }
|
|
13474
|
+
});
|
|
13475
|
+
}
|
|
13476
|
+
emitUIPromptEvent(event) {
|
|
13477
|
+
queueMicrotask(() => {
|
|
13478
|
+
this.emit(event);
|
|
13479
|
+
});
|
|
13480
|
+
}
|
|
13410
13481
|
getUIContext() {
|
|
13411
13482
|
return this.uiContext;
|
|
13412
13483
|
}
|
|
@@ -19160,6 +19231,7 @@ async function loadVirtualModules() {
|
|
|
19160
19231
|
piAi,
|
|
19161
19232
|
piAiOauth,
|
|
19162
19233
|
piAiCloudflareGatewayBinding,
|
|
19234
|
+
properLockfile,
|
|
19163
19235
|
piCodingAgent
|
|
19164
19236
|
] = await Promise.all([
|
|
19165
19237
|
import("typebox"),
|
|
@@ -19171,6 +19243,7 @@ async function loadVirtualModules() {
|
|
|
19171
19243
|
import("@bastani/pi-ai/compat"),
|
|
19172
19244
|
import("@bastani/pi-ai/oauth"),
|
|
19173
19245
|
import("@bastani/pi-ai/api/cloudflare-gateway-binding"),
|
|
19246
|
+
import("proper-lockfile"),
|
|
19174
19247
|
Promise.resolve().then(() => (init_src(), exports_src))
|
|
19175
19248
|
]);
|
|
19176
19249
|
return {
|
|
@@ -19191,6 +19264,7 @@ async function loadVirtualModules() {
|
|
|
19191
19264
|
"@earendil-works/pi-ai/compat": piAi,
|
|
19192
19265
|
"@earendil-works/pi-ai/oauth": piAiOauth,
|
|
19193
19266
|
"@earendil-works/pi-ai/api/cloudflare-gateway-binding": piAiCloudflareGatewayBinding,
|
|
19267
|
+
"proper-lockfile": properLockfile,
|
|
19194
19268
|
"@bastani/atomic": piCodingAgent,
|
|
19195
19269
|
"@mariozechner/pi-agent-core": piAgentCore,
|
|
19196
19270
|
"@mariozechner/pi-tui": piTui,
|
|
@@ -26320,11 +26394,20 @@ function isCodexFastModeCandidateModelId(modelId) {
|
|
|
26320
26394
|
const provider = modelId?.split("/", 1)[0];
|
|
26321
26395
|
return provider !== undefined && isCodexFastModeSupportedProvider(provider);
|
|
26322
26396
|
}
|
|
26323
|
-
function
|
|
26324
|
-
return
|
|
26397
|
+
function isGitHubCopilotModel(model) {
|
|
26398
|
+
return model.provider === "github-copilot";
|
|
26325
26399
|
}
|
|
26326
|
-
function
|
|
26327
|
-
|
|
26400
|
+
function isGitHubCopilotFastModeSupportedModel(model, credential) {
|
|
26401
|
+
if (!isGitHubCopilotModel(model) || credential?.type !== "oauth")
|
|
26402
|
+
return false;
|
|
26403
|
+
const fastModelIds = credential.fastModelIds;
|
|
26404
|
+
return Array.isArray(fastModelIds) && fastModelIds.every((modelId) => typeof modelId === "string") && fastModelIds.includes(`${model.id}-fast`);
|
|
26405
|
+
}
|
|
26406
|
+
function isCodexFastModeSupportedModel(model, copilotCredential) {
|
|
26407
|
+
return isCodexFastModeSupportedProvider(model.provider) || model.api === "openai-codex-responses" || model.id !== undefined && isGitHubCopilotFastModeSupportedModel({ provider: model.provider, id: model.id }, copilotCredential);
|
|
26408
|
+
}
|
|
26409
|
+
function hasSupportedCodexFastModeModel(models, copilotCredential) {
|
|
26410
|
+
return models.some((model) => isCodexFastModeSupportedModel(model, copilotCredential));
|
|
26328
26411
|
}
|
|
26329
26412
|
function isWorkflowStageOrchestrationContext(context) {
|
|
26330
26413
|
return context?.kind === "workflow-stage";
|
|
@@ -26335,11 +26418,11 @@ function getCodexFastModeScope(context) {
|
|
|
26335
26418
|
function isCodexFastModeEnabledForScope(settings, scope) {
|
|
26336
26419
|
return settings[scope];
|
|
26337
26420
|
}
|
|
26338
|
-
function shouldApplyCodexFastModeForScope(model, settings, scope) {
|
|
26339
|
-
return isCodexFastModeSupportedModel(model) && isCodexFastModeEnabledForScope(settings, scope);
|
|
26421
|
+
function shouldApplyCodexFastModeForScope(model, settings, scope, copilotCredential) {
|
|
26422
|
+
return isCodexFastModeSupportedModel(model, copilotCredential) && isCodexFastModeEnabledForScope(settings, scope);
|
|
26340
26423
|
}
|
|
26341
|
-
function shouldApplyCodexFastMode(model, settings, context) {
|
|
26342
|
-
return shouldApplyCodexFastModeForScope(model, settings, getCodexFastModeScope(context));
|
|
26424
|
+
function shouldApplyCodexFastMode(model, settings, context, copilotCredential) {
|
|
26425
|
+
return shouldApplyCodexFastModeForScope(model, settings, getCodexFastModeScope(context), copilotCredential);
|
|
26343
26426
|
}
|
|
26344
26427
|
function usesFirstPartyCodexRouting(model) {
|
|
26345
26428
|
return model.provider === "openai-codex" && isFirstPartyCodexBaseUrl(model.baseUrl);
|
|
@@ -26365,8 +26448,8 @@ function withCodexFastModeHeaders(model, headers, enabled) {
|
|
|
26365
26448
|
setHeader(fastHeaders, CODEX_FAST_MODE_ROUTING_HEADER, `model=${model.id};tier=${CODEX_FAST_MODE_SERVICE_TIER}`);
|
|
26366
26449
|
return fastHeaders;
|
|
26367
26450
|
}
|
|
26368
|
-
function withCodexFastModeStreamOptions(
|
|
26369
|
-
if (!enabled) {
|
|
26451
|
+
function withCodexFastModeStreamOptions(model, options, enabled) {
|
|
26452
|
+
if (!enabled || model.provider === "github-copilot") {
|
|
26370
26453
|
return options;
|
|
26371
26454
|
}
|
|
26372
26455
|
return {
|
|
@@ -26500,10 +26583,14 @@ function streamWithCodexFastMode(model, context, options, streamers = DEFAULT_CO
|
|
|
26500
26583
|
function isObjectPayload(payload) {
|
|
26501
26584
|
return typeof payload === "object" && payload !== null && !Array.isArray(payload);
|
|
26502
26585
|
}
|
|
26503
|
-
function withCodexFastModePayload(payload, enabled) {
|
|
26504
|
-
if (!enabled || !isObjectPayload(payload)
|
|
26586
|
+
function withCodexFastModePayload(payload, enabled, model) {
|
|
26587
|
+
if (!enabled || !isObjectPayload(payload))
|
|
26505
26588
|
return payload;
|
|
26589
|
+
if (model?.provider === "github-copilot") {
|
|
26590
|
+
return payload.model === model.id ? { ...payload, model: `${model.id}-fast` } : payload;
|
|
26506
26591
|
}
|
|
26592
|
+
if (payload.service_tier !== undefined)
|
|
26593
|
+
return payload;
|
|
26507
26594
|
return {
|
|
26508
26595
|
...payload,
|
|
26509
26596
|
service_tier: CODEX_FAST_MODE_SERVICE_TIER
|
|
@@ -26653,7 +26740,7 @@ class FooterComponent {
|
|
|
26653
26740
|
pwd += ` • ${sessionName}`;
|
|
26654
26741
|
const modelName = state.model?.id || "no-model";
|
|
26655
26742
|
const fastModeSettings = this.session.settingsManager.getCodexFastModeSettings();
|
|
26656
|
-
const fastModeEnabled = state.model ? shouldApplyCodexFastMode(state.model, fastModeSettings, this.session.orchestrationContext) : false;
|
|
26743
|
+
const fastModeEnabled = state.model ? shouldApplyCodexFastMode(state.model, fastModeSettings, this.session.orchestrationContext, this.session.modelRuntime.getCredentialSnapshot?.("github-copilot")) : false;
|
|
26657
26744
|
let modelLabel2 = modelName;
|
|
26658
26745
|
if (state.model?.reasoning) {
|
|
26659
26746
|
const thinkingLevel = state.thinkingLevel || "off";
|
|
@@ -45421,14 +45508,18 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
45421
45508
|
|
|
45422
45509
|
class WorkflowStageAdmissionBoundary {
|
|
45423
45510
|
open = true;
|
|
45424
|
-
completed
|
|
45511
|
+
completed;
|
|
45425
45512
|
inFlight = new Map;
|
|
45426
45513
|
pending = new Set;
|
|
45427
45514
|
invocationContext = new AsyncLocalStorage;
|
|
45428
45515
|
closePromise;
|
|
45429
45516
|
drainAdmittedWork;
|
|
45430
|
-
constructor(drainAdmittedWork =
|
|
45431
|
-
this.drainAdmittedWork = drainAdmittedWork;
|
|
45517
|
+
constructor(drainAdmittedWork = undefined, completedKeys = []) {
|
|
45518
|
+
this.drainAdmittedWork = drainAdmittedWork ?? (async () => {});
|
|
45519
|
+
this.completed = new Set(completedKeys);
|
|
45520
|
+
}
|
|
45521
|
+
static restore(entries, drainAdmittedWork) {
|
|
45522
|
+
return new WorkflowStageAdmissionBoundary(drainAdmittedWork, Array.from(entries).flatMap((entry) => entry.type === "custom_message" && typeof entry.stageAdmissionKey === "string" ? [entry.stageAdmissionKey] : []));
|
|
45432
45523
|
}
|
|
45433
45524
|
admit(key, deliver, routeLate) {
|
|
45434
45525
|
if (key !== undefined) {
|
|
@@ -45667,7 +45758,7 @@ class AgentSessionBase {
|
|
|
45667
45758
|
this._subagentPolicy = config.subagentPolicy;
|
|
45668
45759
|
this._systemPromptTransform = config.systemPromptTransform;
|
|
45669
45760
|
const stageContext = config.orchestrationContext?.kind === "workflow-stage" ? config.orchestrationContext : undefined;
|
|
45670
|
-
this._workflowStageAdmission = stageContext?.messageAdmission?.boundary ?? (stageContext ?
|
|
45761
|
+
this._workflowStageAdmission = stageContext?.messageAdmission?.boundary ?? (stageContext ? WorkflowStageAdmissionBoundary.restore(this.sessionManager.getBranch()) : undefined);
|
|
45671
45762
|
if (this._workflowStageAdmission && stageContext && stageContext.messageAdmission === undefined) {
|
|
45672
45763
|
stageContext.messageAdmission = {
|
|
45673
45764
|
boundary: this._workflowStageAdmission,
|
|
@@ -45999,6 +46090,9 @@ class AuthStorage {
|
|
|
45999
46090
|
this.data = this.parseStorageData(content);
|
|
46000
46091
|
} catch {}
|
|
46001
46092
|
}
|
|
46093
|
+
peek(provider) {
|
|
46094
|
+
return this.data[provider];
|
|
46095
|
+
}
|
|
46002
46096
|
async read(provider) {
|
|
46003
46097
|
const credential = this.data[provider];
|
|
46004
46098
|
if (credential?.type !== "api_key")
|
|
@@ -47052,6 +47146,10 @@ function getReloadableStore(store) {
|
|
|
47052
47146
|
const reloadable = store;
|
|
47053
47147
|
return typeof reloadable.reload === "function" ? reloadable : undefined;
|
|
47054
47148
|
}
|
|
47149
|
+
function getSnapshotStore(store) {
|
|
47150
|
+
const snapshotStore = store;
|
|
47151
|
+
return typeof snapshotStore.peek === "function" ? snapshotStore : undefined;
|
|
47152
|
+
}
|
|
47055
47153
|
|
|
47056
47154
|
class RuntimeCredentials {
|
|
47057
47155
|
store;
|
|
@@ -47071,6 +47169,10 @@ class RuntimeCredentials {
|
|
|
47071
47169
|
async reload() {
|
|
47072
47170
|
await getReloadableStore(this.store)?.reload();
|
|
47073
47171
|
}
|
|
47172
|
+
peek(providerId) {
|
|
47173
|
+
const override = this.overrides.get(providerId);
|
|
47174
|
+
return override ? { type: "api_key", key: override } : getSnapshotStore(this.store)?.peek(providerId);
|
|
47175
|
+
}
|
|
47074
47176
|
async read(providerId, options) {
|
|
47075
47177
|
const override = this.overrides.get(providerId);
|
|
47076
47178
|
return override ? { type: "api_key", key: override } : this.store.read(providerId, options);
|
|
@@ -47506,6 +47608,9 @@ class ModelRuntime {
|
|
|
47506
47608
|
hasConfiguredAuth(providerId) {
|
|
47507
47609
|
return this.snapshot.configuredProviders.has(providerId);
|
|
47508
47610
|
}
|
|
47611
|
+
getCredentialSnapshot(providerId) {
|
|
47612
|
+
return this.credentials.peek(providerId);
|
|
47613
|
+
}
|
|
47509
47614
|
async getAuth(providerOrModel, overrides = {}) {
|
|
47510
47615
|
if (typeof providerOrModel === "string")
|
|
47511
47616
|
return this.models.getAuth(providerOrModel, overrides);
|
|
@@ -55461,7 +55566,7 @@ async function createAgentSession(options = {}) {
|
|
|
55461
55566
|
return filtered;
|
|
55462
55567
|
};
|
|
55463
55568
|
const extensionRunnerRef = {};
|
|
55464
|
-
const isCodexFastModeEnabled = (requestModel) => shouldApplyCodexFastMode(requestModel, settingsManager.getCodexFastModeSettings(), options.orchestrationContext);
|
|
55569
|
+
const isCodexFastModeEnabled = (requestModel) => shouldApplyCodexFastMode(requestModel, settingsManager.getCodexFastModeSettings(), options.orchestrationContext, modelRuntime.getCredentialSnapshot("github-copilot"));
|
|
55465
55570
|
agent = new Agent2({
|
|
55466
55571
|
initialState: {
|
|
55467
55572
|
systemPrompt: "",
|
|
@@ -55497,7 +55602,7 @@ async function createAgentSession(options = {}) {
|
|
|
55497
55602
|
const extensionProvider = modelRuntime.getRegisteredProviderConfig(requestModel.provider);
|
|
55498
55603
|
const usesExtensionStream = extensionProvider?.streamSimple !== undefined && requestModel.api === extensionProvider.api;
|
|
55499
55604
|
const transportHeaders = usesExtensionStream ? assembledHeaders : removeUnownedModelHeaders(assembledHeaders, model2.headers, requestHeaders);
|
|
55500
|
-
if (fastModeEnabled && !usesExtensionStream && !authResult) {
|
|
55605
|
+
if (fastModeEnabled && !isGitHubCopilotModel(model2) && !usesExtensionStream && !authResult) {
|
|
55501
55606
|
throw new Error(`No API key found for "${model2.provider}"`);
|
|
55502
55607
|
}
|
|
55503
55608
|
const codexFastModeStreamOptions = withCodexFastModeStreamOptions(requestModel, {
|
|
@@ -55514,7 +55619,7 @@ async function createAgentSession(options = {}) {
|
|
|
55514
55619
|
if (usesExtensionStream) {
|
|
55515
55620
|
return modelRuntime.streamSimple(requestModel, context, codexFastModeStreamOptions);
|
|
55516
55621
|
}
|
|
55517
|
-
if (fastModeEnabled) {
|
|
55622
|
+
if (fastModeEnabled && !isGitHubCopilotModel(requestModel)) {
|
|
55518
55623
|
return streamWithCodexFastMode(requestModel, context, codexFastModeStreamOptions);
|
|
55519
55624
|
}
|
|
55520
55625
|
const transportOptions = usesChatGptCodexTransport(requestModel) && codexFastModeStreamOptions ? withChatGptCodexTransportRouting(requestModel, codexFastModeStreamOptions, false) : codexFastModeStreamOptions;
|
|
@@ -55522,7 +55627,7 @@ async function createAgentSession(options = {}) {
|
|
|
55522
55627
|
},
|
|
55523
55628
|
onPayload: async (payload, model2) => {
|
|
55524
55629
|
const fastModeEnabled = isCodexFastModeEnabled(model2);
|
|
55525
|
-
const guardedPayload = withCodexFastModePayload(payload, fastModeEnabled);
|
|
55630
|
+
const guardedPayload = withCodexFastModePayload(payload, fastModeEnabled, model2);
|
|
55526
55631
|
const sourceMessages = lastConvertedLlmMessages;
|
|
55527
55632
|
const replayGuardedPayload = sourceMessages ? restoreAnthropicReplayThinkingBlocks(guardedPayload, sourceMessages, model2) : guardedPayload;
|
|
55528
55633
|
const runner = extensionRunnerRef.current;
|
|
@@ -59987,6 +60092,31 @@ class RemoteQueuePause {
|
|
|
59987
60092
|
var init_remote_queue_pause = () => {};
|
|
59988
60093
|
|
|
59989
60094
|
// src/modes/interactive-engine/isolated-runtime.ts
|
|
60095
|
+
import { clampThinkingLevel as clampThinkingLevel5 } from "@bastani/pi-ai/compat";
|
|
60096
|
+
function applyPersistedModelDefault(session, model, alreadyInScope) {
|
|
60097
|
+
session.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
60098
|
+
if (alreadyInScope || session.scopedModels.length === 0)
|
|
60099
|
+
return;
|
|
60100
|
+
const enabledModels = session.settingsManager.getEnabledModels();
|
|
60101
|
+
if (!enabledModels?.length)
|
|
60102
|
+
return;
|
|
60103
|
+
const modelReference = `${model.provider}/${model.id}`;
|
|
60104
|
+
if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
|
|
60105
|
+
return;
|
|
60106
|
+
session.settingsManager.setEnabledModels([...enabledModels, modelReference]);
|
|
60107
|
+
}
|
|
60108
|
+
function thinkingPersistTarget(result) {
|
|
60109
|
+
if (!result.provider || !result.modelId)
|
|
60110
|
+
return;
|
|
60111
|
+
return { provider: result.provider, modelId: result.modelId };
|
|
60112
|
+
}
|
|
60113
|
+
function applyPersistedThinkingDefault(session, level, target) {
|
|
60114
|
+
if (target) {
|
|
60115
|
+
session.settingsManager.setModelThinkingLevel(target.provider, target.modelId, level);
|
|
60116
|
+
return;
|
|
60117
|
+
}
|
|
60118
|
+
session.settingsManager.setDefaultThinkingLevel(level);
|
|
60119
|
+
}
|
|
59990
60120
|
var IsolatedInteractiveRuntime;
|
|
59991
60121
|
var init_isolated_runtime = __esm(() => {
|
|
59992
60122
|
init_agent_session_runtime();
|
|
@@ -60005,6 +60135,7 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60005
60135
|
steeringMessages = [];
|
|
60006
60136
|
followUpMessages = [];
|
|
60007
60137
|
queueUpdateGeneration = 0;
|
|
60138
|
+
thinkingEpoch = 0;
|
|
60008
60139
|
pendingQueueClear;
|
|
60009
60140
|
engineCallbackActive = false;
|
|
60010
60141
|
queuePause;
|
|
@@ -60369,43 +60500,56 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60369
60500
|
},
|
|
60370
60501
|
setModel: {
|
|
60371
60502
|
configurable: true,
|
|
60372
|
-
value: async (model) => {
|
|
60373
|
-
const selected = await this.client.setModel(model.provider, model.id);
|
|
60374
|
-
|
|
60503
|
+
value: async (model, options) => {
|
|
60504
|
+
const selected = await this.client.setModel(model.provider, model.id, options);
|
|
60505
|
+
const nextModel = session.modelRuntime.getModel(selected.provider, selected.id) ?? model;
|
|
60506
|
+
session.agent.state.model = nextModel;
|
|
60375
60507
|
this.resolveModelFallback();
|
|
60508
|
+
if (options?.persist === true)
|
|
60509
|
+
await this.syncPersistedModelCatalog(session, nextModel);
|
|
60376
60510
|
}
|
|
60377
60511
|
},
|
|
60378
60512
|
setThinkingLevel: {
|
|
60379
60513
|
configurable: true,
|
|
60380
|
-
value: (level) => {
|
|
60381
|
-
|
|
60382
|
-
|
|
60514
|
+
value: (level, options) => {
|
|
60515
|
+
const availableLevels = session.getAvailableThinkingLevels();
|
|
60516
|
+
const effectiveLevel = availableLevels.includes(level) ? level : session.model ? clampThinkingLevel5(session.model, level) : "off";
|
|
60517
|
+
session.agent.state.thinkingLevel = effectiveLevel;
|
|
60518
|
+
const epoch = ++this.thinkingEpoch;
|
|
60519
|
+
this.dispatchBestEffort("set thinking level", this.client.setThinkingLevelAck(level, options).then((result) => {
|
|
60520
|
+
this.applyThinkingAck(session, epoch, result, options?.persist === true);
|
|
60521
|
+
}));
|
|
60383
60522
|
}
|
|
60384
60523
|
},
|
|
60385
60524
|
cycleModel: {
|
|
60386
60525
|
configurable: true,
|
|
60387
|
-
value: async (direction) => {
|
|
60526
|
+
value: async (direction, options) => {
|
|
60388
60527
|
const previousModel = session.model;
|
|
60389
|
-
const result = await this.client.cycleModel(direction);
|
|
60528
|
+
const result = await this.client.cycleModel(direction, options);
|
|
60390
60529
|
if (!result)
|
|
60391
60530
|
return;
|
|
60392
60531
|
const model = session.modelRuntime.getModel(result.model.provider, result.model.id) ?? result.model;
|
|
60393
60532
|
session.agent.state.model = model;
|
|
60394
60533
|
session.agent.state.thinkingLevel = result.thinkingLevel;
|
|
60395
60534
|
this.resolveModelFallbackAfterExplicitModelSelection(previousModel, model);
|
|
60535
|
+
if (options?.persist === true)
|
|
60536
|
+
await this.syncPersistedModelCatalog(session, model);
|
|
60396
60537
|
return { ...result, model };
|
|
60397
60538
|
}
|
|
60398
60539
|
},
|
|
60399
60540
|
cycleThinkingLevel: {
|
|
60400
60541
|
configurable: true,
|
|
60401
|
-
value: () => {
|
|
60542
|
+
value: (options) => {
|
|
60402
60543
|
const levels = session.getAvailableThinkingLevels();
|
|
60403
60544
|
if (levels.length <= 1)
|
|
60404
60545
|
return;
|
|
60405
60546
|
const current = levels.indexOf(session.thinkingLevel);
|
|
60406
60547
|
const level = levels[(current + 1) % levels.length];
|
|
60407
60548
|
session.agent.state.thinkingLevel = level;
|
|
60408
|
-
|
|
60549
|
+
const epoch = ++this.thinkingEpoch;
|
|
60550
|
+
this.dispatchBestEffort("cycle thinking level", this.client.setThinkingLevelAck(level, options).then((result) => {
|
|
60551
|
+
this.applyThinkingAck(session, epoch, result, options?.persist === true);
|
|
60552
|
+
}));
|
|
60409
60553
|
return level;
|
|
60410
60554
|
}
|
|
60411
60555
|
},
|
|
@@ -60449,6 +60593,14 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60449
60593
|
this.engineCallbackActive = false;
|
|
60450
60594
|
}
|
|
60451
60595
|
}
|
|
60596
|
+
applyThinkingAck(session, epoch, result, persist) {
|
|
60597
|
+
if (persist) {
|
|
60598
|
+
applyPersistedThinkingDefault(session, result.level, thinkingPersistTarget(result));
|
|
60599
|
+
}
|
|
60600
|
+
if (epoch === this.thinkingEpoch) {
|
|
60601
|
+
session.agent.state.thinkingLevel = result.level;
|
|
60602
|
+
}
|
|
60603
|
+
}
|
|
60452
60604
|
dispatchBestEffort(label, operation) {
|
|
60453
60605
|
operation.catch((error) => {
|
|
60454
60606
|
if (this.health.isRecovering())
|
|
@@ -60489,6 +60641,12 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60489
60641
|
}
|
|
60490
60642
|
});
|
|
60491
60643
|
}
|
|
60644
|
+
async syncPersistedModelCatalog(session, model) {
|
|
60645
|
+
const alreadyInScope = session.scopedModels.some((scoped) => scoped.model.provider === model.provider && scoped.model.id === model.id);
|
|
60646
|
+
const catalog = await this.client.requestInternal({ type: "get_available_models" });
|
|
60647
|
+
this.remoteModelCatalog.apply(catalog);
|
|
60648
|
+
applyPersistedModelDefault(session, model, alreadyInScope);
|
|
60649
|
+
}
|
|
60492
60650
|
refreshSessionView() {
|
|
60493
60651
|
const session = super.session;
|
|
60494
60652
|
const sessionFile = session.sessionFile;
|
|
@@ -60528,6 +60686,7 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60528
60686
|
session.agent.state.model = event.model;
|
|
60529
60687
|
break;
|
|
60530
60688
|
case "thinking_level_changed":
|
|
60689
|
+
this.thinkingEpoch += 1;
|
|
60531
60690
|
session.agent.state.thinkingLevel = event.level;
|
|
60532
60691
|
break;
|
|
60533
60692
|
case "session_info_changed":
|
|
@@ -61741,7 +61900,7 @@ var init_slash_commands = __esm(() => {
|
|
|
61741
61900
|
{ name: "tree", description: "Navigate session tree (switch branches)" },
|
|
61742
61901
|
{ name: "thinking", description: "Set thinking level", argumentHint: "<level>" },
|
|
61743
61902
|
{ name: "scoped-models", description: "Enable/disable models for ctrl+p cycling" },
|
|
61744
|
-
{ name: "fast", description: "Configure
|
|
61903
|
+
{ name: "fast", description: "Configure OpenAI fast mode for chat and workflows in supported models" },
|
|
61745
61904
|
{ name: "export", description: "Export session (HTML default, or specify path: .html/.jsonl)" },
|
|
61746
61905
|
{ name: "import", description: "Import and resume a session from a JSONL file" },
|
|
61747
61906
|
{ name: "share", description: "Share session as a secret GitHub gist" },
|
|
@@ -63203,7 +63362,7 @@ var init_interactive_autocomplete = __esm(() => {
|
|
|
63203
63362
|
return [...this.session.modelRuntime.getAvailableSnapshot()];
|
|
63204
63363
|
};
|
|
63205
63364
|
InteractiveModeBase.prototype.hasCodexFastModeSupportedModels = function() {
|
|
63206
|
-
return hasSupportedCodexFastModeModel(this.getCodexFastModeCandidateModels());
|
|
63365
|
+
return hasSupportedCodexFastModeModel(this.getCodexFastModeCandidateModels(), this.session.modelRuntime.getCredentialSnapshot?.("github-copilot"));
|
|
63207
63366
|
};
|
|
63208
63367
|
InteractiveModeBase.prototype.buildRemoteSlashCommands = function(localCommands) {
|
|
63209
63368
|
const remote = getInteractiveEngineRemoteCommands(this.runtimeHost);
|
|
@@ -63891,7 +64050,7 @@ var init_interactive_startup = __esm(() => {
|
|
|
63891
64050
|
if (!model) {
|
|
63892
64051
|
return modelLabel2;
|
|
63893
64052
|
}
|
|
63894
|
-
const fastModeEnabled = shouldApplyCodexFastMode(model, this.session.settingsManager.getCodexFastModeSettings(), this.session.orchestrationContext);
|
|
64053
|
+
const fastModeEnabled = shouldApplyCodexFastMode(model, this.session.settingsManager.getCodexFastModeSettings(), this.session.orchestrationContext, this.session.modelRuntime.getCredentialSnapshot?.("github-copilot"));
|
|
63895
64054
|
return formatCodexFastModeModelLabel(modelLabel2, fastModeEnabled);
|
|
63896
64055
|
};
|
|
63897
64056
|
InteractiveModeBase.prototype.getStartupIdentityText = function(maxWidth, gap = 0, manifestoPhase = 4) {
|
|
@@ -64817,7 +64976,7 @@ var init_interactive_extension_runtime = __esm(() => {
|
|
|
64817
64976
|
if (shortcuts.size === 0)
|
|
64818
64977
|
return;
|
|
64819
64978
|
const createContext = () => ({
|
|
64820
|
-
ui:
|
|
64979
|
+
ui: extensionRunner.getUIContext(),
|
|
64821
64980
|
mode: "tui",
|
|
64822
64981
|
hasUI: true,
|
|
64823
64982
|
cwd: this.sessionManager.getCwd(),
|
|
@@ -68406,7 +68565,7 @@ var init_interactive_selectors = __esm(() => {
|
|
|
68406
68565
|
});
|
|
68407
68566
|
|
|
68408
68567
|
// src/modes/interactive/interactive-model-routing.ts
|
|
68409
|
-
import { clampThinkingLevel as
|
|
68568
|
+
import { clampThinkingLevel as clampThinkingLevel6 } from "@bastani/pi-ai/compat";
|
|
68410
68569
|
function resolveThinkingSelectorDefault(rawDefault, availableLevels, model) {
|
|
68411
68570
|
if (rawDefault === undefined)
|
|
68412
68571
|
return;
|
|
@@ -68414,7 +68573,7 @@ function resolveThinkingSelectorDefault(rawDefault, availableLevels, model) {
|
|
|
68414
68573
|
return rawDefault;
|
|
68415
68574
|
if (!model)
|
|
68416
68575
|
return availableLevels.includes("off") ? "off" : availableLevels[0];
|
|
68417
|
-
const clamped =
|
|
68576
|
+
const clamped = clampThinkingLevel6(model, rawDefault);
|
|
68418
68577
|
if (availableLevels.includes(clamped))
|
|
68419
68578
|
return clamped;
|
|
68420
68579
|
return availableLevels.includes("off") ? "off" : availableLevels[0];
|
|
@@ -70778,11 +70937,20 @@ class RpcClientApi {
|
|
|
70778
70937
|
async getState() {
|
|
70779
70938
|
return this.data(await this.request({ type: "get_state" }));
|
|
70780
70939
|
}
|
|
70781
|
-
async setModel(provider, modelId) {
|
|
70782
|
-
return this.data(await this.request({
|
|
70940
|
+
async setModel(provider, modelId, options) {
|
|
70941
|
+
return this.data(await this.request({
|
|
70942
|
+
type: "set_model",
|
|
70943
|
+
provider,
|
|
70944
|
+
modelId,
|
|
70945
|
+
...options?.persist === true ? { persist: true } : {}
|
|
70946
|
+
}));
|
|
70783
70947
|
}
|
|
70784
|
-
async cycleModel(direction) {
|
|
70785
|
-
return this.data(await this.request({
|
|
70948
|
+
async cycleModel(direction, options) {
|
|
70949
|
+
return this.data(await this.request({
|
|
70950
|
+
type: "cycle_model",
|
|
70951
|
+
direction,
|
|
70952
|
+
...options?.persist === true ? { persist: true } : {}
|
|
70953
|
+
}));
|
|
70786
70954
|
}
|
|
70787
70955
|
async getAvailableModels() {
|
|
70788
70956
|
return this.data(await this.request({ type: "get_available_models" })).models;
|
|
@@ -70816,6 +70984,20 @@ class RpcClientApi {
|
|
|
70816
70984
|
async setThinkingLevel(level) {
|
|
70817
70985
|
await this.request({ type: "set_thinking_level", level });
|
|
70818
70986
|
}
|
|
70987
|
+
async setThinkingLevelAck(level, options) {
|
|
70988
|
+
const response = await this.request({
|
|
70989
|
+
type: "set_thinking_level",
|
|
70990
|
+
level,
|
|
70991
|
+
...options?.persist === true ? { persist: true } : {}
|
|
70992
|
+
});
|
|
70993
|
+
if (!response.success) {
|
|
70994
|
+
return this.data(response);
|
|
70995
|
+
}
|
|
70996
|
+
if (response.command === "set_thinking_level" && "data" in response && response.data) {
|
|
70997
|
+
return response.data;
|
|
70998
|
+
}
|
|
70999
|
+
return { level };
|
|
71000
|
+
}
|
|
70819
71001
|
async cycleThinkingLevel() {
|
|
70820
71002
|
return this.data(await this.request({ type: "cycle_thinking_level" }));
|
|
70821
71003
|
}
|
|
@@ -72834,13 +73016,13 @@ function createRpcCommandHandler({
|
|
|
72834
73016
|
if (!model) {
|
|
72835
73017
|
return createRpcErrorResponse(id, "set_model", `Model not found: ${command.provider}/${command.modelId}`);
|
|
72836
73018
|
}
|
|
72837
|
-
await session.setModel(model);
|
|
73019
|
+
await session.setModel(model, command.persist === true ? { persist: true } : {});
|
|
72838
73020
|
runtimeHost.resolveModelFallback();
|
|
72839
73021
|
return createRpcSuccessResponse(id, "set_model", session.model ?? model);
|
|
72840
73022
|
}
|
|
72841
73023
|
case "cycle_model": {
|
|
72842
73024
|
const previousModel = session.model;
|
|
72843
|
-
const result = await session.cycleModel(command.direction);
|
|
73025
|
+
const result = await session.cycleModel(command.direction, command.persist === true ? { persist: true } : {});
|
|
72844
73026
|
runtimeHost.resolveModelFallbackAfterExplicitModelSelection(previousModel, result?.model);
|
|
72845
73027
|
return createRpcSuccessResponse(id, "cycle_model", result ?? null);
|
|
72846
73028
|
}
|
|
@@ -72903,8 +73085,12 @@ function createRpcCommandHandler({
|
|
|
72903
73085
|
}
|
|
72904
73086
|
}
|
|
72905
73087
|
case "set_thinking_level": {
|
|
72906
|
-
session.setThinkingLevel(command.level);
|
|
72907
|
-
|
|
73088
|
+
session.setThinkingLevel(command.level, command.persist === true ? { persist: true } : {});
|
|
73089
|
+
const model = session.model;
|
|
73090
|
+
return createRpcSuccessResponse(id, "set_thinking_level", {
|
|
73091
|
+
level: session.thinkingLevel,
|
|
73092
|
+
...model ? { provider: model.provider, modelId: model.id } : {}
|
|
73093
|
+
});
|
|
72908
73094
|
}
|
|
72909
73095
|
case "cycle_thinking_level": {
|
|
72910
73096
|
const level = session.cycleThinkingLevel();
|
|
@@ -76717,6 +76903,152 @@ function subscribeIntercomControl(pi, callbacks) {
|
|
|
76717
76903
|
};
|
|
76718
76904
|
}
|
|
76719
76905
|
|
|
76906
|
+
// dist/builtin/workflows/src/shared/pending-stage-delivery.ts
|
|
76907
|
+
var PENDING_STAGE_MESSAGE_LIMIT = 50;
|
|
76908
|
+
var PENDING_STAGE_UNDELIVERABLE_NOTIFICATION_PREFIX = "atomic-pending-stage-undeliverable";
|
|
76909
|
+
function queueStageMessage(messages2, input2, senderGroup, runGroup, stageIdentity) {
|
|
76910
|
+
if (normalizeDeliveryGroup(senderGroup) !== normalizeDeliveryGroup(runGroup)) {
|
|
76911
|
+
return { ok: false, reason: "group_mismatch", runId: input2.runId, stageKey: input2.stageKey };
|
|
76912
|
+
}
|
|
76913
|
+
const messageId = input2.message.id;
|
|
76914
|
+
const queued = pendingStageMessagesFor(messages2, input2.runId, input2.stageKey, stageIdentity);
|
|
76915
|
+
const existing = messages2.find((entry2) => entry2.runId === input2.runId && entry2.id === messageId);
|
|
76916
|
+
if (existing !== undefined) {
|
|
76917
|
+
if (pendingStageMessageSignature(existing, stageIdentity) !== pendingStageMessageSignature(input2, stageIdentity)) {
|
|
76918
|
+
return {
|
|
76919
|
+
ok: false,
|
|
76920
|
+
reason: "message_id_conflict",
|
|
76921
|
+
runId: input2.runId,
|
|
76922
|
+
stageKey: input2.stageKey,
|
|
76923
|
+
messageId
|
|
76924
|
+
};
|
|
76925
|
+
}
|
|
76926
|
+
const queuedPosition = queued.indexOf(existing);
|
|
76927
|
+
return {
|
|
76928
|
+
ok: true,
|
|
76929
|
+
messages: messages2,
|
|
76930
|
+
entry: existing,
|
|
76931
|
+
...queuedPosition >= 0 ? { position: queuedPosition + 1 } : {},
|
|
76932
|
+
deduplicated: true
|
|
76933
|
+
};
|
|
76934
|
+
}
|
|
76935
|
+
if (queued.length >= PENDING_STAGE_MESSAGE_LIMIT) {
|
|
76936
|
+
return {
|
|
76937
|
+
ok: false,
|
|
76938
|
+
reason: "capacity",
|
|
76939
|
+
limit: PENDING_STAGE_MESSAGE_LIMIT,
|
|
76940
|
+
runId: input2.runId,
|
|
76941
|
+
stageKey: input2.stageKey
|
|
76942
|
+
};
|
|
76943
|
+
}
|
|
76944
|
+
const entry = {
|
|
76945
|
+
...input2,
|
|
76946
|
+
id: messageId,
|
|
76947
|
+
...stageIdentity !== undefined ? { stageId: stageIdentity.id } : {},
|
|
76948
|
+
...stageIdentity?.replayKey !== undefined ? { stageReplayKey: stageIdentity.replayKey } : {},
|
|
76949
|
+
admissionOrder: nextAdmissionOrder(messages2, input2.runId),
|
|
76950
|
+
status: "queued"
|
|
76951
|
+
};
|
|
76952
|
+
return {
|
|
76953
|
+
ok: true,
|
|
76954
|
+
messages: [...messages2, entry],
|
|
76955
|
+
entry,
|
|
76956
|
+
position: queued.length + 1,
|
|
76957
|
+
deduplicated: false
|
|
76958
|
+
};
|
|
76959
|
+
}
|
|
76960
|
+
function pendingStageMessagesFor(messages2, runId, stageKey, stageIdentity) {
|
|
76961
|
+
return messages2.map((entry, index) => ({ entry, index })).filter(({ entry }) => matchesPendingStage(entry, runId, stageKey, stageIdentity) && entry.status === "queued").sort((left, right) => (left.entry.admissionOrder ?? left.index + 1) - (right.entry.admissionOrder ?? right.index + 1) || left.index - right.index).map(({ entry }) => entry);
|
|
76962
|
+
}
|
|
76963
|
+
function markPendingStageMessageDelivered(messages2, runId, stageKey, messageId, deliveredAt, stageIdentity) {
|
|
76964
|
+
return updateQueuedPendingStageMessage(messages2, runId, stageKey, messageId, stageIdentity, (entry) => ({
|
|
76965
|
+
...entry,
|
|
76966
|
+
status: "delivered",
|
|
76967
|
+
deliveredAt
|
|
76968
|
+
}));
|
|
76969
|
+
}
|
|
76970
|
+
function markPendingStageMessageUndeliverable(messages2, runId, stageKey, messageId, reason, stageIdentity) {
|
|
76971
|
+
return updateQueuedPendingStageMessage(messages2, runId, stageKey, messageId, stageIdentity, (entry) => ({
|
|
76972
|
+
...entry,
|
|
76973
|
+
status: "undeliverable",
|
|
76974
|
+
undeliverableReason: reason,
|
|
76975
|
+
undeliverableNotificationId: pendingStageUndeliverableNotificationId(entry)
|
|
76976
|
+
}));
|
|
76977
|
+
}
|
|
76978
|
+
function markPendingStageMessageUndeliverableNotified(messages2, runId, stageKey, messageId, notificationId, notifiedAt) {
|
|
76979
|
+
const index = messages2.findIndex((entry) => matchesPendingStage(entry, runId, stageKey) && entry.id === messageId && entry.status === "undeliverable" && entry.undeliverableNotificationId === notificationId && entry.undeliverableNotifiedAt === undefined);
|
|
76980
|
+
if (index < 0)
|
|
76981
|
+
return messages2;
|
|
76982
|
+
const next = [...messages2];
|
|
76983
|
+
next[index] = { ...next[index], undeliverableNotifiedAt: notifiedAt };
|
|
76984
|
+
return next;
|
|
76985
|
+
}
|
|
76986
|
+
function pendingStageUndeliverableNotificationId(entry) {
|
|
76987
|
+
return [
|
|
76988
|
+
PENDING_STAGE_UNDELIVERABLE_NOTIFICATION_PREFIX,
|
|
76989
|
+
encodeURIComponent(entry.runId),
|
|
76990
|
+
encodeURIComponent(entry.stageKey),
|
|
76991
|
+
encodeURIComponent(entry.id)
|
|
76992
|
+
].join(":");
|
|
76993
|
+
}
|
|
76994
|
+
function updateQueuedPendingStageMessage(messages2, runId, stageKey, messageId, stageIdentity, update2) {
|
|
76995
|
+
const index = messages2.findIndex((entry) => matchesPendingStage(entry, runId, stageKey, stageIdentity) && entry.id === messageId && entry.status === "queued");
|
|
76996
|
+
if (index < 0)
|
|
76997
|
+
return messages2;
|
|
76998
|
+
const next = [...messages2];
|
|
76999
|
+
next[index] = update2(next[index]);
|
|
77000
|
+
return next;
|
|
77001
|
+
}
|
|
77002
|
+
function matchesPendingStage(entry, runId, stageKey, stageIdentity) {
|
|
77003
|
+
if (entry.runId !== runId)
|
|
77004
|
+
return false;
|
|
77005
|
+
if (stageIdentity === undefined)
|
|
77006
|
+
return entry.stageKey === stageKey;
|
|
77007
|
+
return entry.stageId === stageIdentity.id || entry.stageReplayKey !== undefined && entry.stageReplayKey === stageIdentity.replayKey || entry.stageId === undefined && stageIdentity.aliases.includes(entry.stageKey);
|
|
77008
|
+
}
|
|
77009
|
+
function nextAdmissionOrder(messages2, runId) {
|
|
77010
|
+
let greatest = 0;
|
|
77011
|
+
let legacyPosition = 0;
|
|
77012
|
+
for (const entry of messages2) {
|
|
77013
|
+
if (entry.runId !== runId)
|
|
77014
|
+
continue;
|
|
77015
|
+
legacyPosition += 1;
|
|
77016
|
+
greatest = Math.max(greatest, entry.admissionOrder ?? legacyPosition);
|
|
77017
|
+
}
|
|
77018
|
+
return greatest + 1;
|
|
77019
|
+
}
|
|
77020
|
+
function pendingStageMessageSignature(entry, stageIdentity) {
|
|
77021
|
+
const storedTarget = "status" in entry ? entry.stageReplayKey ?? entry.stageId : undefined;
|
|
77022
|
+
const { timestamp: transportTimestamp, ...logicalMessage } = entry.message;
|
|
77023
|
+
return stableJson({
|
|
77024
|
+
target: storedTarget ?? stageIdentity?.replayKey ?? stageIdentity?.id ?? entry.stageKey,
|
|
77025
|
+
sender: entry.senderReturnAddress ?? entry.from.id,
|
|
77026
|
+
message: {
|
|
77027
|
+
...logicalMessage,
|
|
77028
|
+
expectsReply: logicalMessage.expectsReply ?? false,
|
|
77029
|
+
content: {
|
|
77030
|
+
...logicalMessage.content,
|
|
77031
|
+
attachments: logicalMessage.content.attachments ?? []
|
|
77032
|
+
}
|
|
77033
|
+
}
|
|
77034
|
+
});
|
|
77035
|
+
}
|
|
77036
|
+
function stableJson(value) {
|
|
77037
|
+
return JSON.stringify(sortJsonValue(value));
|
|
77038
|
+
}
|
|
77039
|
+
function sortJsonValue(value) {
|
|
77040
|
+
if (Array.isArray(value))
|
|
77041
|
+
return value.map(sortJsonValue);
|
|
77042
|
+
if (typeof value !== "object" || value === null)
|
|
77043
|
+
return value;
|
|
77044
|
+
return Object.fromEntries(Object.entries(value).filter(([, nested]) => nested !== undefined).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, sortJsonValue(nested)]));
|
|
77045
|
+
}
|
|
77046
|
+
function normalizeDeliveryGroup(value) {
|
|
77047
|
+
if (typeof value !== "string")
|
|
77048
|
+
return "default";
|
|
77049
|
+
const trimmed = value.trim();
|
|
77050
|
+
return trimmed.length > 0 ? trimmed : "default";
|
|
77051
|
+
}
|
|
76720
77052
|
// dist/builtin/workflows/src/shared/session-scoped-singleton.ts
|
|
76721
77053
|
init_src();
|
|
76722
77054
|
var SHARED_STATES_KEY = Symbol.for("atomic-workflows/session-scoped-singleton-pre-adoption@1");
|
|
@@ -77229,6 +77561,7 @@ function compactStage(stage) {
|
|
|
77229
77561
|
inputRequest,
|
|
77230
77562
|
notices,
|
|
77231
77563
|
mcpScope: _mcpScope,
|
|
77564
|
+
pendingStageDeliveryAvailable: _pendingStageDeliveryAvailable,
|
|
77232
77565
|
attemptedModels: _attemptedModels,
|
|
77233
77566
|
modelAttempts: _modelAttempts,
|
|
77234
77567
|
result: _result,
|
|
@@ -77484,6 +77817,133 @@ function createStoreContext(state = createStoreState()) {
|
|
|
77484
77817
|
};
|
|
77485
77818
|
}
|
|
77486
77819
|
|
|
77820
|
+
// dist/builtin/workflows/src/shared/store-pending-stage-delivery-methods.ts
|
|
77821
|
+
function createPendingStageDeliveryStoreMethods(context) {
|
|
77822
|
+
const transitions = new Map;
|
|
77823
|
+
const serialize = async (runId, transition) => {
|
|
77824
|
+
const previous2 = transitions.get(runId) ?? Promise.resolve();
|
|
77825
|
+
const result = previous2.catch(() => {
|
|
77826
|
+
return;
|
|
77827
|
+
}).then(transition);
|
|
77828
|
+
const settled = result.then(() => {
|
|
77829
|
+
return;
|
|
77830
|
+
}, () => {
|
|
77831
|
+
return;
|
|
77832
|
+
});
|
|
77833
|
+
transitions.set(runId, settled);
|
|
77834
|
+
settled.finally(() => {
|
|
77835
|
+
if (transitions.get(runId) === settled)
|
|
77836
|
+
transitions.delete(runId);
|
|
77837
|
+
});
|
|
77838
|
+
return await result;
|
|
77839
|
+
};
|
|
77840
|
+
return {
|
|
77841
|
+
async queueStageMessage(input2, senderGroup, runGroup, backend) {
|
|
77842
|
+
return await serialize(input2.runId, async () => {
|
|
77843
|
+
const run = context.findRun(input2.runId);
|
|
77844
|
+
if (run === undefined)
|
|
77845
|
+
return;
|
|
77846
|
+
const stageIdentity = resolvePendingStageIdentity(run, input2.stageKey);
|
|
77847
|
+
const result = queueStageMessage(run.pendingStageMessages ?? [], input2, senderGroup, runGroup, stageIdentity);
|
|
77848
|
+
if (result.ok && !result.deduplicated) {
|
|
77849
|
+
await persistTransition(backend, input2.runId, result.messages);
|
|
77850
|
+
run.pendingStageMessages = [...result.messages];
|
|
77851
|
+
context.bumpAndNotify();
|
|
77852
|
+
}
|
|
77853
|
+
return result;
|
|
77854
|
+
});
|
|
77855
|
+
},
|
|
77856
|
+
async validateLiveStageMessage(input2) {
|
|
77857
|
+
return await serialize(input2.runId, async () => {
|
|
77858
|
+
const run = context.findRun(input2.runId);
|
|
77859
|
+
if (run === undefined)
|
|
77860
|
+
return;
|
|
77861
|
+
const result = queueStageMessage(run.pendingStageMessages ?? [], input2, undefined, undefined, resolvePendingStageIdentity(run, input2.stageKey));
|
|
77862
|
+
if (!result.ok) {
|
|
77863
|
+
return result.reason === "message_id_conflict" ? { outcome: "message_id_conflict", messageId: result.messageId } : { outcome: "forward" };
|
|
77864
|
+
}
|
|
77865
|
+
if (!result.deduplicated)
|
|
77866
|
+
return { outcome: "forward" };
|
|
77867
|
+
if (result.entry.status === "delivered")
|
|
77868
|
+
return { outcome: "delivered" };
|
|
77869
|
+
if (result.entry.status === "undeliverable") {
|
|
77870
|
+
return { outcome: "undeliverable", reason: result.entry.undeliverableReason };
|
|
77871
|
+
}
|
|
77872
|
+
if (result.position === undefined) {
|
|
77873
|
+
throw new Error(`atomic-workflows: queued message ${input2.message.id} has no active position`);
|
|
77874
|
+
}
|
|
77875
|
+
return { outcome: "queued", position: result.position };
|
|
77876
|
+
});
|
|
77877
|
+
},
|
|
77878
|
+
pendingStageMessagesFor(runId, stageKey) {
|
|
77879
|
+
const run = context.findRun(runId);
|
|
77880
|
+
return pendingStageMessagesFor(run?.pendingStageMessages ?? [], runId, stageKey, run === undefined ? undefined : resolvePendingStageIdentity(run, stageKey));
|
|
77881
|
+
},
|
|
77882
|
+
async markPendingStageMessageDelivered(runId, stageKey, messageId, deliveredAt, backend) {
|
|
77883
|
+
return await serialize(runId, async () => {
|
|
77884
|
+
const run = context.findRun(runId);
|
|
77885
|
+
if (run === undefined)
|
|
77886
|
+
return false;
|
|
77887
|
+
const current = run.pendingStageMessages ?? [];
|
|
77888
|
+
const next = markPendingStageMessageDelivered(current, runId, stageKey, messageId, deliveredAt, resolvePendingStageIdentity(run, stageKey));
|
|
77889
|
+
if (next === current)
|
|
77890
|
+
return false;
|
|
77891
|
+
await persistTransition(backend, runId, next);
|
|
77892
|
+
run.pendingStageMessages = [...next];
|
|
77893
|
+
context.bumpAndNotify();
|
|
77894
|
+
return true;
|
|
77895
|
+
});
|
|
77896
|
+
},
|
|
77897
|
+
async markPendingStageMessageUndeliverable(runId, stageKey, messageId, reason, backend) {
|
|
77898
|
+
return await serialize(runId, async () => {
|
|
77899
|
+
const run = context.findRun(runId);
|
|
77900
|
+
if (run === undefined)
|
|
77901
|
+
return false;
|
|
77902
|
+
const current = run.pendingStageMessages ?? [];
|
|
77903
|
+
const next = markPendingStageMessageUndeliverable(current, runId, stageKey, messageId, reason, resolvePendingStageIdentity(run, stageKey));
|
|
77904
|
+
if (next === current)
|
|
77905
|
+
return false;
|
|
77906
|
+
await persistTransition(backend, runId, next);
|
|
77907
|
+
run.pendingStageMessages = [...next];
|
|
77908
|
+
context.bumpAndNotify();
|
|
77909
|
+
return true;
|
|
77910
|
+
});
|
|
77911
|
+
},
|
|
77912
|
+
async markPendingStageMessageUndeliverableNotified(runId, stageKey, messageId, notificationId, notifiedAt, backend) {
|
|
77913
|
+
return await serialize(runId, async () => {
|
|
77914
|
+
const run = context.findRun(runId);
|
|
77915
|
+
if (run === undefined)
|
|
77916
|
+
return false;
|
|
77917
|
+
const current = run.pendingStageMessages ?? [];
|
|
77918
|
+
const next = markPendingStageMessageUndeliverableNotified(current, runId, stageKey, messageId, notificationId, notifiedAt);
|
|
77919
|
+
if (next === current)
|
|
77920
|
+
return false;
|
|
77921
|
+
await persistTransition(backend, runId, next);
|
|
77922
|
+
run.pendingStageMessages = [...next];
|
|
77923
|
+
context.bumpAndNotify();
|
|
77924
|
+
return true;
|
|
77925
|
+
});
|
|
77926
|
+
}
|
|
77927
|
+
};
|
|
77928
|
+
}
|
|
77929
|
+
function resolvePendingStageIdentity(run, stageKey) {
|
|
77930
|
+
const exactIds = run.stages.filter((stage2) => stage2.id === stageKey);
|
|
77931
|
+
const candidates = exactIds.length > 0 ? exactIds : run.stages.filter((stage2) => stage2.name === stageKey);
|
|
77932
|
+
if (candidates.length !== 1)
|
|
77933
|
+
return;
|
|
77934
|
+
const stage = candidates[0];
|
|
77935
|
+
return {
|
|
77936
|
+
id: stage.id,
|
|
77937
|
+
...stage.replayKey !== undefined ? { replayKey: stage.replayKey } : {},
|
|
77938
|
+
aliases: stage.id === stage.name ? [stage.id] : [stage.id, stage.name]
|
|
77939
|
+
};
|
|
77940
|
+
}
|
|
77941
|
+
async function persistTransition(backend, runId, messages2) {
|
|
77942
|
+
if (!await backend.persistPendingStageMessages(runId, messages2)) {
|
|
77943
|
+
throw new Error(`atomic-workflows: durable workflow ${runId} is unavailable for pending-stage persistence`);
|
|
77944
|
+
}
|
|
77945
|
+
}
|
|
77946
|
+
|
|
77487
77947
|
// dist/builtin/workflows/src/shared/store-prompt-methods.ts
|
|
77488
77948
|
function createPromptStoreMethods(context) {
|
|
77489
77949
|
const { state } = context;
|
|
@@ -78401,6 +78861,7 @@ function createStore() {
|
|
|
78401
78861
|
const context = createStoreContext();
|
|
78402
78862
|
return {
|
|
78403
78863
|
...createRunStoreMethods(context),
|
|
78864
|
+
...createPendingStageDeliveryStoreMethods(context),
|
|
78404
78865
|
...createStageStoreMethods(context),
|
|
78405
78866
|
...createToolNodeStoreMethods(context),
|
|
78406
78867
|
...createPromptStoreMethods(context)
|
|
@@ -90556,6 +91017,26 @@ function canonicalJsonString(value) {
|
|
|
90556
91017
|
}
|
|
90557
91018
|
|
|
90558
91019
|
// dist/builtin/workflows/src/durable/backend.ts
|
|
91020
|
+
function replacePendingStageMessagesForRun(existing, logicalRunId, messages2) {
|
|
91021
|
+
if (messages2.some((entry) => entry.runId !== logicalRunId)) {
|
|
91022
|
+
throw new Error(`atomic-workflows: pending-stage persistence mixed logical run ${logicalRunId}`);
|
|
91023
|
+
}
|
|
91024
|
+
const firstOwnedIndex = existing.findIndex((entry) => entry.runId === logicalRunId);
|
|
91025
|
+
if (firstOwnedIndex < 0)
|
|
91026
|
+
return [...existing, ...messages2];
|
|
91027
|
+
const merged = [];
|
|
91028
|
+
for (let index = 0;index < existing.length; index += 1) {
|
|
91029
|
+
const entry = existing[index];
|
|
91030
|
+
if (index === firstOwnedIndex)
|
|
91031
|
+
merged.push(...messages2);
|
|
91032
|
+
if (entry.runId !== logicalRunId)
|
|
91033
|
+
merged.push(entry);
|
|
91034
|
+
}
|
|
91035
|
+
return merged;
|
|
91036
|
+
}
|
|
91037
|
+
function pendingStageMessagesForDurableRun(backend, logicalRunId, rootWorkflowId = logicalRunId) {
|
|
91038
|
+
return (backend.getWorkflow(rootWorkflowId)?.pendingStageMessages ?? []).filter((entry) => entry.runId === logicalRunId);
|
|
91039
|
+
}
|
|
90559
91040
|
function checkpointKey(c2) {
|
|
90560
91041
|
return `${c2.kind}:${c2.checkpointId}`;
|
|
90561
91042
|
}
|
|
@@ -90582,6 +91063,7 @@ class InMemoryDurableBackend {
|
|
|
90582
91063
|
...handle.workflowCwd !== undefined ? { workflowCwd: handle.workflowCwd } : existing?.handle.workflowCwd !== undefined ? { workflowCwd: existing.handle.workflowCwd } : {},
|
|
90583
91064
|
...handle.repositoryRoot !== undefined ? { repositoryRoot: handle.repositoryRoot } : existing?.handle.repositoryRoot !== undefined ? { repositoryRoot: existing.handle.repositoryRoot } : {},
|
|
90584
91065
|
...handle.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: handle.gitWorktreeRoot } : existing?.handle.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: existing.handle.gitWorktreeRoot } : {},
|
|
91066
|
+
pendingStageMessages: handle.pendingStageMessages ?? existing?.handle.pendingStageMessages ?? [],
|
|
90585
91067
|
...handle.sessionFile !== undefined ? { sessionFile: handle.sessionFile } : {},
|
|
90586
91068
|
completedCheckpoints,
|
|
90587
91069
|
pendingPrompts,
|
|
@@ -90606,6 +91088,17 @@ class InMemoryDurableBackend {
|
|
|
90606
91088
|
if (handle.pendingPrompts !== undefined)
|
|
90607
91089
|
this.promptReservations.delete(handle.workflowId);
|
|
90608
91090
|
}
|
|
91091
|
+
async persistPendingStageMessages(workflowId, messages2, logicalRunId = workflowId) {
|
|
91092
|
+
const handle = this.getWorkflow(workflowId);
|
|
91093
|
+
if (handle === undefined)
|
|
91094
|
+
return false;
|
|
91095
|
+
this.registerWorkflow({
|
|
91096
|
+
...handle,
|
|
91097
|
+
pendingStageMessages: replacePendingStageMessagesForRun(handle.pendingStageMessages ?? [], logicalRunId, messages2),
|
|
91098
|
+
updatedAt: nextMetadataTimestamp(handle.updatedAt)
|
|
91099
|
+
});
|
|
91100
|
+
return true;
|
|
91101
|
+
}
|
|
90609
91102
|
recordCheckpoint(checkpoint) {
|
|
90610
91103
|
const currentCheckpoint = withCurrentStageTopology(checkpoint);
|
|
90611
91104
|
const rec = this.workflows.get(currentCheckpoint.workflowId);
|
|
@@ -90798,6 +91291,7 @@ class InMemoryDurableBackend {
|
|
|
90798
91291
|
createdAt: h.createdAt,
|
|
90799
91292
|
completedCheckpoints: h.completedCheckpoints,
|
|
90800
91293
|
pendingPrompts: h.pendingPrompts,
|
|
91294
|
+
pendingStageMessages: h.pendingStageMessages ?? [],
|
|
90801
91295
|
...h.ownerExecutorId !== undefined ? { ownerExecutorId: h.ownerExecutorId } : {},
|
|
90802
91296
|
...h.sessionFile !== undefined ? { sessionFile: h.sessionFile } : {},
|
|
90803
91297
|
...h.label !== undefined ? { label: h.label } : {},
|
|
@@ -90886,6 +91380,9 @@ function toResumableEntry(handle) {
|
|
|
90886
91380
|
updatedAt: handle.updatedAt
|
|
90887
91381
|
};
|
|
90888
91382
|
}
|
|
91383
|
+
function nextMetadataTimestamp(previous2) {
|
|
91384
|
+
return Math.max(Date.now(), previous2 + 1);
|
|
91385
|
+
}
|
|
90889
91386
|
|
|
90890
91387
|
// dist/builtin/workflows/src/durable/stage-topology-validation.ts
|
|
90891
91388
|
function immutableStageGroupError(stages) {
|
|
@@ -92076,6 +92573,7 @@ function encodeMetadata(metadata) {
|
|
|
92076
92573
|
completedCheckpoints: metadata.completedCheckpoints,
|
|
92077
92574
|
pendingPrompts: metadata.pendingPrompts,
|
|
92078
92575
|
promptReservationEpoch: metadata.promptReservationEpoch,
|
|
92576
|
+
...metadata.pendingStageMessages !== undefined ? { pendingStageMessages: serializePendingStageMessages(metadata.pendingStageMessages) } : {},
|
|
92079
92577
|
...metadata.ownerExecutorId !== undefined ? { ownerExecutorId: metadata.ownerExecutorId } : {},
|
|
92080
92578
|
...metadata.transitionClaimId !== undefined ? { transitionClaimId: metadata.transitionClaimId } : {},
|
|
92081
92579
|
...metadata.sessionFile !== undefined ? { sessionFile: metadata.sessionFile } : {},
|
|
@@ -92133,15 +92631,101 @@ function metadataTimestamp(record) {
|
|
|
92133
92631
|
function parseDurableWorkflowMetadata(value, workflowId) {
|
|
92134
92632
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
92135
92633
|
return;
|
|
92634
|
+
const serialized = value;
|
|
92635
|
+
const pendingStageMessages = parsePendingStageMessages(serialized.pendingStageMessages);
|
|
92636
|
+
if (pendingStageMessages === null)
|
|
92637
|
+
return;
|
|
92136
92638
|
const metadata = value;
|
|
92137
92639
|
if (metadata.workflowId !== workflowId || typeof metadata.workflowId !== "string" || typeof metadata.name !== "string" || typeof metadata.inputs !== "object" || metadata.inputs === null || Array.isArray(metadata.inputs) || typeof metadata.status !== "string" || !isDurableWorkflowStatus(metadata.status) || typeof metadata.completedCheckpoints !== "number" || typeof metadata.createdAt !== "number" || typeof metadata.pendingPrompts !== "number" || typeof metadata.promptReservationEpoch !== "string" || typeof metadata.updatedAt !== "number" || metadata.ownerExecutorId !== undefined && typeof metadata.ownerExecutorId !== "string" || metadata.transitionClaimId !== undefined && typeof metadata.transitionClaimId !== "string" || metadata.sessionFile !== undefined && typeof metadata.sessionFile !== "string" || metadata.label !== undefined && typeof metadata.label !== "string" || metadata.rootWorkflowId !== undefined && typeof metadata.rootWorkflowId !== "string" || metadata.resumable !== undefined && typeof metadata.resumable !== "boolean" || metadata.exited !== undefined && typeof metadata.exited !== "boolean" || metadata.exitReason !== undefined && typeof metadata.exitReason !== "string" || metadata.error !== undefined && typeof metadata.error !== "string" || metadata.failureKind !== undefined && !isWorkflowFailureKind(metadata.failureKind) || metadata.failureCode !== undefined && !isWorkflowFailureCode(metadata.failureCode) || metadata.failureRecoverability !== undefined && !isWorkflowFailureRecoverability(metadata.failureRecoverability) || metadata.failureDisposition !== undefined && !isWorkflowFailureDisposition(metadata.failureDisposition) || metadata.failedToolNodeId !== undefined && typeof metadata.failedToolNodeId !== "string" || metadata.invocationCwd !== undefined && typeof metadata.invocationCwd !== "string" || metadata.workflowCwd !== undefined && typeof metadata.workflowCwd !== "string" || metadata.repositoryRoot !== undefined && typeof metadata.repositoryRoot !== "string" || metadata.gitWorktreeRoot !== undefined && typeof metadata.gitWorktreeRoot !== "string")
|
|
92138
92640
|
return;
|
|
92139
92641
|
const { origin, ...metadataWithoutOrigin } = metadata;
|
|
92140
92642
|
return {
|
|
92141
92643
|
...metadataWithoutOrigin,
|
|
92644
|
+
pendingStageMessages,
|
|
92142
92645
|
...isWorkflowActor(origin) ? { origin } : {}
|
|
92143
92646
|
};
|
|
92144
92647
|
}
|
|
92648
|
+
function serializePendingStageMessages(messages2) {
|
|
92649
|
+
return messages2.map((entry) => ({
|
|
92650
|
+
id: entry.id,
|
|
92651
|
+
runId: entry.runId,
|
|
92652
|
+
stageKey: entry.stageKey,
|
|
92653
|
+
...entry.stageId !== undefined ? { stageId: entry.stageId } : {},
|
|
92654
|
+
...entry.stageReplayKey !== undefined ? { stageReplayKey: entry.stageReplayKey } : {},
|
|
92655
|
+
...entry.senderRegistrationName !== undefined ? { senderRegistrationName: entry.senderRegistrationName } : {},
|
|
92656
|
+
...entry.senderReturnAddress !== undefined ? { senderReturnAddress: entry.senderReturnAddress } : {},
|
|
92657
|
+
from: {
|
|
92658
|
+
id: entry.from.id,
|
|
92659
|
+
...entry.from.name !== undefined ? { name: entry.from.name } : {},
|
|
92660
|
+
...entry.from.group !== undefined ? { group: entry.from.group } : {},
|
|
92661
|
+
...entry.from.cwd !== undefined ? { cwd: entry.from.cwd } : {},
|
|
92662
|
+
...entry.from.model !== undefined ? { model: entry.from.model } : {},
|
|
92663
|
+
...entry.from.pid !== undefined ? { pid: entry.from.pid } : {},
|
|
92664
|
+
...entry.from.startedAt !== undefined ? { startedAt: entry.from.startedAt } : {},
|
|
92665
|
+
...entry.from.lastActivity !== undefined ? { lastActivity: entry.from.lastActivity } : {},
|
|
92666
|
+
...entry.from.status !== undefined ? { status: entry.from.status } : {}
|
|
92667
|
+
},
|
|
92668
|
+
message: {
|
|
92669
|
+
id: entry.message.id,
|
|
92670
|
+
timestamp: entry.message.timestamp,
|
|
92671
|
+
...entry.message.replyTo !== undefined ? { replyTo: entry.message.replyTo } : {},
|
|
92672
|
+
...entry.message.expectsReply !== undefined ? { expectsReply: entry.message.expectsReply } : {},
|
|
92673
|
+
...entry.message.replyError !== undefined ? { replyError: entry.message.replyError } : {},
|
|
92674
|
+
...entry.message.source !== undefined ? { source: { ...entry.message.source } } : {},
|
|
92675
|
+
content: {
|
|
92676
|
+
text: entry.message.content.text,
|
|
92677
|
+
...entry.message.content.attachments !== undefined ? { attachments: entry.message.content.attachments.map((attachment) => ({ ...attachment })) } : {}
|
|
92678
|
+
}
|
|
92679
|
+
},
|
|
92680
|
+
queuedAt: entry.queuedAt,
|
|
92681
|
+
...entry.admissionOrder !== undefined ? { admissionOrder: entry.admissionOrder } : {},
|
|
92682
|
+
status: entry.status,
|
|
92683
|
+
...entry.deliveredAt !== undefined ? { deliveredAt: entry.deliveredAt } : {},
|
|
92684
|
+
...entry.undeliverableReason !== undefined ? { undeliverableReason: entry.undeliverableReason } : {},
|
|
92685
|
+
...entry.undeliverableNotificationId !== undefined ? { undeliverableNotificationId: entry.undeliverableNotificationId } : {},
|
|
92686
|
+
...entry.undeliverableNotifiedAt !== undefined ? { undeliverableNotifiedAt: entry.undeliverableNotifiedAt } : {}
|
|
92687
|
+
}));
|
|
92688
|
+
}
|
|
92689
|
+
function parsePendingStageMessages(value) {
|
|
92690
|
+
if (value === undefined)
|
|
92691
|
+
return [];
|
|
92692
|
+
if (!Array.isArray(value) || !value.every(isPendingStageMessage))
|
|
92693
|
+
return null;
|
|
92694
|
+
return value;
|
|
92695
|
+
}
|
|
92696
|
+
function isPendingStageMessage(value) {
|
|
92697
|
+
if (!isSerializableObject(value))
|
|
92698
|
+
return false;
|
|
92699
|
+
return typeof value.id === "string" && typeof value.runId === "string" && typeof value.stageKey === "string" && (value.stageId === undefined || typeof value.stageId === "string") && (value.stageReplayKey === undefined || typeof value.stageReplayKey === "string") && (value.senderRegistrationName === undefined || typeof value.senderRegistrationName === "string") && (value.senderReturnAddress === undefined || typeof value.senderReturnAddress === "string") && typeof value.queuedAt === "string" && (value.admissionOrder === undefined || typeof value.admissionOrder === "number" && Number.isSafeInteger(value.admissionOrder) && value.admissionOrder > 0) && (value.status === "queued" || value.status === "delivered" || value.status === "undeliverable") && (value.deliveredAt === undefined || typeof value.deliveredAt === "string") && (value.undeliverableReason === undefined || typeof value.undeliverableReason === "string") && (value.undeliverableNotificationId === undefined || typeof value.undeliverableNotificationId === "string") && (value.undeliverableNotifiedAt === undefined || typeof value.undeliverableNotifiedAt === "string") && isPendingStageSender(value.from) && isPendingStageIntercomMessage(value.message);
|
|
92700
|
+
}
|
|
92701
|
+
function isPendingStageSender(value) {
|
|
92702
|
+
return isSerializableObject(value) && typeof value.id === "string" && (value.name === undefined || typeof value.name === "string") && (value.group === undefined || typeof value.group === "string") && (value.cwd === undefined || typeof value.cwd === "string") && (value.model === undefined || typeof value.model === "string") && (value.pid === undefined || typeof value.pid === "number") && (value.startedAt === undefined || typeof value.startedAt === "number") && (value.lastActivity === undefined || typeof value.lastActivity === "number") && (value.status === undefined || typeof value.status === "string");
|
|
92703
|
+
}
|
|
92704
|
+
function isPendingStageIntercomMessage(value) {
|
|
92705
|
+
if (!isSerializableObject(value) || typeof value.id !== "string" || typeof value.timestamp !== "number")
|
|
92706
|
+
return false;
|
|
92707
|
+
if (value.replyTo !== undefined && typeof value.replyTo !== "string")
|
|
92708
|
+
return false;
|
|
92709
|
+
if (value.expectsReply !== undefined && typeof value.expectsReply !== "boolean")
|
|
92710
|
+
return false;
|
|
92711
|
+
if (value.replyError !== undefined && typeof value.replyError !== "string")
|
|
92712
|
+
return false;
|
|
92713
|
+
if (!isSerializableObject(value.content) || typeof value.content.text !== "string")
|
|
92714
|
+
return false;
|
|
92715
|
+
const attachments = value.content.attachments;
|
|
92716
|
+
if (attachments !== undefined && (!Array.isArray(attachments) || !attachments.every(isPendingStageAttachment)))
|
|
92717
|
+
return false;
|
|
92718
|
+
return value.source === undefined || isPendingStageSource(value.source);
|
|
92719
|
+
}
|
|
92720
|
+
function isPendingStageAttachment(value) {
|
|
92721
|
+
return isSerializableObject(value) && (value.type === "file" || value.type === "snippet" || value.type === "context") && typeof value.name === "string" && typeof value.content === "string" && (value.language === undefined || typeof value.language === "string");
|
|
92722
|
+
}
|
|
92723
|
+
function isPendingStageSource(value) {
|
|
92724
|
+
return isSerializableObject(value) && typeof value.subagentRunId === "string" && (value.subagentAgent === undefined || typeof value.subagentAgent === "string") && (value.subagentIndex === undefined || typeof value.subagentIndex === "number");
|
|
92725
|
+
}
|
|
92726
|
+
function isSerializableObject(value) {
|
|
92727
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
92728
|
+
}
|
|
92145
92729
|
function isWorkflowActor(value) {
|
|
92146
92730
|
return value === "user" || value === "agent";
|
|
92147
92731
|
}
|
|
@@ -92676,6 +93260,29 @@ class DbosDurableBackend {
|
|
|
92676
93260
|
await this.writeMetadata(handle.workflowId);
|
|
92677
93261
|
});
|
|
92678
93262
|
}
|
|
93263
|
+
async persistPendingStageMessages(workflowId, messages2, logicalRunId = workflowId) {
|
|
93264
|
+
let persisted = false;
|
|
93265
|
+
await this.enqueueWrite(async () => {
|
|
93266
|
+
if (!this.isWorkflowLoadable(workflowId))
|
|
93267
|
+
return;
|
|
93268
|
+
const handle = this.mem.getWorkflow(workflowId);
|
|
93269
|
+
const value = this.mem.toMetadata(workflowId);
|
|
93270
|
+
if (handle === undefined || value === undefined)
|
|
93271
|
+
return;
|
|
93272
|
+
const updatedAt = Math.max(Date.now(), handle.updatedAt + 1);
|
|
93273
|
+
const pendingStageMessages = replacePendingStageMessagesForRun(handle.pendingStageMessages ?? [], logicalRunId, messages2);
|
|
93274
|
+
const metadata = {
|
|
93275
|
+
...this.promptReservations.metadata(workflowId, value),
|
|
93276
|
+
pendingStageMessages,
|
|
93277
|
+
ownerExecutorId: this.executorId,
|
|
93278
|
+
updatedAt
|
|
93279
|
+
};
|
|
93280
|
+
await this.sdk.recordStepOutput(workflowId, metadataStepName(updatedAt), encodeMetadata(metadata));
|
|
93281
|
+
this.mem.registerWorkflow({ ...handle, pendingStageMessages, updatedAt });
|
|
93282
|
+
persisted = true;
|
|
93283
|
+
});
|
|
93284
|
+
return persisted;
|
|
93285
|
+
}
|
|
92679
93286
|
recordCheckpoint(checkpoint) {
|
|
92680
93287
|
if (!this.isWorkflowLoadable(checkpoint.workflowId))
|
|
92681
93288
|
return;
|
|
@@ -95378,6 +95985,10 @@ function withMidSessionResumePrompt(stage, enabled) {
|
|
|
95378
95985
|
});
|
|
95379
95986
|
return stage;
|
|
95380
95987
|
}
|
|
95988
|
+
function pendingStageIdForReplay(backend, workflowId, replayKey, stageName) {
|
|
95989
|
+
const candidates = new Set((backend.getWorkflow(workflowId)?.pendingStageMessages ?? []).filter((entry) => entry.stageReplayKey === replayKey || entry.stageReplayKey === undefined && entry.stageKey === stageName).map((entry) => entry.stageId).filter((stageId) => stageId !== undefined));
|
|
95990
|
+
return candidates.size === 1 ? candidates.values().next().value : undefined;
|
|
95991
|
+
}
|
|
95381
95992
|
function createDurableStagePrimitive(input2) {
|
|
95382
95993
|
return (name, options) => {
|
|
95383
95994
|
const replayKey = input2.nextReplayKey(name);
|
|
@@ -95389,13 +96000,12 @@ function createDurableStagePrimitive(input2) {
|
|
|
95389
96000
|
const session = input2.backend.getStageSession(input2.workflowId, replayKey);
|
|
95390
96001
|
const isMidSessionResume = session?.sessionFile !== undefined;
|
|
95391
96002
|
const topology = activeStageTopology(input2.backend, input2.workflowId, replayKey);
|
|
96003
|
+
const durableStageId = topology?.stageId ?? pendingStageIdForReplay(input2.backend, input2.workflowId, replayKey, name);
|
|
95392
96004
|
const liveOptions = {
|
|
95393
96005
|
...options ?? {},
|
|
95394
96006
|
durableReplayKey: replayKey,
|
|
95395
|
-
...
|
|
95396
|
-
|
|
95397
|
-
durableParentIds: [...topology.parentIds]
|
|
95398
|
-
} : {},
|
|
96007
|
+
...durableStageId !== undefined ? { durableStageId } : {},
|
|
96008
|
+
...topology !== undefined ? { durableParentIds: [...topology.parentIds] } : {},
|
|
95399
96009
|
...isMidSessionResume ? {
|
|
95400
96010
|
resumeFromSessionFile: session.sessionFile,
|
|
95401
96011
|
durableAccumulatedDurationMs: session.durationMs ?? 0
|
|
@@ -96093,6 +96703,7 @@ function appendStageStart(api, payload) {
|
|
|
96093
96703
|
name: payload.name,
|
|
96094
96704
|
parentIds: [...payload.parentIds],
|
|
96095
96705
|
...payload.model !== undefined ? { model: payload.model } : {},
|
|
96706
|
+
...payload.pendingStageDeliveryAvailable !== undefined ? { pendingStageDeliveryAvailable: payload.pendingStageDeliveryAvailable } : {},
|
|
96096
96707
|
...payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {},
|
|
96097
96708
|
...payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {},
|
|
96098
96709
|
...payload.replayed !== undefined ? { replayed: payload.replayed } : {},
|
|
@@ -96636,6 +97247,7 @@ function installCompactionHook(api, store2) {
|
|
|
96636
97247
|
stageId: stage.id,
|
|
96637
97248
|
name: stage.name,
|
|
96638
97249
|
parentIds: [...stage.parentIds],
|
|
97250
|
+
pendingStageDeliveryAvailable: stage.pendingStageDeliveryAvailable,
|
|
96639
97251
|
ts: stage.startedAt ?? now
|
|
96640
97252
|
});
|
|
96641
97253
|
}
|
|
@@ -97212,7 +97824,7 @@ function formatWorkflowLifecycleNoticeText(details) {
|
|
|
97212
97824
|
return `? Workflow "${workflowName}" needs input (run ${details.runId}).${prompt2} Respond: /workflow connect ${details.runId} to answer this run-level prompt.`;
|
|
97213
97825
|
}
|
|
97214
97826
|
const stage = details.stageName ?? details.stageId ?? "unknown";
|
|
97215
|
-
const responseHint = details.stageId && details.promptId ? `/workflow connect ${details.runId} or workflow({ action: "
|
|
97827
|
+
const responseHint = details.stageId && details.promptId ? `/workflow connect ${details.runId} or workflow({ action: "answer", runId: ${jsonString(details.runId)}, stageId: ${jsonString(details.stageId)}, promptId: ${jsonString(details.promptId)}, response: ... })` : `/workflow connect ${details.runId}`;
|
|
97216
97828
|
return `? Workflow "${workflowName}" needs input (run ${details.runId}, stage ${stage}).${prompt2} Respond: ${responseHint}.`;
|
|
97217
97829
|
}
|
|
97218
97830
|
function makeTerminalNotice(run, kind) {
|
|
@@ -98512,6 +99124,12 @@ function workflow(spec) {
|
|
|
98512
99124
|
return Object.freeze(branded);
|
|
98513
99125
|
}
|
|
98514
99126
|
|
|
99127
|
+
// dist/builtin/workflows/builtin/steering-context.ts
|
|
99128
|
+
var exports_steering_context = {};
|
|
99129
|
+
__export(exports_steering_context, {
|
|
99130
|
+
withSteeringPropagationContext: () => withSteeringPropagationContext
|
|
99131
|
+
});
|
|
99132
|
+
|
|
98515
99133
|
// dist/builtin/workflows/src/authoring/keep-context.ts
|
|
98516
99134
|
var KEEP_CONTEXT_OPEN_TAG = "<keepContext>";
|
|
98517
99135
|
var KEEP_CONTEXT_CLOSE_TAG = "</keepContext>";
|
|
@@ -98525,6 +99143,12 @@ ${KEEP_CONTEXT_CLOSE_TAG}`;
|
|
|
98525
99143
|
}
|
|
98526
99144
|
|
|
98527
99145
|
// dist/builtin/workflows/builtin/shared-prompts.ts
|
|
99146
|
+
var PENDING_STAGE_DELIVERY_GUIDANCE_LINES = [
|
|
99147
|
+
"Send material updates through Intercom to every affected workflow stage, including stages that have not started.",
|
|
99148
|
+
"Atomic queues messages for known pending stages addressed as `<runId>:<stageKey>` and delivers them when their sessions initialize."
|
|
99149
|
+
];
|
|
99150
|
+
var PENDING_STAGE_DELIVERY_GUIDANCE = PENDING_STAGE_DELIVERY_GUIDANCE_LINES.join(`
|
|
99151
|
+
`);
|
|
98528
99152
|
var STEERING_PROPAGATION_CONTRACT = [
|
|
98529
99153
|
"Steering propagation contract:",
|
|
98530
99154
|
"- Mid-run user messages (steering, follow-ups, resume text) are authoritative and may amend this run's objective or acceptance criteria. Adopt an amendment as required behavior from the moment you receive it.",
|
|
@@ -98532,6 +99156,7 @@ var STEERING_PROPAGATION_CONTRACT = [
|
|
|
98532
99156
|
"- Keep user-authored amendments visibly separate from your own observations, so later stages can tell a required clause from an agent proposal.",
|
|
98533
99157
|
"- Treat amendments inherited from an upstream stage as contract clauses. Cover them in acceptance and traceability work; never classify inherited user amendments as beyond_objective, unrequested scope, or speculative expansion.",
|
|
98534
99158
|
"- If an amendment is ambiguous, or conflicts with the launch contract or another amendment, resolve it before implementing: ask through `intercom` when a supervisor or originating stage is reachable, otherwise state the conflict in your report and implement the narrowest reading consistent with the launch contract.",
|
|
99159
|
+
...PENDING_STAGE_DELIVERY_GUIDANCE_LINES.map((line) => `- ${line}`),
|
|
98535
99160
|
"- Propagate nothing else this way. Guidance about how to work, tool preferences, and your own improvement ideas are not amendments; those follow the scope discipline contract."
|
|
98536
99161
|
].join(`
|
|
98537
99162
|
`);
|
|
@@ -106193,6 +106818,9 @@ class ScopedDurableBackend {
|
|
|
106193
106818
|
this.persistent = inner.persistent;
|
|
106194
106819
|
}
|
|
106195
106820
|
registerWorkflow(_handle) {}
|
|
106821
|
+
persistPendingStageMessages(workflowId, messages2, logicalRunId = workflowId) {
|
|
106822
|
+
return this.inner.persistPendingStageMessages(this.scope.rootWorkflowId, messages2, logicalRunId);
|
|
106823
|
+
}
|
|
106196
106824
|
recordCheckpoint(checkpoint) {
|
|
106197
106825
|
this.inner.recordCheckpoint(this.remap(checkpoint));
|
|
106198
106826
|
}
|
|
@@ -109530,6 +110158,7 @@ import { randomUUID as randomUUID16 } from "node:crypto";
|
|
|
109530
110158
|
|
|
109531
110159
|
// dist/builtin/workflows/src/shared/intercom-group.ts
|
|
109532
110160
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
110161
|
+
var DEFAULT_INTERCOM_GROUP = "default";
|
|
109533
110162
|
function workflowInvocationIntercomGroup(rootRunId) {
|
|
109534
110163
|
return `workflow:${rootRunId}`;
|
|
109535
110164
|
}
|
|
@@ -109539,6 +110168,12 @@ function normalizeAutoGroupSentinel(group) {
|
|
|
109539
110168
|
const sentinel = group.trim().toLowerCase();
|
|
109540
110169
|
return sentinel === "true" || sentinel === "auto" ? true : group;
|
|
109541
110170
|
}
|
|
110171
|
+
function normalizeGroup(value) {
|
|
110172
|
+
if (typeof value !== "string")
|
|
110173
|
+
return DEFAULT_INTERCOM_GROUP;
|
|
110174
|
+
const trimmed = value.trim();
|
|
110175
|
+
return trimmed.length > 0 ? trimmed : DEFAULT_INTERCOM_GROUP;
|
|
110176
|
+
}
|
|
109542
110177
|
function resolveStageGroup(stageOptions, workflowGroup) {
|
|
109543
110178
|
if (!stageOptions)
|
|
109544
110179
|
return workflowGroup;
|
|
@@ -109563,6 +110198,11 @@ function stageHasIntercomAccess(stageOptions) {
|
|
|
109563
110198
|
return false;
|
|
109564
110199
|
return true;
|
|
109565
110200
|
}
|
|
110201
|
+
function stageCanUseWorkflowPendingStageRoute(stageOptions, workflowGroup) {
|
|
110202
|
+
if (!stageHasIntercomAccess(stageOptions) || stageOptions?.group === true)
|
|
110203
|
+
return false;
|
|
110204
|
+
return normalizeGroup(resolveStageGroup(stageOptions, workflowGroup)) === normalizeGroup(workflowGroup);
|
|
110205
|
+
}
|
|
109566
110206
|
|
|
109567
110207
|
// dist/builtin/workflows/src/shared/budget-meter.ts
|
|
109568
110208
|
var usageFields = ["input", "output", "cacheRead", "cacheWrite", "cost"];
|
|
@@ -109817,9 +110457,9 @@ function createRunBudgetController(input2) {
|
|
|
109817
110457
|
function createParallelPrimitive(input2) {
|
|
109818
110458
|
return async (steps, options = {}) => {
|
|
109819
110459
|
input2.runtime.exit.throwIfWorkflowExitSelected();
|
|
109820
|
-
const
|
|
109821
|
-
const normalizedOptions =
|
|
109822
|
-
const normalizedSteps = steps.map(
|
|
110460
|
+
const normalizeGroup2 = (value) => value.group === undefined ? value : { ...value, group: normalizeAutoGroupSentinel(value.group) };
|
|
110461
|
+
const normalizedOptions = normalizeGroup2(options);
|
|
110462
|
+
const normalizedSteps = steps.map(normalizeGroup2);
|
|
109823
110463
|
const needsAutoGroup = normalizedOptions.group === true || normalizedSteps.some((step) => step.group === true);
|
|
109824
110464
|
const autoGroup = needsAutoGroup ? randomUUID16() : undefined;
|
|
109825
110465
|
const resolveAutoGroup = (value) => value.group === true && autoGroup ? { ...value, group: autoGroup } : value;
|
|
@@ -111790,7 +112430,7 @@ function createAdmittedToolExecutionTracker(options = {}) {
|
|
|
111790
112430
|
const inFlight = new Set;
|
|
111791
112431
|
const admissions = [];
|
|
111792
112432
|
const failures = [];
|
|
111793
|
-
let
|
|
112433
|
+
let nextAdmissionOrder2 = 0;
|
|
111794
112434
|
let state = "OPEN";
|
|
111795
112435
|
let closing;
|
|
111796
112436
|
const abandonment = Promise.withResolvers();
|
|
@@ -111841,7 +112481,7 @@ function createAdmittedToolExecutionTracker(options = {}) {
|
|
|
111841
112481
|
return { accepted: false, error, bindNode() {}, noteCancelled() {} };
|
|
111842
112482
|
}
|
|
111843
112483
|
const admission = {
|
|
111844
|
-
admissionOrder: ++
|
|
112484
|
+
admissionOrder: ++nextAdmissionOrder2,
|
|
111845
112485
|
nodeId: undefined,
|
|
111846
112486
|
failure: undefined,
|
|
111847
112487
|
cancelled: false,
|
|
@@ -113143,6 +113783,150 @@ function createReplayStageContext(input2) {
|
|
|
113143
113783
|
};
|
|
113144
113784
|
}
|
|
113145
113785
|
|
|
113786
|
+
// dist/builtin/workflows/src/durable/run-owner-backend.ts
|
|
113787
|
+
function durableRootRunIdForRun(runs, runId) {
|
|
113788
|
+
return reciprocalWorkflowRootRunId(new Map(runs.map((run2) => [run2.id, run2])), runId);
|
|
113789
|
+
}
|
|
113790
|
+
function durableBackendForRun(backend, runs, runId) {
|
|
113791
|
+
const rootRunId = durableRootRunIdForRun(runs, runId);
|
|
113792
|
+
if (rootRunId === undefined)
|
|
113793
|
+
return;
|
|
113794
|
+
const runById = new Map(runs.map((run2) => [run2.id, run2]));
|
|
113795
|
+
if (rootRunId === runId)
|
|
113796
|
+
return backend;
|
|
113797
|
+
const scopes = [];
|
|
113798
|
+
let current = runById.get(runId);
|
|
113799
|
+
while (current !== undefined && current.id !== rootRunId) {
|
|
113800
|
+
const parent = current.parentRunId === undefined ? undefined : runById.get(current.parentRunId);
|
|
113801
|
+
const boundary = parent?.stages.find((stage) => stage.id === current?.parentStageId);
|
|
113802
|
+
if (parent === undefined || boundary?.replayKey === undefined)
|
|
113803
|
+
return;
|
|
113804
|
+
scopes.push(boundary.replayKey);
|
|
113805
|
+
current = parent;
|
|
113806
|
+
}
|
|
113807
|
+
if (current?.id !== rootRunId)
|
|
113808
|
+
return;
|
|
113809
|
+
let view = backend;
|
|
113810
|
+
for (const scopePrefix of scopes.reverse()) {
|
|
113811
|
+
view = new ScopedDurableBackend(view, { rootWorkflowId: rootRunId, scopePrefix });
|
|
113812
|
+
}
|
|
113813
|
+
return view;
|
|
113814
|
+
}
|
|
113815
|
+
|
|
113816
|
+
// dist/builtin/workflows/src/shared/pending-stage-route-capability.ts
|
|
113817
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
113818
|
+
var routeCapabilities = new WeakMap;
|
|
113819
|
+
function workflowPendingStageRouteCapability(store2, runId) {
|
|
113820
|
+
let capabilities = routeCapabilities.get(store2);
|
|
113821
|
+
if (capabilities === undefined) {
|
|
113822
|
+
capabilities = new Map;
|
|
113823
|
+
routeCapabilities.set(store2, capabilities);
|
|
113824
|
+
}
|
|
113825
|
+
let capability = capabilities.get(runId);
|
|
113826
|
+
if (capability === undefined) {
|
|
113827
|
+
capability = randomUUID17();
|
|
113828
|
+
capabilities.set(runId, capability);
|
|
113829
|
+
}
|
|
113830
|
+
return capability;
|
|
113831
|
+
}
|
|
113832
|
+
|
|
113833
|
+
// dist/builtin/workflows/src/runs/foreground/pending-stage-delivery.ts
|
|
113834
|
+
var pendingDeliveryClaims = new WeakMap;
|
|
113835
|
+
function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageName3) {
|
|
113836
|
+
let resolveReady;
|
|
113837
|
+
let rejectReady;
|
|
113838
|
+
let readyPromise;
|
|
113839
|
+
let drainError;
|
|
113840
|
+
let drainPromise;
|
|
113841
|
+
const pendingReady = () => {
|
|
113842
|
+
if (readyPromise === undefined) {
|
|
113843
|
+
readyPromise = new Promise((resolve35, reject) => {
|
|
113844
|
+
resolveReady = resolve35;
|
|
113845
|
+
rejectReady = reject;
|
|
113846
|
+
});
|
|
113847
|
+
}
|
|
113848
|
+
return readyPromise;
|
|
113849
|
+
};
|
|
113850
|
+
return {
|
|
113851
|
+
routeCapability: workflowPendingStageRouteCapability(activeStore, runId),
|
|
113852
|
+
deliverPending(deliver) {
|
|
113853
|
+
if (drainPromise === undefined) {
|
|
113854
|
+
drainError = undefined;
|
|
113855
|
+
const attempt = deliverPendingStageMessages(activeStore, runId, stageId, stageName3, deliver);
|
|
113856
|
+
const drain2 = attempt.then(() => resolveReady?.(), (error) => {
|
|
113857
|
+
drainError = error;
|
|
113858
|
+
rejectReady?.(error);
|
|
113859
|
+
readyPromise = undefined;
|
|
113860
|
+
resolveReady = undefined;
|
|
113861
|
+
rejectReady = undefined;
|
|
113862
|
+
if (drainPromise === drain2)
|
|
113863
|
+
drainPromise = undefined;
|
|
113864
|
+
throw error;
|
|
113865
|
+
});
|
|
113866
|
+
drainPromise = drain2;
|
|
113867
|
+
}
|
|
113868
|
+
return drainPromise;
|
|
113869
|
+
},
|
|
113870
|
+
ready() {
|
|
113871
|
+
if (activeStore.pendingStageMessagesFor(runId, stageId).length === 0 && (stageId === stageName3 || activeStore.pendingStageMessagesFor(runId, stageName3).length === 0)) {
|
|
113872
|
+
return;
|
|
113873
|
+
}
|
|
113874
|
+
return drainError === undefined ? pendingReady() : Promise.reject(drainError);
|
|
113875
|
+
}
|
|
113876
|
+
};
|
|
113877
|
+
}
|
|
113878
|
+
async function deliverPendingStageMessages(activeStore, runId, stageId, stageName3, deliver) {
|
|
113879
|
+
const candidateIds = new Set([
|
|
113880
|
+
...activeStore.pendingStageMessagesFor(runId, stageId),
|
|
113881
|
+
...activeStore.pendingStageMessagesFor(runId, stageName3)
|
|
113882
|
+
].map((entry) => entry.id));
|
|
113883
|
+
const entries = (activeStore.runs().find((run2) => run2.id === runId)?.pendingStageMessages ?? []).map((entry, index) => ({ entry, index })).filter(({ entry }) => candidateIds.has(entry.id)).sort((left, right) => (left.entry.admissionOrder ?? left.index + 1) - (right.entry.admissionOrder ?? right.index + 1) || left.index - right.index).map(({ entry }) => entry);
|
|
113884
|
+
const rootBackend = getDurableBackend();
|
|
113885
|
+
const backend = durableBackendForRun(rootBackend, activeStore.runs(), runId);
|
|
113886
|
+
if (backend === undefined) {
|
|
113887
|
+
throw new Error(`atomic-workflows: workflow run ${runId} has no durable owner for pending-stage delivery`);
|
|
113888
|
+
}
|
|
113889
|
+
for (const entry of entries) {
|
|
113890
|
+
const releaseClaim = claimPendingDelivery(activeStore, runId, entry.stageKey, entry.id);
|
|
113891
|
+
if (releaseClaim === undefined)
|
|
113892
|
+
continue;
|
|
113893
|
+
try {
|
|
113894
|
+
await deliver(toPendingStageSender(entry), entry.message);
|
|
113895
|
+
if (!await activeStore.markPendingStageMessageDelivered(runId, entry.stageKey, entry.id, new Date().toISOString(), backend)) {
|
|
113896
|
+
throw new Error(`atomic-workflows: pending-stage message ${entry.id} changed during delivery`);
|
|
113897
|
+
}
|
|
113898
|
+
} finally {
|
|
113899
|
+
releaseClaim();
|
|
113900
|
+
}
|
|
113901
|
+
}
|
|
113902
|
+
}
|
|
113903
|
+
function claimPendingDelivery(store2, runId, stageKey, messageId) {
|
|
113904
|
+
let claims = pendingDeliveryClaims.get(store2);
|
|
113905
|
+
if (claims === undefined) {
|
|
113906
|
+
claims = new Set;
|
|
113907
|
+
pendingDeliveryClaims.set(store2, claims);
|
|
113908
|
+
}
|
|
113909
|
+
const key2 = JSON.stringify([runId, stageKey, messageId]);
|
|
113910
|
+
if (claims.has(key2))
|
|
113911
|
+
return;
|
|
113912
|
+
claims.add(key2);
|
|
113913
|
+
return () => {
|
|
113914
|
+
claims?.delete(key2);
|
|
113915
|
+
if (claims?.size === 0)
|
|
113916
|
+
pendingDeliveryClaims.delete(store2);
|
|
113917
|
+
};
|
|
113918
|
+
}
|
|
113919
|
+
function toPendingStageSender(entry) {
|
|
113920
|
+
return {
|
|
113921
|
+
...entry.from,
|
|
113922
|
+
cwd: entry.from.cwd ?? "",
|
|
113923
|
+
model: entry.from.model ?? "unknown",
|
|
113924
|
+
pid: entry.from.pid ?? 0,
|
|
113925
|
+
startedAt: entry.from.startedAt ?? entry.message.timestamp,
|
|
113926
|
+
lastActivity: entry.from.lastActivity ?? entry.message.timestamp
|
|
113927
|
+
};
|
|
113928
|
+
}
|
|
113929
|
+
|
|
113146
113930
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts
|
|
113147
113931
|
init_src();
|
|
113148
113932
|
|
|
@@ -113534,7 +114318,7 @@ function workflowSessionOptions(meta2) {
|
|
|
113534
114318
|
workflow: { runId: meta2.runId, stageId: meta2.stageId, stageName: meta2.stageName }
|
|
113535
114319
|
};
|
|
113536
114320
|
}
|
|
113537
|
-
function workflowOrchestrationContext(meta2, stageOptions) {
|
|
114321
|
+
function workflowOrchestrationContext(meta2, stageOptions, pendingStageDelivery) {
|
|
113538
114322
|
const base = {
|
|
113539
114323
|
kind: "workflow-stage",
|
|
113540
114324
|
workflowRunId: meta2.runId,
|
|
@@ -113543,11 +114327,12 @@ function workflowOrchestrationContext(meta2, stageOptions) {
|
|
|
113543
114327
|
constraints: { disableWorkflowTool: true }
|
|
113544
114328
|
};
|
|
113545
114329
|
const intercomGroup = stageHasIntercomAccess(stageOptions) ? resolveStageGroup(stageOptions, meta2.workflowIntercomGroup) : undefined;
|
|
113546
|
-
|
|
114330
|
+
const context = intercomGroup ? { ...base, intercomGroup } : base;
|
|
114331
|
+
return pendingStageDelivery === undefined ? context : { ...context, pendingStageDelivery };
|
|
113547
114332
|
}
|
|
113548
|
-
function stripWorkflowOnlyOptions(options, defaultSessionDir, meta2) {
|
|
114333
|
+
function stripWorkflowOnlyOptions(options, defaultSessionDir, meta2, pendingStageDelivery) {
|
|
113549
114334
|
const classification = workflowSessionOptions(meta2);
|
|
113550
|
-
const orchestrationContext = workflowOrchestrationContext(meta2, options);
|
|
114335
|
+
const orchestrationContext = workflowOrchestrationContext(meta2, options, pendingStageDelivery);
|
|
113551
114336
|
if (!options) {
|
|
113552
114337
|
return defaultSessionDir === undefined ? { orchestrationContext } : {
|
|
113553
114338
|
orchestrationContext,
|
|
@@ -114913,7 +115698,7 @@ class StageSessionController {
|
|
|
114913
115698
|
});
|
|
114914
115699
|
let created;
|
|
114915
115700
|
try {
|
|
114916
|
-
created = this.opts.adapters.agentSession ? await this.opts.adapters.agentSession.create(stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta), {
|
|
115701
|
+
created = this.opts.adapters.agentSession ? await this.opts.adapters.agentSession.create(stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta, this.opts.pendingStageDelivery), {
|
|
114917
115702
|
...this.meta,
|
|
114918
115703
|
stageOptions,
|
|
114919
115704
|
...this.sharedOrchestrationContext !== undefined ? { orchestrationContext: this.sharedOrchestrationContext } : {}
|
|
@@ -114930,10 +115715,12 @@ class StageSessionController {
|
|
|
114930
115715
|
throw this.staleCreationReason(startGeneration);
|
|
114931
115716
|
}
|
|
114932
115717
|
const session = attachCreatedStageSession(created, this.disposed, this.opts.stageName, (result) => this.attachSession(result));
|
|
114933
|
-
|
|
114934
|
-
|
|
115718
|
+
const attachedSession = session instanceof Promise ? await session : session;
|
|
115719
|
+
const pendingStageDeliveryReady = this.sharedOrchestrationContext?.pendingStageDelivery?.ready();
|
|
115720
|
+
if (pendingStageDeliveryReady !== undefined)
|
|
115721
|
+
await pendingStageDeliveryReady;
|
|
114935
115722
|
await this.opts.onSessionReady?.();
|
|
114936
|
-
return
|
|
115723
|
+
return attachedSession;
|
|
114937
115724
|
}
|
|
114938
115725
|
attachSession(created) {
|
|
114939
115726
|
const result = normalizeSessionCreateResult(created);
|
|
@@ -115685,6 +116472,12 @@ function createWorkflowStageFactory(input2) {
|
|
|
115685
116472
|
const replaySource = replayDecision.kind === "replay" ? replayDecision.source : undefined;
|
|
115686
116473
|
const executeReplaySource = replayDecision.kind === "execute" ? replayDecision.source : undefined;
|
|
115687
116474
|
const shouldReplay = replaySource !== undefined;
|
|
116475
|
+
const stageOptionsForContext = executeReplaySource?.sessionFile === undefined ? options : {
|
|
116476
|
+
...options ?? {},
|
|
116477
|
+
context: options?.context ?? "fork",
|
|
116478
|
+
forkFromSessionFile: options?.forkFromSessionFile ?? executeReplaySource.sessionFile
|
|
116479
|
+
};
|
|
116480
|
+
const pendingStageDeliveryAvailable = stageCanUseWorkflowPendingStageRoute(stageOptionsForContext, input2.workflowIntercomGroup);
|
|
115688
116481
|
const stageSnapshot = {
|
|
115689
116482
|
id: stageId,
|
|
115690
116483
|
name,
|
|
@@ -115692,6 +116485,7 @@ function createWorkflowStageFactory(input2) {
|
|
|
115692
116485
|
status: shouldReplay ? "completed" : "pending",
|
|
115693
116486
|
parentIds: Object.freeze(parentIds),
|
|
115694
116487
|
toolEvents: [],
|
|
116488
|
+
pendingStageDeliveryAvailable,
|
|
115695
116489
|
...shouldReplay ? {
|
|
115696
116490
|
startedAt: Date.now(),
|
|
115697
116491
|
endedAt: Date.now(),
|
|
@@ -115720,11 +116514,6 @@ function createWorkflowStageFactory(input2) {
|
|
|
115720
116514
|
throwIfWorkflowExitSelected: input2.exit.throwIfWorkflowExitSelected
|
|
115721
116515
|
});
|
|
115722
116516
|
}
|
|
115723
|
-
const stageOptionsForContext = executeReplaySource?.sessionFile === undefined ? options : {
|
|
115724
|
-
...options ?? {},
|
|
115725
|
-
context: options?.context ?? "fork",
|
|
115726
|
-
forkFromSessionFile: options?.forkFromSessionFile ?? executeReplaySource.sessionFile
|
|
115727
|
-
};
|
|
115728
116517
|
const applyModelFallbackMeta = (meta2) => {
|
|
115729
116518
|
if (meta2.model !== undefined)
|
|
115730
116519
|
stageSnapshot.model = meta2.model;
|
|
@@ -115762,6 +116551,9 @@ function createWorkflowStageFactory(input2) {
|
|
|
115762
116551
|
workflowIntercomGroup: input2.workflowIntercomGroup,
|
|
115763
116552
|
signal: input2.signal,
|
|
115764
116553
|
stageOptions: stageOptionsForContext,
|
|
116554
|
+
...pendingStageDeliveryAvailable ? {
|
|
116555
|
+
pendingStageDelivery: createWorkflowPendingStageDelivery(input2.activeStore, input2.runId, stageId, name)
|
|
116556
|
+
} : {},
|
|
115765
116557
|
models: input2.opts.models,
|
|
115766
116558
|
executionMode: input2.opts.executionMode,
|
|
115767
116559
|
defaultSessionDir: input2.opts.defaultSessionDir,
|
|
@@ -115887,6 +116679,7 @@ function createWorkflowStageFactory(input2) {
|
|
|
115887
116679
|
name,
|
|
115888
116680
|
parentIds: stageSnapshot.parentIds,
|
|
115889
116681
|
...stageReplayFields(stageSnapshot),
|
|
116682
|
+
pendingStageDeliveryAvailable,
|
|
115890
116683
|
ts: stageSnapshot.startedAt ?? Date.now()
|
|
115891
116684
|
});
|
|
115892
116685
|
};
|
|
@@ -116249,6 +117042,9 @@ async function run(def, inputs, opts = {}) {
|
|
|
116249
117042
|
status: "running",
|
|
116250
117043
|
stages: [],
|
|
116251
117044
|
toolNodes: [],
|
|
117045
|
+
pendingStageMessages: [
|
|
117046
|
+
...pendingStageMessagesForDurableRun(rootBackend, runId, opts.parentRun?.rootRunId ?? runId)
|
|
117047
|
+
],
|
|
116252
117048
|
startedAt: Date.now(),
|
|
116253
117049
|
...opts.parentRun !== undefined ? {
|
|
116254
117050
|
parentRunId: opts.parentRun.runId,
|
|
@@ -116822,8 +117618,8 @@ var runWorkflow = () => {
|
|
|
116822
117618
|
};
|
|
116823
117619
|
|
|
116824
117620
|
// dist/builtin/workflows/src/extension/workflow-module-loader.ts
|
|
116825
|
-
var WORKFLOWS_MODULE_SPECIFIER = "@bastani/workflows";
|
|
116826
|
-
var
|
|
117621
|
+
var WORKFLOWS_MODULE_SPECIFIER = "@bastani/atomic/workflows";
|
|
117622
|
+
var LEGACY_WORKFLOWS_MODULE_SPECIFIER = "@bastani/workflows";
|
|
116827
117623
|
var TYPEBOX_MODULE_SPECIFIER = "typebox";
|
|
116828
117624
|
var WORKFLOWS_SDK_MODULE = {
|
|
116829
117625
|
...exports_sdk_surface
|
|
@@ -116842,19 +117638,27 @@ var WORKFLOWS_BUILTIN_MODULE = {
|
|
|
116842
117638
|
var TYPEBOX_MODULE = {
|
|
116843
117639
|
...typeboxModule
|
|
116844
117640
|
};
|
|
117641
|
+
function createWorkflowVirtualModules(moduleSpecifier) {
|
|
117642
|
+
const builtinModuleSpecifier = `${moduleSpecifier}/builtin`;
|
|
117643
|
+
return {
|
|
117644
|
+
[moduleSpecifier]: WORKFLOWS_SDK_MODULE,
|
|
117645
|
+
[builtinModuleSpecifier]: WORKFLOWS_BUILTIN_MODULE,
|
|
117646
|
+
[`${builtinModuleSpecifier}/adversarial-verification`]: { default: adversarial_verification_default },
|
|
117647
|
+
[`${builtinModuleSpecifier}/classify-and-act`]: { default: classify_and_act_default },
|
|
117648
|
+
[`${builtinModuleSpecifier}/fan-out-and-synthesize`]: { default: fan_out_and_synthesize_default },
|
|
117649
|
+
[`${builtinModuleSpecifier}/generate-and-filter`]: { default: generate_and_filter_default },
|
|
117650
|
+
[`${builtinModuleSpecifier}/goal`]: { default: goal_default },
|
|
117651
|
+
[`${builtinModuleSpecifier}/loop-until-done`]: { default: loop_until_done_default },
|
|
117652
|
+
[`${builtinModuleSpecifier}/open-claude-design`]: { default: open_claude_design_default },
|
|
117653
|
+
[`${builtinModuleSpecifier}/ralph`]: { default: ralph_default },
|
|
117654
|
+
[`${builtinModuleSpecifier}/tournament`]: { default: tournament_default },
|
|
117655
|
+
[`${builtinModuleSpecifier}/steering-context`]: exports_steering_context
|
|
117656
|
+
};
|
|
117657
|
+
}
|
|
116845
117658
|
var WORKFLOWS_VIRTUAL_MODULES = {
|
|
116846
|
-
|
|
116847
|
-
|
|
116848
|
-
[TYPEBOX_MODULE_SPECIFIER]: TYPEBOX_MODULE
|
|
116849
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/adversarial-verification`]: { default: adversarial_verification_default },
|
|
116850
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/classify-and-act`]: { default: classify_and_act_default },
|
|
116851
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/fan-out-and-synthesize`]: { default: fan_out_and_synthesize_default },
|
|
116852
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/generate-and-filter`]: { default: generate_and_filter_default },
|
|
116853
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/goal`]: { default: goal_default },
|
|
116854
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/loop-until-done`]: { default: loop_until_done_default },
|
|
116855
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/open-claude-design`]: { default: open_claude_design_default },
|
|
116856
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/ralph`]: { default: ralph_default },
|
|
116857
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/tournament`]: { default: tournament_default }
|
|
117659
|
+
...createWorkflowVirtualModules(WORKFLOWS_MODULE_SPECIFIER),
|
|
117660
|
+
...createWorkflowVirtualModules(LEGACY_WORKFLOWS_MODULE_SPECIFIER),
|
|
117661
|
+
[TYPEBOX_MODULE_SPECIFIER]: TYPEBOX_MODULE
|
|
116858
117662
|
};
|
|
116859
117663
|
var workflowModuleLoader = createJiti2(import.meta.url, {
|
|
116860
117664
|
moduleCache: false,
|
|
@@ -117499,27 +118303,6 @@ function ensurePostMortemStageHandle(runId, stage, deps) {
|
|
|
117499
118303
|
const handle = deps.registry.getOrCreateDetached(runId, stage.id, () => createPostMortemStageHandle(runId, stage, sessionFile, adapters, deps.cwd, deps.defaultSessionDir));
|
|
117500
118304
|
return { ok: true, handle };
|
|
117501
118305
|
}
|
|
117502
|
-
function acquirePostMortemStageHandle(runId, stage, deps) {
|
|
117503
|
-
if (!TERMINAL_POSTMORTEM_STATUSES.has(stage.status))
|
|
117504
|
-
return { ok: false, reason: "not_terminal" };
|
|
117505
|
-
const existing = deps.registry.peek(runId, stage.id);
|
|
117506
|
-
if (existing !== undefined && existing.isDisposed !== true) {
|
|
117507
|
-
return {
|
|
117508
|
-
ok: true,
|
|
117509
|
-
lease: deps.registry.acquireDetached(runId, stage.id, () => existing)
|
|
117510
|
-
};
|
|
117511
|
-
}
|
|
117512
|
-
if (deps.adapters?.agentSession === undefined)
|
|
117513
|
-
return { ok: false, reason: "no_adapter" };
|
|
117514
|
-
const sessionFile = stage.sessionFile;
|
|
117515
|
-
if (typeof sessionFile !== "string" || sessionFile.length === 0)
|
|
117516
|
-
return { ok: false, reason: "no_session" };
|
|
117517
|
-
if (!isReopenableSessionTranscript(sessionFile))
|
|
117518
|
-
return { ok: false, reason: "invalid_session" };
|
|
117519
|
-
const adapters = deps.adapters;
|
|
117520
|
-
const lease = deps.registry.acquireDetached(runId, stage.id, () => createPostMortemStageHandle(runId, stage, sessionFile, adapters, deps.cwd, deps.defaultSessionDir));
|
|
117521
|
-
return { ok: true, lease };
|
|
117522
|
-
}
|
|
117523
118306
|
function createPostMortemStageHandle(runId, stage, sessionFile, adapters, cwd, defaultSessionDir) {
|
|
117524
118307
|
const context = createStageContext2({
|
|
117525
118308
|
runId,
|
|
@@ -118249,7 +119032,7 @@ function formatWorkflowHeartbeatNoticeText(details) {
|
|
|
118249
119032
|
const workflowName = escapeQuotedText3(details.workflowName);
|
|
118250
119033
|
const elapsed = formatWorkflowHeartbeatElapsed(details);
|
|
118251
119034
|
const cadence = formatWorkflowHeartbeatCadence(details.intervalMinutes);
|
|
118252
|
-
return `${WORKFLOW_HEARTBEAT_GLYPH} Workflow "${workflowName}" heartbeat (run ${details.runId}) — still running` + `${elapsed === undefined ? "" : ` after ${elapsed}`}, on a ${cadence} cadence. ` + "This is a periodic alignment check
|
|
119035
|
+
return `${WORKFLOW_HEARTBEAT_GLYPH} Workflow "${workflowName}" heartbeat (run ${details.runId}) — still running` + `${elapsed === undefined ? "" : ` after ${elapsed}`}, on a ${cadence} cadence. ` + "This is a periodic alignment check. Review whether the run is still on goal. " + "When steering or communication is useful, use Intercom. Consider the expanded workflow topology and match " + "each update's reach to its impact: send a local update to its affected stage; when shared scope or acceptance " + "criteria change, send the same authoritative Intercom update to every relevant live and known unstarted " + "`<runId>:<stageKey>`, including each worker-to-reviewer loop. Intercom delivers immediately to live stages and " + "queues updates for known stages that have not started, delivering them before their first model turn, so workers " + "and reviewers begin with one consistent contract. " + "Use `ask` once the target has a live session that can reply. " + "Use workflow pause, resume, interrupt, or quit for run control. " + "Continue the progressing run when no intervention is needed, or ask the user when a decision is needed. " + `Inspect: /workflow status ${details.runId}`;
|
|
118253
119036
|
}
|
|
118254
119037
|
function registerWorkflowHeartbeatRenderer(options) {
|
|
118255
119038
|
const register = options.registerMessageRenderer;
|
|
@@ -119481,6 +120264,241 @@ function createWorkflowExtensionRuntimeState(pi, adapters, resolveCwd = () => pi
|
|
|
119481
120264
|
};
|
|
119482
120265
|
}
|
|
119483
120266
|
|
|
120267
|
+
// dist/builtin/workflows/src/extension/pending-stage-intercom.ts
|
|
120268
|
+
var PENDING_STAGE_ROUTE_EVENT = "atomic:workflow-pending-stage-route";
|
|
120269
|
+
var PENDING_STAGE_MESSAGE_EVENT = "atomic:workflow-pending-stage-message";
|
|
120270
|
+
var PENDING_STAGE_UNDELIVERABLE_EVENT = "atomic:workflow-pending-stage-undeliverable";
|
|
120271
|
+
var PENDING_STAGE_ASK_REFUSAL = "Cannot ask a workflow stage whose session has not initialized. Use send; Atomic will queue the message until the stage session initializes.";
|
|
120272
|
+
function registerPendingStageIntercomBridge(pi, activeStore) {
|
|
120273
|
+
let disposed = false;
|
|
120274
|
+
let sweepPromise = Promise.resolve();
|
|
120275
|
+
const notifyUndeliverable = async (entry, reason, notificationId) => {
|
|
120276
|
+
const payload = {
|
|
120277
|
+
handled: false,
|
|
120278
|
+
runId: entry.runId,
|
|
120279
|
+
senderId: entry.from.id,
|
|
120280
|
+
...entry.senderRegistrationName === undefined ? {} : { senderRegistrationName: entry.senderRegistrationName },
|
|
120281
|
+
...entry.senderReturnAddress === undefined ? {} : { senderReturnAddress: entry.senderReturnAddress },
|
|
120282
|
+
messageId: entry.message.id,
|
|
120283
|
+
notificationId,
|
|
120284
|
+
reason
|
|
120285
|
+
};
|
|
120286
|
+
pi.events?.emit?.(PENDING_STAGE_UNDELIVERABLE_EVENT, payload);
|
|
120287
|
+
return payload.handled && await payload.completion === true;
|
|
120288
|
+
};
|
|
120289
|
+
const announceRoutes = () => {
|
|
120290
|
+
if (disposed)
|
|
120291
|
+
return;
|
|
120292
|
+
const runs = activeStore.runs();
|
|
120293
|
+
for (const run2 of runs) {
|
|
120294
|
+
const rootRunId = durableRootRunIdForRun(runs, run2.id);
|
|
120295
|
+
if (rootRunId === undefined)
|
|
120296
|
+
continue;
|
|
120297
|
+
pi.events?.emit?.(PENDING_STAGE_ROUTE_EVENT, {
|
|
120298
|
+
runId: run2.id,
|
|
120299
|
+
group: workflowInvocationIntercomGroup(rootRunId),
|
|
120300
|
+
capability: workflowPendingStageRouteCapability(activeStore, run2.id)
|
|
120301
|
+
});
|
|
120302
|
+
}
|
|
120303
|
+
sweepPromise = sweepPromise.then(() => settleUndeliverablePendingStageMessages(activeStore, notifyUndeliverable)).then(() => {
|
|
120304
|
+
return;
|
|
120305
|
+
}).catch((error) => console.warn("atomic-workflows: pending stage delivery sweep failed", error));
|
|
120306
|
+
};
|
|
120307
|
+
const unsubscribeStore = activeStore.subscribeInvalidation(announceRoutes);
|
|
120308
|
+
announceRoutes();
|
|
120309
|
+
const subscription = pi.events?.on?.(PENDING_STAGE_MESSAGE_EVENT, (payload) => {
|
|
120310
|
+
if (disposed || !isPendingStageMessageEvent(payload) || payload.handled)
|
|
120311
|
+
return;
|
|
120312
|
+
const runs = activeStore.runs();
|
|
120313
|
+
const run2 = runs.find((candidate) => candidate.id === payload.runId);
|
|
120314
|
+
if (run2 === undefined)
|
|
120315
|
+
return;
|
|
120316
|
+
const rootRunId = durableRootRunIdForRun(runs, run2.id);
|
|
120317
|
+
if (rootRunId === undefined)
|
|
120318
|
+
return;
|
|
120319
|
+
if (payload.live === true) {
|
|
120320
|
+
if (knownLiveStage(run2, payload.stageKey) === undefined)
|
|
120321
|
+
return;
|
|
120322
|
+
payload.handled = true;
|
|
120323
|
+
payload.completion = validateLiveDelivery(activeStore, payload);
|
|
120324
|
+
return;
|
|
120325
|
+
}
|
|
120326
|
+
const stage = knownUninitializedStage(run2, payload.stageKey);
|
|
120327
|
+
if (stage === undefined)
|
|
120328
|
+
return;
|
|
120329
|
+
payload.handled = true;
|
|
120330
|
+
payload.completion = queueAndPersist(activeStore, payload, workflowInvocationIntercomGroup(rootRunId), stage.pendingStageDeliveryAvailable === true);
|
|
120331
|
+
});
|
|
120332
|
+
const dispose2 = () => {
|
|
120333
|
+
disposed = true;
|
|
120334
|
+
unsubscribeStore();
|
|
120335
|
+
if (typeof subscription === "function")
|
|
120336
|
+
subscription();
|
|
120337
|
+
};
|
|
120338
|
+
pi.on?.("session_shutdown", dispose2);
|
|
120339
|
+
return dispose2;
|
|
120340
|
+
}
|
|
120341
|
+
function isPendingStageMessageEvent(value) {
|
|
120342
|
+
if (typeof value !== "object" || value === null)
|
|
120343
|
+
return false;
|
|
120344
|
+
const event = value;
|
|
120345
|
+
return typeof event.handled === "boolean" && (event.live === undefined || typeof event.live === "boolean") && typeof event.runId === "string" && typeof event.stageKey === "string" && typeof event.from?.id === "string" && (event.from.name === undefined || typeof event.from.name === "string") && (event.senderRegistrationName === undefined || typeof event.senderRegistrationName === "string") && (event.senderReturnAddress === undefined || typeof event.senderReturnAddress === "string") && typeof event.message?.id === "string" && typeof event.message.timestamp === "number" && typeof event.message.content?.text === "string";
|
|
120346
|
+
}
|
|
120347
|
+
function knownLiveStage(run2, stageKey) {
|
|
120348
|
+
const exactIds = run2.stages.filter((stage) => stage.id === stageKey);
|
|
120349
|
+
const candidates = exactIds.length > 0 ? exactIds : run2.stages.filter((stage) => stage.name === stageKey);
|
|
120350
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
120351
|
+
}
|
|
120352
|
+
async function validateLiveDelivery(activeStore, event) {
|
|
120353
|
+
const result = await activeStore.validateLiveStageMessage({
|
|
120354
|
+
runId: event.runId,
|
|
120355
|
+
stageKey: event.stageKey,
|
|
120356
|
+
from: event.from,
|
|
120357
|
+
message: event.message,
|
|
120358
|
+
queuedAt: new Date().toISOString()
|
|
120359
|
+
});
|
|
120360
|
+
if (result === undefined)
|
|
120361
|
+
return { outcome: "refused", reason: "Session not found" };
|
|
120362
|
+
if (result.outcome === "forward" || result.outcome === "delivered" || result.outcome === "queued")
|
|
120363
|
+
return result;
|
|
120364
|
+
if (result.outcome === "undeliverable") {
|
|
120365
|
+
return { outcome: "refused", reason: result.reason ?? "Pending-stage delivery was refused" };
|
|
120366
|
+
}
|
|
120367
|
+
return {
|
|
120368
|
+
outcome: "refused",
|
|
120369
|
+
reason: `Intercom message ID '${result.messageId}' conflicts with the durable identity for ${event.runId}:${event.stageKey}`,
|
|
120370
|
+
reasonCode: "message_id_conflict"
|
|
120371
|
+
};
|
|
120372
|
+
}
|
|
120373
|
+
async function queueAndPersist(activeStore, event, runGroup, pendingStageDeliveryAvailable) {
|
|
120374
|
+
if (event.message.expectsReply === true) {
|
|
120375
|
+
return { outcome: "refused", reason: PENDING_STAGE_ASK_REFUSAL };
|
|
120376
|
+
}
|
|
120377
|
+
if (!pendingStageDeliveryAvailable) {
|
|
120378
|
+
return {
|
|
120379
|
+
outcome: "refused",
|
|
120380
|
+
reason: `Workflow stage ${event.runId}:${event.stageKey} cannot receive Intercom messages before startup`
|
|
120381
|
+
};
|
|
120382
|
+
}
|
|
120383
|
+
const request = {
|
|
120384
|
+
runId: event.runId,
|
|
120385
|
+
stageKey: event.stageKey,
|
|
120386
|
+
from: event.from,
|
|
120387
|
+
...event.senderRegistrationName === undefined ? {} : { senderRegistrationName: event.senderRegistrationName },
|
|
120388
|
+
...event.senderReturnAddress === undefined ? {} : { senderReturnAddress: event.senderReturnAddress },
|
|
120389
|
+
message: event.message,
|
|
120390
|
+
queuedAt: new Date().toISOString()
|
|
120391
|
+
};
|
|
120392
|
+
const rootBackend = getDurableBackend();
|
|
120393
|
+
const backend = durableBackendForRun(rootBackend, activeStore.runs(), event.runId);
|
|
120394
|
+
if (backend === undefined)
|
|
120395
|
+
return { outcome: "refused", reason: "Session not found" };
|
|
120396
|
+
const result = await activeStore.queueStageMessage(request, event.from.group, runGroup, backend);
|
|
120397
|
+
if (result === undefined)
|
|
120398
|
+
return { outcome: "refused", reason: "Session not found" };
|
|
120399
|
+
if (!result.ok) {
|
|
120400
|
+
if (result.reason === "capacity") {
|
|
120401
|
+
return {
|
|
120402
|
+
outcome: "refused",
|
|
120403
|
+
reason: `Pending stage message queue is full (limit ${result.limit}) for ${result.runId}:${result.stageKey}`
|
|
120404
|
+
};
|
|
120405
|
+
}
|
|
120406
|
+
if (result.reason === "message_id_conflict") {
|
|
120407
|
+
return {
|
|
120408
|
+
outcome: "refused",
|
|
120409
|
+
reason: `Intercom message ID '${result.messageId}' was already queued for ${result.runId}:${result.stageKey} with a different target, sender, or payload`
|
|
120410
|
+
};
|
|
120411
|
+
}
|
|
120412
|
+
return { outcome: "refused", reason: "Target workflow run is in a different intercom group" };
|
|
120413
|
+
}
|
|
120414
|
+
if (result.entry.status === "delivered")
|
|
120415
|
+
return { outcome: "delivered" };
|
|
120416
|
+
if (result.entry.status === "undeliverable") {
|
|
120417
|
+
return {
|
|
120418
|
+
outcome: "refused",
|
|
120419
|
+
reason: result.entry.undeliverableReason ?? "Pending-stage delivery was refused"
|
|
120420
|
+
};
|
|
120421
|
+
}
|
|
120422
|
+
if (result.position === undefined)
|
|
120423
|
+
return { outcome: "refused", reason: "Pending-stage delivery was refused" };
|
|
120424
|
+
return { outcome: "queued", position: result.position };
|
|
120425
|
+
}
|
|
120426
|
+
function knownUninitializedStage(run2, stageKey) {
|
|
120427
|
+
const exactIds = run2.stages.filter((stage2) => stage2.id === stageKey);
|
|
120428
|
+
const candidates = exactIds.length > 0 ? exactIds : run2.stages.filter((stage2) => stage2.name === stageKey);
|
|
120429
|
+
if (candidates.length !== 1)
|
|
120430
|
+
return;
|
|
120431
|
+
const stage = candidates[0];
|
|
120432
|
+
return (stage.status === "pending" || stage.status === "running") && stage.sessionId === undefined && stage.sessionFile === undefined ? stage : undefined;
|
|
120433
|
+
}
|
|
120434
|
+
function pendingStageDestination(run2, entry) {
|
|
120435
|
+
if (entry.stageId !== undefined) {
|
|
120436
|
+
const candidates2 = run2.stages.filter((stage) => stage.id === entry.stageId);
|
|
120437
|
+
return candidates2.length === 1 ? candidates2[0] : undefined;
|
|
120438
|
+
}
|
|
120439
|
+
if (entry.stageReplayKey !== undefined) {
|
|
120440
|
+
const candidates2 = run2.stages.filter((stage) => stage.replayKey === entry.stageReplayKey);
|
|
120441
|
+
return candidates2.length === 1 ? candidates2[0] : undefined;
|
|
120442
|
+
}
|
|
120443
|
+
const exactIds = run2.stages.filter((stage) => stage.id === entry.stageKey);
|
|
120444
|
+
const candidates = exactIds.length > 0 ? exactIds : run2.stages.filter((stage) => stage.name === entry.stageKey);
|
|
120445
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
120446
|
+
}
|
|
120447
|
+
function pendingStageUndeliverableReason(run2, entry) {
|
|
120448
|
+
const stage = pendingStageDestination(run2, entry);
|
|
120449
|
+
if (run2.status === "cancelled") {
|
|
120450
|
+
return `Workflow run ${run2.id} terminated with status cancelled before stage ${entry.stageKey} started`;
|
|
120451
|
+
}
|
|
120452
|
+
if (stage?.status === "skipped") {
|
|
120453
|
+
return `Workflow stage ${entry.stageKey} was skipped${stage.skippedReason ? ` (${stage.skippedReason})` : ""}`;
|
|
120454
|
+
}
|
|
120455
|
+
if (isTerminalRunStatus(run2.status)) {
|
|
120456
|
+
return `Workflow run ${run2.id} terminated with status ${run2.status} before stage ${entry.stageKey} started`;
|
|
120457
|
+
}
|
|
120458
|
+
return;
|
|
120459
|
+
}
|
|
120460
|
+
function needsUndeliverableSettlement(run2, entry) {
|
|
120461
|
+
if (entry.status === "queued")
|
|
120462
|
+
return pendingStageUndeliverableReason(run2, entry) !== undefined;
|
|
120463
|
+
return entry.status === "undeliverable" && entry.undeliverableNotificationId !== undefined && entry.undeliverableNotifiedAt === undefined && entry.undeliverableReason !== undefined;
|
|
120464
|
+
}
|
|
120465
|
+
async function settleUndeliverablePendingStageMessages(activeStore, notify2) {
|
|
120466
|
+
const runs = activeStore.runs();
|
|
120467
|
+
if (!runs.some((run2) => run2.pendingStageMessages?.some((entry) => needsUndeliverableSettlement(run2, entry)))) {
|
|
120468
|
+
return 0;
|
|
120469
|
+
}
|
|
120470
|
+
let settled = 0;
|
|
120471
|
+
const rootBackend = getDurableBackend();
|
|
120472
|
+
for (const run2 of runs) {
|
|
120473
|
+
const backend = durableBackendForRun(rootBackend, runs, run2.id);
|
|
120474
|
+
if (backend === undefined) {
|
|
120475
|
+
throw new Error(`atomic-workflows: workflow run ${run2.id} has no durable owner for pending-stage settlement`);
|
|
120476
|
+
}
|
|
120477
|
+
for (const snapshotEntry of run2.pendingStageMessages ?? []) {
|
|
120478
|
+
let entry = snapshotEntry;
|
|
120479
|
+
if (entry.status === "queued") {
|
|
120480
|
+
const reason = pendingStageUndeliverableReason(run2, entry);
|
|
120481
|
+
if (reason === undefined)
|
|
120482
|
+
continue;
|
|
120483
|
+
if (await activeStore.markPendingStageMessageUndeliverable(run2.id, entry.stageKey, entry.id, reason, backend)) {
|
|
120484
|
+
settled += 1;
|
|
120485
|
+
}
|
|
120486
|
+
const currentRun2 = activeStore.runs().find((candidate) => candidate.id === run2.id);
|
|
120487
|
+
const currentEntry = currentRun2?.pendingStageMessages?.find((candidate) => candidate.stageKey === entry.stageKey && candidate.id === entry.id);
|
|
120488
|
+
if (currentEntry === undefined)
|
|
120489
|
+
continue;
|
|
120490
|
+
entry = currentEntry;
|
|
120491
|
+
}
|
|
120492
|
+
if (entry.status !== "undeliverable" || entry.undeliverableNotificationId === undefined || entry.undeliverableNotifiedAt !== undefined || entry.undeliverableReason === undefined)
|
|
120493
|
+
continue;
|
|
120494
|
+
if (!await notify2(entry, entry.undeliverableReason, entry.undeliverableNotificationId))
|
|
120495
|
+
continue;
|
|
120496
|
+
await activeStore.markPendingStageMessageUndeliverableNotified(run2.id, entry.stageKey, entry.id, entry.undeliverableNotificationId, new Date().toISOString(), backend);
|
|
120497
|
+
}
|
|
120498
|
+
}
|
|
120499
|
+
return settled;
|
|
120500
|
+
}
|
|
120501
|
+
|
|
119484
120502
|
// dist/builtin/workflows/src/extension/postmortem-deps.ts
|
|
119485
120503
|
function resolveStageCwd(runId) {
|
|
119486
120504
|
try {
|
|
@@ -119814,7 +120832,9 @@ function withWorkflowStageSessionOptions(options, meta2, pi) {
|
|
|
119814
120832
|
return {
|
|
119815
120833
|
...options,
|
|
119816
120834
|
excludedTools,
|
|
119817
|
-
...meta2 ? {
|
|
120835
|
+
...meta2 ? {
|
|
120836
|
+
orchestrationContext: meta2.orchestrationContext ?? options.orchestrationContext ?? makeWorkflowStageOrchestrationContext(meta2, pi)
|
|
120837
|
+
} : {}
|
|
119818
120838
|
};
|
|
119819
120839
|
}
|
|
119820
120840
|
function shouldBindStageUiContext(pi, meta2) {
|
|
@@ -119919,10 +120939,8 @@ function buildRuntimeAdapters(pi, options = {}) {
|
|
|
119919
120939
|
const sessionOptions = withWorkflowStageSessionOptions(stripWorkflowOnlyOptions2(stageOptions) ?? {}, meta2, pi);
|
|
119920
120940
|
const result = await createSession(sessionOptions);
|
|
119921
120941
|
const bindable = result.session;
|
|
119922
|
-
if (
|
|
119923
|
-
await bindable.bindExtensions({
|
|
119924
|
-
uiContext: makeStageExtensionUiContext(pi.ui ?? {}, meta2, broker)
|
|
119925
|
-
});
|
|
120942
|
+
if (typeof bindable.bindExtensions === "function") {
|
|
120943
|
+
await bindable.bindExtensions(shouldBindStageUiContext(pi, meta2) ? { uiContext: makeStageExtensionUiContext(pi.ui ?? {}, meta2, broker) } : {});
|
|
119926
120944
|
}
|
|
119927
120945
|
return result;
|
|
119928
120946
|
}
|
|
@@ -122016,6 +123034,139 @@ function buildWorkflowStatusListing(snapshots2, filter = "all", now = Date.now()
|
|
|
122016
123034
|
};
|
|
122017
123035
|
}
|
|
122018
123036
|
|
|
123037
|
+
// dist/builtin/workflows/src/extension/workflow-tool-answer.ts
|
|
123038
|
+
function answerResult(runId, stageId, status, message) {
|
|
123039
|
+
return { action: "answer", runId, stageId, status, message };
|
|
123040
|
+
}
|
|
123041
|
+
function terminalAnswerResult(runId, stageId, workflowStatus) {
|
|
123042
|
+
const message = `Cannot answer a prompt because workflow ${runId} has terminated with status ${workflowStatus}. If work remains, start a new workflow to address it.`;
|
|
123043
|
+
return {
|
|
123044
|
+
action: "answer",
|
|
123045
|
+
runId,
|
|
123046
|
+
stageId,
|
|
123047
|
+
status: "failed",
|
|
123048
|
+
code: "WORKFLOW_TERMINAL",
|
|
123049
|
+
workflowStatus,
|
|
123050
|
+
error: message,
|
|
123051
|
+
message
|
|
123052
|
+
};
|
|
123053
|
+
}
|
|
123054
|
+
function hasPayloadProperty(args) {
|
|
123055
|
+
return args.text !== undefined || args.response !== undefined || args.message !== undefined;
|
|
123056
|
+
}
|
|
123057
|
+
function promptPayloadFromArgs(args) {
|
|
123058
|
+
if (args.response !== undefined)
|
|
123059
|
+
return args.response;
|
|
123060
|
+
if (args.text !== undefined)
|
|
123061
|
+
return args.text;
|
|
123062
|
+
return args.message;
|
|
123063
|
+
}
|
|
123064
|
+
function textPayloadFromArgs(args) {
|
|
123065
|
+
if (args.text !== undefined)
|
|
123066
|
+
return args.text;
|
|
123067
|
+
if (typeof args.response === "string")
|
|
123068
|
+
return args.response;
|
|
123069
|
+
return args.message;
|
|
123070
|
+
}
|
|
123071
|
+
function brokerAnswerFromArgs(args) {
|
|
123072
|
+
if (args.response !== undefined) {
|
|
123073
|
+
const coerced = coerceStageInputAnswer(args.response);
|
|
123074
|
+
if (hasStageInputAnswerContent(coerced))
|
|
123075
|
+
return coerced;
|
|
123076
|
+
}
|
|
123077
|
+
const text = textPayloadFromArgs(args);
|
|
123078
|
+
return text !== undefined ? { text } : {};
|
|
123079
|
+
}
|
|
123080
|
+
function answerablePromptIds(stage) {
|
|
123081
|
+
const target = stage.workflowGraphTarget;
|
|
123082
|
+
const ids = [];
|
|
123083
|
+
const brokered = stageUiBroker.peekStagePrompt(target.runId, target.stageId);
|
|
123084
|
+
if (brokered !== undefined)
|
|
123085
|
+
ids.push(brokered.id);
|
|
123086
|
+
if (stage.pendingPrompt !== undefined)
|
|
123087
|
+
ids.push(stage.pendingPrompt.id);
|
|
123088
|
+
if (stage.status === "awaiting_input" && stage.promptFootprint?.kind === "custom")
|
|
123089
|
+
ids.push(stage.promptFootprint.id);
|
|
123090
|
+
return ids;
|
|
123091
|
+
}
|
|
123092
|
+
function inferPromptStageTarget(runId, promptId) {
|
|
123093
|
+
const pending = expandWorkflowGraph(readGraphStoreSnapshot(store), runId).stages.filter((stage) => {
|
|
123094
|
+
const ids = answerablePromptIds(stage);
|
|
123095
|
+
return promptId === undefined ? ids.length > 0 : ids.includes(promptId);
|
|
123096
|
+
});
|
|
123097
|
+
const only = pending[0];
|
|
123098
|
+
if (pending.length === 1 && only !== undefined) {
|
|
123099
|
+
return { ok: true, runId: only.workflowGraphTarget.runId, stageId: only.workflowGraphTarget.stageId };
|
|
123100
|
+
}
|
|
123101
|
+
if (pending.length === 0) {
|
|
123102
|
+
return promptId === undefined ? { ok: true, runId } : { ok: false, message: `No pending prompt ${promptId} in run ${runId}.` };
|
|
123103
|
+
}
|
|
123104
|
+
return {
|
|
123105
|
+
ok: false,
|
|
123106
|
+
message: `${pending.length} prompts pending; pass stageId: ${pending.map(expandedStageLabel).join(", ")}`
|
|
123107
|
+
};
|
|
123108
|
+
}
|
|
123109
|
+
async function workflowAnswerAction(args) {
|
|
123110
|
+
const target = resolveToolRunTarget(args, "No active run with a pending prompt.");
|
|
123111
|
+
if (target.kind === "all")
|
|
123112
|
+
return answerResult("--all", "", "noop", "Answer requires a single run.");
|
|
123113
|
+
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
123114
|
+
return answerResult(target.target, "", "noop", target.message);
|
|
123115
|
+
}
|
|
123116
|
+
const runs = store.runs();
|
|
123117
|
+
const runById = new Map(runs.map((run2) => [run2.id, run2]));
|
|
123118
|
+
const rootRunId = reciprocalWorkflowRootRunId(runById, target.runId) ?? target.runId;
|
|
123119
|
+
const rootRun = runById.get(rootRunId);
|
|
123120
|
+
if (rootRun !== undefined && isTerminalRunStatus(rootRun.status)) {
|
|
123121
|
+
return terminalAnswerResult(rootRun.id, args.stageId?.trim() ?? "", rootRun.status);
|
|
123122
|
+
}
|
|
123123
|
+
const requested = resolveToolStageTarget(target.runId, args.stageId);
|
|
123124
|
+
const stage = requested.ok && requested.stageId === undefined ? inferPromptStageTarget(target.runId, args.promptId) : requested;
|
|
123125
|
+
if (!stage.ok || stage.stageId === undefined) {
|
|
123126
|
+
return answerResult(target.runId, "", "noop", stage.ok ? "Stage id or name is required." : stage.message);
|
|
123127
|
+
}
|
|
123128
|
+
const stageRunId = stage.runId ?? target.runId;
|
|
123129
|
+
const snapshot2 = store.runs().find((run2) => run2.id === stageRunId)?.stages.find((item) => item.id === stage.stageId);
|
|
123130
|
+
const brokerPrompt = stageUiBroker.peekStagePrompt(stageRunId, stage.stageId);
|
|
123131
|
+
if (brokerPrompt !== undefined && (args.promptId === undefined || args.promptId === brokerPrompt.id)) {
|
|
123132
|
+
if (!hasPayloadProperty(args))
|
|
123133
|
+
return answerResult(stageRunId, stage.stageId, "noop", "Answer requires text, response, or message.");
|
|
123134
|
+
const ok2 = stageUiBroker.answerStagePrompt(stageRunId, stage.stageId, brokerAnswerFromArgs(args), {
|
|
123135
|
+
answerSource: "workflow_tool"
|
|
123136
|
+
});
|
|
123137
|
+
return answerResult(stageRunId, stage.stageId, ok2 ? "ok" : "noop", ok2 ? `Answered input request ${brokerPrompt.id}.` : `No matching pending input request ${brokerPrompt.id}.`);
|
|
123138
|
+
}
|
|
123139
|
+
const customPrompt = snapshot2?.status === "awaiting_input" && snapshot2.promptFootprint?.kind === "custom" ? snapshot2.promptFootprint : undefined;
|
|
123140
|
+
if (customPrompt !== undefined && (args.promptId === undefined || args.promptId === customPrompt.id)) {
|
|
123141
|
+
return answerResult(stageRunId, stage.stageId, "noop", `Custom UI prompt ${customPrompt.id} requires the interactive workflow graph; arbitrary ctx.ui.custom<T> results cannot be answered through workflow answer.`);
|
|
123142
|
+
}
|
|
123143
|
+
const promptId = args.promptId ?? snapshot2?.pendingPrompt?.id;
|
|
123144
|
+
if (promptId === undefined) {
|
|
123145
|
+
return answerResult(stageRunId, stage.stageId, "noop", "No pending prompt to answer.");
|
|
123146
|
+
}
|
|
123147
|
+
if (!hasPayloadProperty(args))
|
|
123148
|
+
return answerResult(stageRunId, stage.stageId, "noop", "Answer requires text, response, or message.");
|
|
123149
|
+
if (stageUiBroker.wasStagePromptResolved(stageRunId, stage.stageId, promptId)) {
|
|
123150
|
+
return answerResult(stageRunId, stage.stageId, "ok", `Input request ${promptId} was already answered.`);
|
|
123151
|
+
}
|
|
123152
|
+
const rawPayload = promptPayloadFromArgs(args);
|
|
123153
|
+
const pendingPrompt = snapshot2?.pendingPrompt;
|
|
123154
|
+
const primitivePrompt = pendingPrompt?.id === promptId && isPrimitivePrompt(pendingPrompt) ? pendingPrompt : undefined;
|
|
123155
|
+
if (primitivePrompt !== undefined) {
|
|
123156
|
+
const coerced = coercePrimitivePromptAnswer(primitivePrompt, rawPayload);
|
|
123157
|
+
if (!coerced.ok)
|
|
123158
|
+
return answerResult(stageRunId, stage.stageId, "noop", primitivePromptAnswerRejection(promptId, primitivePrompt));
|
|
123159
|
+
const ok2 = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, coerced.value, {
|
|
123160
|
+
answerSource: "workflow_tool"
|
|
123161
|
+
});
|
|
123162
|
+
return answerResult(stageRunId, stage.stageId, ok2 ? "ok" : "noop", ok2 ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123163
|
+
}
|
|
123164
|
+
const ok = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, rawPayload, {
|
|
123165
|
+
answerSource: "workflow_tool"
|
|
123166
|
+
});
|
|
123167
|
+
return answerResult(stageRunId, stage.stageId, ok ? "ok" : "noop", ok ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123168
|
+
}
|
|
123169
|
+
|
|
122019
123170
|
// dist/builtin/workflows/src/extension/workflow-tool-content.ts
|
|
122020
123171
|
function stringifyWorkflowToolResult(result) {
|
|
122021
123172
|
return JSON.stringify(result, null, 2);
|
|
@@ -122024,7 +123175,7 @@ function compactWorkflowToolMessage(result) {
|
|
|
122024
123175
|
if (result.action === "reload") {
|
|
122025
123176
|
return `${result.action}: ${result.status} — ${result.message}`;
|
|
122026
123177
|
}
|
|
122027
|
-
const target = [result.runId, result.action === "
|
|
123178
|
+
const target = [result.runId, result.action === "answer" ? result.stageId : undefined].filter((part) => part !== undefined && part.length > 0).join("/");
|
|
122028
123179
|
return `${result.action}:${target ? ` ${target}` : ""} ${result.status} — ${result.message}`;
|
|
122029
123180
|
}
|
|
122030
123181
|
var STATUS_MESSAGE_CHAR_LIMIT = 120;
|
|
@@ -122100,7 +123251,7 @@ function renderStatusToolContent(result) {
|
|
|
122100
123251
|
for (const entry of run2.awaitingInput)
|
|
122101
123252
|
lines.push(statusAwaitingInputLine(entry));
|
|
122102
123253
|
});
|
|
122103
|
-
lines.push("hint: status with runId returns full run detail;
|
|
123254
|
+
lines.push("hint: status with runId returns full run detail; workflow answer answers pending prompts using runId/stageId/promptId; workflow resume controls paused runs; pause/interrupt/quit also accept runId. Ordinary Intercom handles free-form workflow-stage communication at <runId>:<stageKey>: live delivery is immediate, known unstarted stages queue before their first model turn. Use Intercom ask once a reply-capable live session exists.");
|
|
122104
123255
|
return lines.join(`
|
|
122105
123256
|
`);
|
|
122106
123257
|
}
|
|
@@ -122228,7 +123379,7 @@ function renderWorkflowToolContent(result, args) {
|
|
|
122228
123379
|
return renderStagesToolContent(result);
|
|
122229
123380
|
case "stage":
|
|
122230
123381
|
return renderStageToolContent(result);
|
|
122231
|
-
case "
|
|
123382
|
+
case "answer":
|
|
122232
123383
|
case "pause":
|
|
122233
123384
|
case "reload":
|
|
122234
123385
|
case "interrupt":
|
|
@@ -123003,284 +124154,6 @@ function workflowTranscriptResult(args, source) {
|
|
|
123003
124154
|
});
|
|
123004
124155
|
}
|
|
123005
124156
|
|
|
123006
|
-
// dist/builtin/workflows/src/extension/workflow-tool-send.ts
|
|
123007
|
-
function hasPayloadProperty(args) {
|
|
123008
|
-
return args.text !== undefined || args.response !== undefined || args.message !== undefined;
|
|
123009
|
-
}
|
|
123010
|
-
function promptPayloadFromArgs(args) {
|
|
123011
|
-
if (args.response !== undefined)
|
|
123012
|
-
return args.response;
|
|
123013
|
-
if (args.text !== undefined)
|
|
123014
|
-
return args.text;
|
|
123015
|
-
return args.message;
|
|
123016
|
-
}
|
|
123017
|
-
function textPayloadFromArgs(args) {
|
|
123018
|
-
if (args.text !== undefined)
|
|
123019
|
-
return args.text;
|
|
123020
|
-
if (typeof args.response === "string")
|
|
123021
|
-
return args.response;
|
|
123022
|
-
if (args.message !== undefined)
|
|
123023
|
-
return args.message;
|
|
123024
|
-
return;
|
|
123025
|
-
}
|
|
123026
|
-
function brokerAnswerFromArgs(args) {
|
|
123027
|
-
if (args.response !== undefined) {
|
|
123028
|
-
const coerced = coerceStageInputAnswer(args.response);
|
|
123029
|
-
if (hasStageInputAnswerContent(coerced))
|
|
123030
|
-
return coerced;
|
|
123031
|
-
}
|
|
123032
|
-
const text = textPayloadFromArgs(args);
|
|
123033
|
-
return text !== undefined ? { text } : {};
|
|
123034
|
-
}
|
|
123035
|
-
function answersPendingPrompt(delivery, promptId) {
|
|
123036
|
-
return delivery === "answer" || delivery === "auto" || promptId !== undefined;
|
|
123037
|
-
}
|
|
123038
|
-
function answerablePromptIds(stage) {
|
|
123039
|
-
const target = stage.workflowGraphTarget;
|
|
123040
|
-
const ids = [];
|
|
123041
|
-
const brokered = stageUiBroker.peekStagePrompt(target.runId, target.stageId);
|
|
123042
|
-
if (brokered !== undefined)
|
|
123043
|
-
ids.push(brokered.id);
|
|
123044
|
-
if (stage.pendingPrompt !== undefined)
|
|
123045
|
-
ids.push(stage.pendingPrompt.id);
|
|
123046
|
-
if (stage.status === "awaiting_input" && stage.promptFootprint?.kind === "custom") {
|
|
123047
|
-
ids.push(stage.promptFootprint.id);
|
|
123048
|
-
}
|
|
123049
|
-
return ids;
|
|
123050
|
-
}
|
|
123051
|
-
function inferPromptStageTarget(runId, delivery, promptId) {
|
|
123052
|
-
if (!answersPendingPrompt(delivery, promptId))
|
|
123053
|
-
return { ok: true, runId };
|
|
123054
|
-
const pending = expandWorkflowGraph(readGraphStoreSnapshot(store), runId).stages.filter((stage) => {
|
|
123055
|
-
const ids = answerablePromptIds(stage);
|
|
123056
|
-
return promptId === undefined ? ids.length > 0 : ids.includes(promptId);
|
|
123057
|
-
});
|
|
123058
|
-
const only = pending[0];
|
|
123059
|
-
if (pending.length === 1 && only !== undefined) {
|
|
123060
|
-
return { ok: true, runId: only.workflowGraphTarget.runId, stageId: only.workflowGraphTarget.stageId };
|
|
123061
|
-
}
|
|
123062
|
-
if (pending.length === 0) {
|
|
123063
|
-
return promptId === undefined ? { ok: true, runId } : { ok: false, message: `No pending prompt ${promptId} in run ${runId}.` };
|
|
123064
|
-
}
|
|
123065
|
-
return {
|
|
123066
|
-
ok: false,
|
|
123067
|
-
message: `${pending.length} prompts pending; pass stageId: ${pending.map(expandedStageLabel).join(", ")}`
|
|
123068
|
-
};
|
|
123069
|
-
}
|
|
123070
|
-
function workflowSendResult(runId, stageId, delivery, status, message) {
|
|
123071
|
-
return { action: "send", runId, stageId, delivery, status, message };
|
|
123072
|
-
}
|
|
123073
|
-
function terminalWorkflowSendResult(runId, stageId, workflowStatus) {
|
|
123074
|
-
const message = `Cannot send a message because workflow ${runId} has terminated with status ${workflowStatus}. If work remains, start a new workflow to address it. Complete it inline only when the remaining task is small, deterministic, and low risk.`;
|
|
123075
|
-
return {
|
|
123076
|
-
action: "send",
|
|
123077
|
-
runId,
|
|
123078
|
-
stageId,
|
|
123079
|
-
delivery: "rejected",
|
|
123080
|
-
status: "failed",
|
|
123081
|
-
code: "WORKFLOW_TERMINAL",
|
|
123082
|
-
workflowStatus,
|
|
123083
|
-
error: message,
|
|
123084
|
-
message
|
|
123085
|
-
};
|
|
123086
|
-
}
|
|
123087
|
-
|
|
123088
|
-
class WorkflowSendAdmissionError extends Error {
|
|
123089
|
-
result;
|
|
123090
|
-
constructor(result) {
|
|
123091
|
-
super(result.message);
|
|
123092
|
-
this.result = result;
|
|
123093
|
-
}
|
|
123094
|
-
}
|
|
123095
|
-
function terminalWorkflowSendResultForRoot(rootRunId, stageId) {
|
|
123096
|
-
const rootRun = store.runs().find((run2) => run2.id === rootRunId);
|
|
123097
|
-
return rootRun !== undefined && isTerminalRunStatus(rootRun.status) ? terminalWorkflowSendResult(rootRun.id, stageId, rootRun.status) : undefined;
|
|
123098
|
-
}
|
|
123099
|
-
async function deliverStageUserMessage(handle, text, deliverAs, beforeDelivery) {
|
|
123100
|
-
if (handle.sendUserMessage === undefined) {
|
|
123101
|
-
throw new Error("atomic-workflows: stage handle does not support admission-aware message delivery");
|
|
123102
|
-
}
|
|
123103
|
-
return handle.sendUserMessage(text, { deliverAs }, beforeDelivery);
|
|
123104
|
-
}
|
|
123105
|
-
function deliveryMessage(delivery) {
|
|
123106
|
-
if (delivery === "prompt")
|
|
123107
|
-
return "Prompt started for stage.";
|
|
123108
|
-
if (delivery === "steer")
|
|
123109
|
-
return "Steered live stage.";
|
|
123110
|
-
if (delivery === "followUp")
|
|
123111
|
-
return "Follow-up queued for stage.";
|
|
123112
|
-
return "Message handled by stage extension.";
|
|
123113
|
-
}
|
|
123114
|
-
async function workflowSendAction(args, deps = {}) {
|
|
123115
|
-
const target = resolveToolRunTarget(args, "No active run to message.");
|
|
123116
|
-
const requestedDelivery = args.delivery ?? "auto";
|
|
123117
|
-
if (target.kind === "all") {
|
|
123118
|
-
return workflowSendResult("--all", "", requestedDelivery, "noop", "Send requires a single run.");
|
|
123119
|
-
}
|
|
123120
|
-
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
123121
|
-
return workflowSendResult(target.target, "", requestedDelivery, "noop", target.message);
|
|
123122
|
-
}
|
|
123123
|
-
const runs = store.runs();
|
|
123124
|
-
const runById = new Map(runs.map((run3) => [run3.id, run3]));
|
|
123125
|
-
const rootRunId = reciprocalWorkflowRootRunId(runById, target.runId) ?? target.runId;
|
|
123126
|
-
const rootRun = runById.get(rootRunId);
|
|
123127
|
-
if (rootRun !== undefined && isTerminalRunStatus(rootRun.status)) {
|
|
123128
|
-
return terminalWorkflowSendResult(rootRun.id, args.stageId?.trim() ?? "", rootRun.status);
|
|
123129
|
-
}
|
|
123130
|
-
const requested = resolveToolStageTarget(target.runId, args.stageId);
|
|
123131
|
-
const stage = requested.ok && requested.stageId === undefined ? inferPromptStageTarget(target.runId, requestedDelivery, args.promptId) : requested;
|
|
123132
|
-
if (!stage.ok || stage.stageId === undefined) {
|
|
123133
|
-
return workflowSendResult(target.runId, "", requestedDelivery, "noop", stage.ok ? "Stage id or name is required." : stage.message);
|
|
123134
|
-
}
|
|
123135
|
-
const resolvedStageId = stage.stageId;
|
|
123136
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
123137
|
-
const run2 = store.runs().find((r) => r.id === stageRunId);
|
|
123138
|
-
const snapshot2 = run2?.stages.find((s) => s.id === stage.stageId);
|
|
123139
|
-
const brokerPrompt = stageUiBroker.peekStagePrompt(stageRunId, stage.stageId);
|
|
123140
|
-
const targetsBrokerPrompt = brokerPrompt !== undefined && (args.promptId === undefined || args.promptId === brokerPrompt.id) && (requestedDelivery === "answer" || args.promptId !== undefined || requestedDelivery === "auto");
|
|
123141
|
-
if (targetsBrokerPrompt && brokerPrompt !== undefined) {
|
|
123142
|
-
if (!hasPayloadProperty(args)) {
|
|
123143
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
|
|
123144
|
-
}
|
|
123145
|
-
const ok = stageUiBroker.answerStagePrompt(stageRunId, stage.stageId, brokerAnswerFromArgs(args), {
|
|
123146
|
-
answerSource: "workflow_tool"
|
|
123147
|
-
});
|
|
123148
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", ok ? "ok" : "noop", ok ? `Answered input request ${brokerPrompt.id}.` : `No matching pending input request ${brokerPrompt.id}.`);
|
|
123149
|
-
}
|
|
123150
|
-
const customPrompt = snapshot2?.status === "awaiting_input" && snapshot2.promptFootprint?.kind === "custom" ? snapshot2.promptFootprint : undefined;
|
|
123151
|
-
const targetsCustomPrompt = customPrompt !== undefined && (args.promptId === undefined || args.promptId === customPrompt.id) && (requestedDelivery === "answer" || args.promptId !== undefined || requestedDelivery === "auto");
|
|
123152
|
-
if (targetsCustomPrompt && customPrompt !== undefined) {
|
|
123153
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", `Custom UI prompt ${customPrompt.id} requires the interactive workflow graph; arbitrary ctx.ui.custom<T> results cannot be answered through workflow send.`);
|
|
123154
|
-
}
|
|
123155
|
-
const targetsPrompt = requestedDelivery === "answer" || args.promptId !== undefined || requestedDelivery === "auto" && snapshot2?.pendingPrompt !== undefined;
|
|
123156
|
-
if (targetsPrompt) {
|
|
123157
|
-
const promptId = args.promptId ?? snapshot2?.pendingPrompt?.id;
|
|
123158
|
-
if (promptId === undefined) {
|
|
123159
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "No pending prompt to answer.");
|
|
123160
|
-
}
|
|
123161
|
-
if (!hasPayloadProperty(args)) {
|
|
123162
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
|
|
123163
|
-
}
|
|
123164
|
-
if (stageUiBroker.wasStagePromptResolved(stageRunId, stage.stageId, promptId)) {
|
|
123165
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "ok", `Input request ${promptId} was already answered.`);
|
|
123166
|
-
}
|
|
123167
|
-
const rawPayload = promptPayloadFromArgs(args);
|
|
123168
|
-
const pendingPrompt = snapshot2?.pendingPrompt;
|
|
123169
|
-
const primitivePrompt = pendingPrompt?.id === promptId && isPrimitivePrompt(pendingPrompt) ? pendingPrompt : undefined;
|
|
123170
|
-
if (primitivePrompt !== undefined) {
|
|
123171
|
-
const coercedPayload = coercePrimitivePromptAnswer(primitivePrompt, rawPayload);
|
|
123172
|
-
if (!coercedPayload.ok) {
|
|
123173
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", primitivePromptAnswerRejection(promptId, primitivePrompt));
|
|
123174
|
-
}
|
|
123175
|
-
const ok2 = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, coercedPayload.value, {
|
|
123176
|
-
answerSource: "workflow_tool"
|
|
123177
|
-
});
|
|
123178
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", ok2 ? "ok" : "noop", ok2 ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123179
|
-
}
|
|
123180
|
-
const ok = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, rawPayload, {
|
|
123181
|
-
answerSource: "workflow_tool"
|
|
123182
|
-
});
|
|
123183
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", ok ? "ok" : "noop", ok ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123184
|
-
}
|
|
123185
|
-
const text = textPayloadFromArgs(args);
|
|
123186
|
-
if (text === undefined) {
|
|
123187
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Send requires text, response, or message.");
|
|
123188
|
-
}
|
|
123189
|
-
let lease;
|
|
123190
|
-
let handle;
|
|
123191
|
-
const existingHandle = stageControlRegistry.peek(stageRunId, stage.stageId);
|
|
123192
|
-
if (existingHandle !== undefined) {
|
|
123193
|
-
lease = stageControlRegistry.acquireDetached(stageRunId, stage.stageId, () => existingHandle);
|
|
123194
|
-
handle = lease.handle;
|
|
123195
|
-
} else if (deps.resolvePostMortemDeps !== undefined && snapshot2 !== undefined) {
|
|
123196
|
-
const acquired = acquirePostMortemStageHandle(stageRunId, snapshot2, deps.resolvePostMortemDeps(stageRunId));
|
|
123197
|
-
if (acquired.ok) {
|
|
123198
|
-
lease = acquired.lease;
|
|
123199
|
-
handle = lease.handle;
|
|
123200
|
-
}
|
|
123201
|
-
}
|
|
123202
|
-
if (handle === undefined) {
|
|
123203
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "No live handle for stage.");
|
|
123204
|
-
}
|
|
123205
|
-
let admitted = false;
|
|
123206
|
-
const admitDelivery = () => {
|
|
123207
|
-
const terminal = terminalWorkflowSendResultForRoot(rootRunId, args.stageId?.trim() ?? resolvedStageId);
|
|
123208
|
-
if (terminal !== undefined)
|
|
123209
|
-
throw new WorkflowSendAdmissionError(terminal);
|
|
123210
|
-
if (lease !== undefined && !lease.commit()) {
|
|
123211
|
-
throw new WorkflowSendAdmissionError(workflowSendResult(stageRunId, resolvedStageId, requestedDelivery, "noop", "Stage handle changed before message admission; retry against the current live stage."));
|
|
123212
|
-
}
|
|
123213
|
-
admitted = true;
|
|
123214
|
-
};
|
|
123215
|
-
const terminalPending = Promise.withResolvers();
|
|
123216
|
-
const unsubscribeTerminal = subscribeStoreInvalidation(store, () => {
|
|
123217
|
-
if (admitted)
|
|
123218
|
-
return;
|
|
123219
|
-
const terminal = terminalWorkflowSendResultForRoot(rootRunId, args.stageId?.trim() ?? resolvedStageId);
|
|
123220
|
-
if (terminal !== undefined)
|
|
123221
|
-
terminalPending.reject(new WorkflowSendAdmissionError(terminal));
|
|
123222
|
-
});
|
|
123223
|
-
const awaitAdmission = (operation) => Promise.race([operation, terminalPending.promise]);
|
|
123224
|
-
try {
|
|
123225
|
-
const isTerminalPostMortemStage = handle.status === "completed";
|
|
123226
|
-
if (requestedDelivery === "resume" && handle.status !== "paused" && !isTerminalPostMortemStage) {
|
|
123227
|
-
return workflowSendResult(stageRunId, stage.stageId, "resume", "noop", "Stage is not paused; no resume message was delivered.");
|
|
123228
|
-
}
|
|
123229
|
-
if (handle.status === "paused" && requestedDelivery !== "resume" && requestedDelivery !== "auto") {
|
|
123230
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Stage is paused; resume it before sending a new message.");
|
|
123231
|
-
}
|
|
123232
|
-
const resumesStage = requestedDelivery === "resume" || requestedDelivery === "auto" && handle.status === "paused";
|
|
123233
|
-
if (!resumesStage && handle.sendUserMessage === undefined) {
|
|
123234
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Stage handle does not support admission-aware message delivery.");
|
|
123235
|
-
}
|
|
123236
|
-
if (resumesStage) {
|
|
123237
|
-
if (isTerminalPostMortemStage) {
|
|
123238
|
-
return workflowSendResult(stageRunId, stage.stageId, "resume", "noop", 'Cannot resume a terminal post-mortem stage; use delivery "followUp" or "prompt" to continue its retained conversation.');
|
|
123239
|
-
}
|
|
123240
|
-
const resumedDelivery = await awaitAdmission(handle.resume(text, admitDelivery));
|
|
123241
|
-
if (resumedDelivery !== undefined && resumedDelivery !== "prompt") {
|
|
123242
|
-
return workflowSendResult(stageRunId, stage.stageId, resumedDelivery, "ok", deliveryMessage(resumedDelivery));
|
|
123243
|
-
}
|
|
123244
|
-
if (resumedDelivery === "prompt") {
|
|
123245
|
-
return workflowSendResult(stageRunId, stage.stageId, "prompt", "ok", "Resumed stage and started prompt.");
|
|
123246
|
-
}
|
|
123247
|
-
const hasResumeMessage = text.trim().length > 0;
|
|
123248
|
-
return workflowSendResult(stageRunId, stage.stageId, "resume", "ok", hasResumeMessage ? "Resumed interrupted stage with message." : "Resumed stage.");
|
|
123249
|
-
}
|
|
123250
|
-
if (requestedDelivery === "steer") {
|
|
123251
|
-
if (isTerminalPostMortemStage) {
|
|
123252
|
-
return workflowSendResult(stageRunId, stage.stageId, "steer", "noop", 'Cannot steer a terminal post-mortem stage; use delivery "followUp" or "prompt" to continue its retained conversation.');
|
|
123253
|
-
}
|
|
123254
|
-
const delivery2 = await awaitAdmission(deliverStageUserMessage(handle, text, "steer", admitDelivery));
|
|
123255
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery2, "ok", deliveryMessage(delivery2));
|
|
123256
|
-
}
|
|
123257
|
-
if (requestedDelivery === "auto" && handle.isStreaming && !isTerminalPostMortemStage) {
|
|
123258
|
-
const delivery2 = await awaitAdmission(deliverStageUserMessage(handle, text, "steer", admitDelivery));
|
|
123259
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery2, "ok", deliveryMessage(delivery2));
|
|
123260
|
-
}
|
|
123261
|
-
if (requestedDelivery === "prompt") {
|
|
123262
|
-
const delivery2 = await awaitAdmission(deliverStageUserMessage(handle, text, undefined, admitDelivery));
|
|
123263
|
-
const message = delivery2 === "prompt" ? "Prompt sent to stage." : deliveryMessage(delivery2);
|
|
123264
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery2, "ok", message);
|
|
123265
|
-
}
|
|
123266
|
-
const delivery = await awaitAdmission(deliverStageUserMessage(handle, text, "followUp", admitDelivery));
|
|
123267
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery, "ok", deliveryMessage(delivery));
|
|
123268
|
-
} catch (error) {
|
|
123269
|
-
if (error instanceof WorkflowSendAdmissionError)
|
|
123270
|
-
return error.result;
|
|
123271
|
-
throw error;
|
|
123272
|
-
} finally {
|
|
123273
|
-
unsubscribeTerminal();
|
|
123274
|
-
if (!admitted) {
|
|
123275
|
-
try {
|
|
123276
|
-
await lease?.release();
|
|
123277
|
-
} catch (error) {
|
|
123278
|
-
console.warn("atomic-workflows: provisional workflow-send handle cleanup failed", error);
|
|
123279
|
-
}
|
|
123280
|
-
}
|
|
123281
|
-
}
|
|
123282
|
-
}
|
|
123283
|
-
|
|
123284
124157
|
// dist/builtin/workflows/src/extension/workflow-tool.ts
|
|
123285
124158
|
async function resolveDurableInspectionSource(args, runtime) {
|
|
123286
124159
|
const target = args.runId?.trim();
|
|
@@ -123308,7 +124181,7 @@ function durableInspectionError(action, runId, message) {
|
|
|
123308
124181
|
truncated: false
|
|
123309
124182
|
};
|
|
123310
124183
|
}
|
|
123311
|
-
function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflowResourcesLoaded = () => {}
|
|
124184
|
+
function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflowResourcesLoaded = () => {}) {
|
|
123312
124185
|
return async function executeWorkflowTool(args, ctx, signal, onRunAccepted) {
|
|
123313
124186
|
const action = args.action ?? "run";
|
|
123314
124187
|
const runId = args.runId ?? "";
|
|
@@ -123397,8 +124270,8 @@ function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflo
|
|
|
123397
124270
|
return workflowStageResult(args, source);
|
|
123398
124271
|
return workflowTranscriptResult(args, source);
|
|
123399
124272
|
}
|
|
123400
|
-
case "
|
|
123401
|
-
return awaitRequest(
|
|
124273
|
+
case "answer":
|
|
124274
|
+
return awaitRequest(workflowAnswerAction(args));
|
|
123402
124275
|
case "pause":
|
|
123403
124276
|
return awaitRequest(workflowPauseAction(args));
|
|
123404
124277
|
case "reload":
|
|
@@ -123459,8 +124332,8 @@ function renderCall(args, opts = {}) {
|
|
|
123459
124332
|
case "transcript":
|
|
123460
124333
|
line = name === undefined ? "workflow: read stage transcript" : `workflow: read stage transcript in ${quoted(name)}`;
|
|
123461
124334
|
break;
|
|
123462
|
-
case "
|
|
123463
|
-
line = name === undefined ? "workflow:
|
|
124335
|
+
case "answer":
|
|
124336
|
+
line = name === undefined ? "workflow: answer prompt" : `workflow: answer prompt in ${quoted(name)}`;
|
|
123464
124337
|
break;
|
|
123465
124338
|
case "pause":
|
|
123466
124339
|
line = name === undefined ? "workflow: pause run" : `workflow: pause run ${quoted(name)}`;
|
|
@@ -123652,9 +124525,9 @@ function renderResult(result, opts) {
|
|
|
123652
124525
|
const suffix = r.truncated ? " (truncated)" : "";
|
|
123653
124526
|
return renderNotice("WORKFLOW TRANSCRIPT", `${r.runId}/${r.stageId} ${r.source}: ${text}${suffix}`, opts, themed);
|
|
123654
124527
|
}
|
|
123655
|
-
case "
|
|
124528
|
+
case "answer": {
|
|
123656
124529
|
const r = result;
|
|
123657
|
-
return renderNotice("WORKFLOW
|
|
124530
|
+
return renderNotice("WORKFLOW ANSWER", `${r.runId}/${r.stageId}: ${r.message}`, opts, themed);
|
|
123658
124531
|
}
|
|
123659
124532
|
case "pause": {
|
|
123660
124533
|
const r = result;
|
|
@@ -123697,7 +124570,7 @@ function renderResult(result, opts) {
|
|
|
123697
124570
|
}
|
|
123698
124571
|
|
|
123699
124572
|
// dist/builtin/workflows/src/extension/workflow-prompts.ts
|
|
123700
|
-
var WORKFLOW_TOOL_DESCRIPTION = "Run named builtin, project, user, or package workflows; custom definitions may import reusable project/package workflows or builtin definitions from @bastani/workflows/builtin and nest them with ctx.workflow(...), including deeper composition within the configured maxDepth; " + "when workflow execution fits but another shape would better achieve the task, author a custom TypeScript workflow({...}) inline with normal coding tools, reload it, and run it; after successfully creating and reloading a newly authored custom workflow, report the folder containing its generated code as 'Custom workflow created. You can inspect its code at: <workflow-folder-path>'; do this only for newly created custom workflows, never builtin or pre-existing workflows; " + "discover with list/get/inputs/models, list session runs with status (no runId; statusFilter narrows the list), inspect status/stages/stage details, " + "
|
|
124573
|
+
var WORKFLOW_TOOL_DESCRIPTION = "Run named builtin, project, user, or package workflows; custom definitions may import reusable project/package workflows or builtin definitions from @bastani/atomic/workflows/builtin and nest them with ctx.workflow(...), including deeper composition within the configured maxDepth; " + "when workflow execution fits but another shape would better achieve the task, author a custom TypeScript workflow({...}) inline with normal coding tools, reload it, and run it; after successfully creating and reloading a newly authored custom workflow, report the folder containing its generated code as 'Custom workflow created. You can inspect its code at: <workflow-folder-path>'; do this only for newly created custom workflows, never builtin or pre-existing workflows; " + "discover with list/get/inputs/models, list session runs with status (no runId; statusFilter narrows the list), inspect status/stages/stage details, " + "answer pending prompts only while the root workflow is nonterminal, pause/resume/interrupt/quit runs, and reload workflow resources. " + "When steering or communication is useful, use Intercom; address a workflow stage as `<runId>:<stageKey>`. Live delivery is immediate; a known stage that has not started is queued and receives the message before its first model turn. Use `ask` only for a reply-capable live session. " + "Treat a blocked run as continuable by default: resume resumable blocks, answer pending prompts, steer past the obstacle, or start a follow-up workflow past a terminal block, and escalate to the user only when the blocked result is so ambiguous that human input or steering must settle it; when ask_user_question or human input is unavailable, continue fully autonomously on the interpretation best supported by the objective and repository evidence, and record the assumption. " + "For action 'run' and 'resume', budget accepts per-field duration, token, cost, and warning overrides; fields resolve over the workflow declaration and config, and 0 disables a field. " + "Pass budget only when the user asked for a limit; otherwise omit it entirely and inherit the declaration and config rather than inventing a cap. " + "For primitive prompt answers, use booleans or the documented confirm labels, exact case-insensitive select labels or 1-based indexes, and text strings for input/editor; an invalid answer remains pending and returns guidance instead of choosing a default. " + "For large stage handoffs, write context to files/artifacts, pass paths via reads, and prompt downstream agents to 'Read the file at <path>...' instead of injecting large previous text. " + "Wrap critical parts of run inputs and steering messages in <keepContext>...</keepContext> so compaction preserves them verbatim in the stages that inherit them; tag role constraints, prohibitions, must-hold criteria, and identifiers, not background or bulk reference material. " + "For transcripts, prefer status/stages/stage to get sessionFile/transcriptPath, " + "quote the exact path without rewriting separators (Windows backslashes are valid), " + "then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview. " + "Use action 'models' to inspect models in the configured catalog; the result is a configured-auth snapshot showing what's present in the registry with configured authentication, not proof of credentials, entitlements, OAuth freshness, or live provider access. " + "When authoring a workflow that should dynamically select a model, first call workflow({ action: 'models' }) to inspect the configured catalog, then select from the returned provider/id entries considering the isCurrent marker and available thinking levels.";
|
|
123701
124574
|
var DEFAULT_PROMPT_GUIDANCE = [
|
|
123702
124575
|
`**Workflows**: Treat workflows as the default execution path for any non-trivial task and for any request that has inherent structure plus an objective you can make verifiable. Use the \`workflow\` tool for existing named workflows; when the task needs a graph that is not installed, author a custom TypeScript \`workflow({...})\` inline with normal coding tools, reload workflow resources, and run it.
|
|
123703
124576
|
- Workflow fit check: prefer a workflow for implementation, build, debug/diagnosis, bug-fix, migration, new-feature, scoped multi-file, or docs/code changes with validation; and whenever there are multiple steps, dependencies, handoffs, uncertainty, review/validation needs, long-running work, measurable done criteria, or an outcome that needs evidence.
|
|
@@ -123729,16 +124602,16 @@ var DEFAULT_PROMPT_GUIDANCE = [
|
|
|
123729
124602
|
`**Workflow discovery and lifecycle**:
|
|
123730
124603
|
- For unfamiliar named workflows, discover with \`action: "list"\`, inspect with \`action: "get"\` or \`action: "inputs"\`, and run with \`action: "run"\`, \`workflow\`, and validated \`inputs\`; do not invent workflow names or input keys.
|
|
123731
124604
|
- Do not pass a \`budget\` unless the user asked for a limit. Budget fields are overrides, not required inputs: omitting \`budget\` inherits the workflow declaration and config, which is the intended default, and assuming no budget is always the correct default. A cap you invented truncates an otherwise healthy run at a duration, token, or cost boundary the user never chose, and the resulting failure reads as a workflow problem rather than as your override. When the user does state a limit, pass only the fields they named, leave every other field inherited, and use \`0\` to disable a field they asked you to remove.
|
|
123732
|
-
- Heartbeat cadence is 15 minutes by default.
|
|
124605
|
+
- Heartbeat cadence is 15 minutes by default. Keep that interval unless the user explicitly asks for a different cadence. A heartbeat is a periodic alignment check: re-read the objective, judge whether the run is still on goal, and continue a progressing run when no intervention is needed. Use workflow pause, resume, interrupt, or quit when run control is useful, and ask the user when a decision is needed.
|
|
123733
124606
|
- Wrap critical parts of the \`inputs\` you pass — objective, prompt, acceptance criteria — in \`<keepContext>\` / \`</keepContext>\`. Tagged text survives compaction verbatim regardless of the compression ratio, and stages inherit it because workflows inject your inputs into their prompts. A long stage is compacted repeatedly, and compaction ranks lines individually: a verbose restated objective outlives the one line that bounds it, so a stage can end up executing a coherent but unbounded version of what you asked for. Decide this per launch rather than tagging everything — tag role constraints, prohibitions, must-hold criteria, and identifiers such as a target branch, worktree path, or issue number; leave background, quoted issue text, and reference material untagged and pass bulk through files and \`reads\`. Protected lines count against the keep target rather than raising it, so an over-tagged input makes the evidence stages need compress harder.
|
|
123734
|
-
- Tag steering the same way.
|
|
123735
|
-
- In interactive chat, named workflow launches run in the background. Run \`/workflow connect <run>\` to see agents working and chat with and steer each stage. Inspection and control calls (\`status\`, \`stages\`, \`stage\`, \`transcript\`, \`
|
|
123736
|
-
- \`workflow
|
|
124607
|
+
- Tag steering the same way. An Intercom \`send\` amendment is authoritative and stages must carry it forward, but it arrives late in an already-long session and is exactly one short message competing with the whole transcript; \`<keepContext>\` around the requirement keeps it from being compacted away before the stage acts on it.
|
|
124608
|
+
- In interactive chat, named workflow launches run in the background. Run \`/workflow connect <run>\` to see agents working and chat with and steer each stage. Inspection and control calls (\`status\`, \`stages\`, \`stage\`, \`transcript\`, \`answer\`, \`pause\`, \`resume\`, \`interrupt\`, \`quit\`) remain available while work runs.
|
|
124609
|
+
- \`workflow answer\` handles a pending human-input prompt. Send free-form updates through Intercom to \`<runId>:<stageKey>\`; Atomic delivers immediately to live stages and queues messages for known stages that have not started, delivering them before their first model turn. Use \`ask\` once the target has a live session that can reply. Use explicit \`/workflow attach <run> <stage>\` for user-driven post-mortem chat.
|
|
123737
124610
|
- A blocked run is a changed condition, not a stop order. On a blocked status or a WORKFLOW BLOCKED lifecycle notice, keep the work moving by default: resume a resumable block, answer the pending prompt, steer the stage past the obstacle, or start a follow-up workflow that carries the remaining tracked work past a terminal block — continue inline only if the remaining work is minimal. Stop for user input only when the task is so ambiguous that competing interpretations lead to materially different outcomes and judgment cannot infer intent from the stated objective and repository evidence; then ask one grouped question or wait for steering.
|
|
123738
124611
|
- A budget-exceeded stop (the resumable \`budget_exceeded\` blocked rail) is the exception: the exhausted budget is a boundary someone chose, so do not raise it silently. Summarize progress and the estimated next steps, ask the user whether to proceed — prefer the \`ask_user_question\` tool when it is available — and resume with a raised \`budget\` only after approval.
|
|
123739
124612
|
- When human input is unavailable — \`ask_user_question\` is not among your tools, the session is headless, or nobody answers — do not stall on a question. Choose the interpretation best supported by the stated objective and repository evidence — mine git history, commits, PRs, issues, and the user's own comments to infer how they would decide — record the assumption and rationale in the result or an artifact, and continue fully autonomously on best judgment.
|
|
123740
124613
|
- Natural-language instructions to create or use a worktree do not enable runner isolation. A named workflow must declare and implement any worktree and feature-branch inputs it supports; inspect its inputs and pass a distinct path and branch for each concurrent item. Reusable \`baseBranch\` binding creates a missing target as a detached checkout from that base or reuses an existing same-repository worktree as-is; neither case checks out a separate feature-branch input.
|
|
123741
|
-
- Once you have started the selected single run or every run in the selected bounded wave, end the current turn and wait for user input or lifecycle notices. Do not use sleep/status polling loops: key start, finish, and failure events arrive automatically. Use targeted \`status\`/\`stages\`/\`stage\` checks only when the user asks or the next step needs them, and use \`send\`/\`pause\`/\`resume\`/\`interrupt\`/\`quit\`
|
|
124614
|
+
- Once you have started the selected single run or every run in the selected bounded wave, end the current turn and wait for user input or lifecycle notices. Do not use sleep/status polling loops: key start, finish, and failure events arrive automatically. Use targeted \`status\`/\`stages\`/\`stage\` checks only when the user asks or the next step needs them, and use Intercom \`send\`/\`ask\` for stage communication or \`answer\`/\`pause\`/\`resume\`/\`interrupt\`/\`quit\` for workflow prompts and control.
|
|
123742
124615
|
- For transcripts, avoid whole-file reads. Get \`sessionFile\`/\`transcriptPath\` from \`stages\` or \`stage\`, preserve the exact path and platform separators, search with \`rg\`/\`grep\`, and read small relevant ranges; use explicit \`tail\` or \`limit\` only for a bounded preview.`,
|
|
123743
124616
|
`**Workflow authoring and handoffs**:
|
|
123744
124617
|
- When a user asks to create or edit a workflow, clarify only unresolved requirements that materially affect its purpose, inputs, stages, handoffs, validation, success criteria, or starter pattern. Read the workflow docs/examples, implement the TypeScript definition with normal coding tools, reload it, and run representative test inputs before presenting it. Use the create-spec skill when it adds value; it is not mandatory when context is already sufficient.
|
|
@@ -123800,26 +124673,26 @@ var WorkflowParametersSchema = Type36.Object({
|
|
|
123800
124673
|
Type36.Literal("stages"),
|
|
123801
124674
|
Type36.Literal("stage"),
|
|
123802
124675
|
Type36.Literal("transcript"),
|
|
123803
|
-
Type36.Literal("
|
|
124676
|
+
Type36.Literal("answer"),
|
|
123804
124677
|
Type36.Literal("pause"),
|
|
123805
124678
|
Type36.Literal("interrupt"),
|
|
123806
124679
|
Type36.Literal("quit"),
|
|
123807
124680
|
Type36.Literal("resume"),
|
|
123808
124681
|
Type36.Literal("reload")
|
|
123809
124682
|
], {
|
|
123810
|
-
description: "Workflow action: run/list/get/inputs/models/status, inspect stage metadata,
|
|
124683
|
+
description: "Workflow action: run/list/get/inputs/models/status, inspect stage metadata, answer pending prompts, pause/resume/interrupt/quit runs, inspect the configured model catalog, or reload workflow resources. 'status' without runId lists every workflow run in the current session with concise per-run summaries (status, timing, active stages, awaiting-input prompts); filter the listing with statusFilter. 'status' with runId returns one run's full detail. For transcript inspection, prefer status/stages/stage first to get sessionFile/transcriptPath, quote the exact path without rewriting separators (Windows backslashes are valid), then search it with rg/grep and read small ranges; transcript is path-only by default when sessionFile/transcriptPath exists, explicit tail/limit returns bounded previews, and missing transcript paths fall back to a small preview."
|
|
123811
124684
|
})),
|
|
123812
124685
|
runId: Type36.Optional(Type36.String({
|
|
123813
|
-
description: "Full 36-character run UUID for status/stages/stage/transcript/
|
|
124686
|
+
description: "Full 36-character run UUID for status/stages/stage/transcript/answer/pause/resume/interrupt/quit. Prefixes are not accepted; pass the id exactly as displayed. Omit runId with action 'status' to list all session runs and their statuses. Use '--all' or all:true for supported bulk run-control actions."
|
|
123814
124687
|
})),
|
|
123815
124688
|
all: Type36.Optional(Type36.Boolean({
|
|
123816
124689
|
description: "Apply supported run-control actions (pause/interrupt/quit) to all in-flight runs instead of one run; cannot be combined with stageId."
|
|
123817
124690
|
})),
|
|
123818
124691
|
stageId: Type36.Optional(Type36.String({
|
|
123819
|
-
description: "Exact stage id or exact stage name for stage-scoped inspection, transcript,
|
|
124692
|
+
description: "Exact stage id or exact stage name for stage-scoped inspection, transcript, answer, pause, or resume. Prefixes and partial names are not accepted. A nested stage id is the full 'runId:stageId' composite. For interrupt and quit it may also name an in-flight ctx.tool node by its exact tool:<argsHash> id or tool name, which aborts that single call."
|
|
123820
124693
|
})),
|
|
123821
124694
|
message: Type36.Optional(Type36.String({
|
|
123822
|
-
description: "
|
|
124695
|
+
description: "Prompt answer text for answer, or optional text forwarded when resuming paused work."
|
|
123823
124696
|
})),
|
|
123824
124697
|
statusFilter: Type36.Optional(Type36.Union([
|
|
123825
124698
|
Type36.Literal("pending"),
|
|
@@ -123851,21 +124724,11 @@ var WorkflowParametersSchema = Type36.Object({
|
|
|
123851
124724
|
description: "Transcript-only: include captured tool output entries when building inlined snapshot previews; this does not bypass the path-only default. Prefer rg/grep on the exact quoted sessionFile/transcriptPath for large outputs. Live session transcripts may not expose tool output."
|
|
123852
124725
|
})),
|
|
123853
124726
|
text: Type36.Optional(Type36.String({
|
|
123854
|
-
description: "Text
|
|
124727
|
+
description: "Text for a pending prompt answer."
|
|
123855
124728
|
})),
|
|
123856
124729
|
response: Type36.Optional(WorkflowResponseSchema),
|
|
123857
|
-
delivery: Type36.Optional(Type36.Union([
|
|
123858
|
-
Type36.Literal("auto"),
|
|
123859
|
-
Type36.Literal("answer"),
|
|
123860
|
-
Type36.Literal("prompt"),
|
|
123861
|
-
Type36.Literal("steer"),
|
|
123862
|
-
Type36.Literal("followUp"),
|
|
123863
|
-
Type36.Literal("resume")
|
|
123864
|
-
], {
|
|
123865
|
-
description: "Delivery mode for the send action: auto answers pending prompts first, then resumes paused stages, steers streaming stages, or queues a follow-up."
|
|
123866
|
-
})),
|
|
123867
124730
|
promptId: Type36.Optional(Type36.String({
|
|
123868
|
-
description: "Pending prompt identifier
|
|
124731
|
+
description: "Pending prompt identifier for the answer action."
|
|
123869
124732
|
})),
|
|
123870
124733
|
reason: Type36.Optional(Type36.String({
|
|
123871
124734
|
description: "Human-readable reason for the reload action, echoed in the reload result."
|
|
@@ -123877,7 +124740,7 @@ var WORKFLOW_TOOL_REQUEST_TIMEOUT_MS = 120000;
|
|
|
123877
124740
|
var MUTATING_WORKFLOW_ACTIONS = new Set([
|
|
123878
124741
|
"reload",
|
|
123879
124742
|
"run",
|
|
123880
|
-
"
|
|
124743
|
+
"answer",
|
|
123881
124744
|
"pause",
|
|
123882
124745
|
"resume",
|
|
123883
124746
|
"interrupt",
|
|
@@ -123998,10 +124861,11 @@ function factory(pi) {
|
|
|
123998
124861
|
const postMortemHandleResolver = createPostMortemHandleResolver(postMortemResolverDeps);
|
|
123999
124862
|
const overlay = buildWorkflowOverlay(pi, postMortemHandleResolver);
|
|
124000
124863
|
registerCompletedStageIntercomAskRouter(pi, postMortemHandleResolver);
|
|
124864
|
+
registerPendingStageIntercomBridge(pi, store);
|
|
124001
124865
|
const workflowCommands = new Map;
|
|
124002
124866
|
const storeWidgetRef = { current: null };
|
|
124003
124867
|
const intercomControlRef = { current: null };
|
|
124004
|
-
const executeWorkflowTool = makeExecuteWorkflowTool((ctx) => runtimeState.runtimeForContext(ctx), runtimeState.reloadWorkflowResources, runtimeState.ensureWorkflowResourcesLoaded
|
|
124868
|
+
const executeWorkflowTool = makeExecuteWorkflowTool((ctx) => runtimeState.runtimeForContext(ctx), runtimeState.reloadWorkflowResources, runtimeState.ensureWorkflowResourcesLoaded);
|
|
124005
124869
|
const executeWorkflowToolWithAutoAttach = async (args, ctx, signal, onRunAccepted) => {
|
|
124006
124870
|
const result = await executeWorkflowTool(args, ctx, signal, onRunAccepted);
|
|
124007
124871
|
if (workflowPolicyFromContext(ctx).mode === "interactive" && typeof args.workflow === "string" && result.action === "run" && result.status === "running" && result.runId.length > 0 && runtimeState.runtimeProxy.registry.get(args.workflow)?.autoAttach === true) {
|