@bastani/atomic 0.9.16-alpha.6 → 0.9.16-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -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 +680 -53
- 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 +109 -35
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/qlty/SKILL.md +123 -0
- package/dist/builtin/subagents/skills/qlty/references/coding-with-ai-agents.md +64 -0
- package/dist/builtin/subagents/skills/qlty/references/commands.md +291 -0
- package/dist/builtin/subagents/skills/qlty/references/plugins-and-extensions.md +228 -0
- package/dist/builtin/subagents/skills/qlty/references/quickstart.md +110 -0
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +173 -51
- package/dist/builtin/web-access/index.bundle.mjs +109 -35
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +23 -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} +137 -133
- 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-5n10x7j2.js +69730 -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-bfkmzv9h.js +156 -0
- package/dist/builtin/workflows/builtin/chunk-c53y8bdh.js +345 -0
- package/dist/builtin/workflows/builtin/chunk-cdtd3m3w.js +529 -0
- package/dist/builtin/workflows/builtin/chunk-cg9tmks0.js +206 -0
- package/dist/builtin/workflows/builtin/chunk-hdpj1dkw.js +2447 -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-qwzvgxnq.js +404 -0
- package/dist/builtin/workflows/builtin/chunk-qx2ptjs3.js +215 -0
- package/dist/builtin/workflows/builtin/chunk-v04c5qmd.js +1207 -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/chunk-zf28603f.js +1080 -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 +1250 -428
- package/dist/builtin/workflows/src/{index.bundle.mjs → index.js} +956 -427
- 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/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/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/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.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-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/intercom.md +15 -6
- package/docs/packages.md +2 -2
- package/docs/providers.md +8 -3
- package/docs/quickstart.md +3 -2
- package/docs/rpc.md +21 -4
- package/docs/settings.md +6 -4
- package/docs/skills.md +4 -0
- package/docs/subagents.md +1 -1
- package/docs/usage.md +1 -1
- package/docs/workflows.md +112 -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 -211
- 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 -100
- package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -455
- 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) {
|
|
@@ -19160,6 +19167,7 @@ async function loadVirtualModules() {
|
|
|
19160
19167
|
piAi,
|
|
19161
19168
|
piAiOauth,
|
|
19162
19169
|
piAiCloudflareGatewayBinding,
|
|
19170
|
+
properLockfile,
|
|
19163
19171
|
piCodingAgent
|
|
19164
19172
|
] = await Promise.all([
|
|
19165
19173
|
import("typebox"),
|
|
@@ -19171,6 +19179,7 @@ async function loadVirtualModules() {
|
|
|
19171
19179
|
import("@bastani/pi-ai/compat"),
|
|
19172
19180
|
import("@bastani/pi-ai/oauth"),
|
|
19173
19181
|
import("@bastani/pi-ai/api/cloudflare-gateway-binding"),
|
|
19182
|
+
import("proper-lockfile"),
|
|
19174
19183
|
Promise.resolve().then(() => (init_src(), exports_src))
|
|
19175
19184
|
]);
|
|
19176
19185
|
return {
|
|
@@ -19191,6 +19200,7 @@ async function loadVirtualModules() {
|
|
|
19191
19200
|
"@earendil-works/pi-ai/compat": piAi,
|
|
19192
19201
|
"@earendil-works/pi-ai/oauth": piAiOauth,
|
|
19193
19202
|
"@earendil-works/pi-ai/api/cloudflare-gateway-binding": piAiCloudflareGatewayBinding,
|
|
19203
|
+
"proper-lockfile": properLockfile,
|
|
19194
19204
|
"@bastani/atomic": piCodingAgent,
|
|
19195
19205
|
"@mariozechner/pi-agent-core": piAgentCore,
|
|
19196
19206
|
"@mariozechner/pi-tui": piTui,
|
|
@@ -26320,11 +26330,20 @@ function isCodexFastModeCandidateModelId(modelId) {
|
|
|
26320
26330
|
const provider = modelId?.split("/", 1)[0];
|
|
26321
26331
|
return provider !== undefined && isCodexFastModeSupportedProvider(provider);
|
|
26322
26332
|
}
|
|
26323
|
-
function
|
|
26324
|
-
return
|
|
26333
|
+
function isGitHubCopilotModel(model) {
|
|
26334
|
+
return model.provider === "github-copilot";
|
|
26325
26335
|
}
|
|
26326
|
-
function
|
|
26327
|
-
|
|
26336
|
+
function isGitHubCopilotFastModeSupportedModel(model, credential) {
|
|
26337
|
+
if (!isGitHubCopilotModel(model) || credential?.type !== "oauth")
|
|
26338
|
+
return false;
|
|
26339
|
+
const fastModelIds = credential.fastModelIds;
|
|
26340
|
+
return Array.isArray(fastModelIds) && fastModelIds.every((modelId) => typeof modelId === "string") && fastModelIds.includes(`${model.id}-fast`);
|
|
26341
|
+
}
|
|
26342
|
+
function isCodexFastModeSupportedModel(model, copilotCredential) {
|
|
26343
|
+
return isCodexFastModeSupportedProvider(model.provider) || model.api === "openai-codex-responses" || model.id !== undefined && isGitHubCopilotFastModeSupportedModel({ provider: model.provider, id: model.id }, copilotCredential);
|
|
26344
|
+
}
|
|
26345
|
+
function hasSupportedCodexFastModeModel(models, copilotCredential) {
|
|
26346
|
+
return models.some((model) => isCodexFastModeSupportedModel(model, copilotCredential));
|
|
26328
26347
|
}
|
|
26329
26348
|
function isWorkflowStageOrchestrationContext(context) {
|
|
26330
26349
|
return context?.kind === "workflow-stage";
|
|
@@ -26335,11 +26354,11 @@ function getCodexFastModeScope(context) {
|
|
|
26335
26354
|
function isCodexFastModeEnabledForScope(settings, scope) {
|
|
26336
26355
|
return settings[scope];
|
|
26337
26356
|
}
|
|
26338
|
-
function shouldApplyCodexFastModeForScope(model, settings, scope) {
|
|
26339
|
-
return isCodexFastModeSupportedModel(model) && isCodexFastModeEnabledForScope(settings, scope);
|
|
26357
|
+
function shouldApplyCodexFastModeForScope(model, settings, scope, copilotCredential) {
|
|
26358
|
+
return isCodexFastModeSupportedModel(model, copilotCredential) && isCodexFastModeEnabledForScope(settings, scope);
|
|
26340
26359
|
}
|
|
26341
|
-
function shouldApplyCodexFastMode(model, settings, context) {
|
|
26342
|
-
return shouldApplyCodexFastModeForScope(model, settings, getCodexFastModeScope(context));
|
|
26360
|
+
function shouldApplyCodexFastMode(model, settings, context, copilotCredential) {
|
|
26361
|
+
return shouldApplyCodexFastModeForScope(model, settings, getCodexFastModeScope(context), copilotCredential);
|
|
26343
26362
|
}
|
|
26344
26363
|
function usesFirstPartyCodexRouting(model) {
|
|
26345
26364
|
return model.provider === "openai-codex" && isFirstPartyCodexBaseUrl(model.baseUrl);
|
|
@@ -26365,8 +26384,8 @@ function withCodexFastModeHeaders(model, headers, enabled) {
|
|
|
26365
26384
|
setHeader(fastHeaders, CODEX_FAST_MODE_ROUTING_HEADER, `model=${model.id};tier=${CODEX_FAST_MODE_SERVICE_TIER}`);
|
|
26366
26385
|
return fastHeaders;
|
|
26367
26386
|
}
|
|
26368
|
-
function withCodexFastModeStreamOptions(
|
|
26369
|
-
if (!enabled) {
|
|
26387
|
+
function withCodexFastModeStreamOptions(model, options, enabled) {
|
|
26388
|
+
if (!enabled || model.provider === "github-copilot") {
|
|
26370
26389
|
return options;
|
|
26371
26390
|
}
|
|
26372
26391
|
return {
|
|
@@ -26500,10 +26519,14 @@ function streamWithCodexFastMode(model, context, options, streamers = DEFAULT_CO
|
|
|
26500
26519
|
function isObjectPayload(payload) {
|
|
26501
26520
|
return typeof payload === "object" && payload !== null && !Array.isArray(payload);
|
|
26502
26521
|
}
|
|
26503
|
-
function withCodexFastModePayload(payload, enabled) {
|
|
26504
|
-
if (!enabled || !isObjectPayload(payload)
|
|
26522
|
+
function withCodexFastModePayload(payload, enabled, model) {
|
|
26523
|
+
if (!enabled || !isObjectPayload(payload))
|
|
26505
26524
|
return payload;
|
|
26525
|
+
if (model?.provider === "github-copilot") {
|
|
26526
|
+
return payload.model === model.id ? { ...payload, model: `${model.id}-fast` } : payload;
|
|
26506
26527
|
}
|
|
26528
|
+
if (payload.service_tier !== undefined)
|
|
26529
|
+
return payload;
|
|
26507
26530
|
return {
|
|
26508
26531
|
...payload,
|
|
26509
26532
|
service_tier: CODEX_FAST_MODE_SERVICE_TIER
|
|
@@ -26653,7 +26676,7 @@ class FooterComponent {
|
|
|
26653
26676
|
pwd += ` • ${sessionName}`;
|
|
26654
26677
|
const modelName = state.model?.id || "no-model";
|
|
26655
26678
|
const fastModeSettings = this.session.settingsManager.getCodexFastModeSettings();
|
|
26656
|
-
const fastModeEnabled = state.model ? shouldApplyCodexFastMode(state.model, fastModeSettings, this.session.orchestrationContext) : false;
|
|
26679
|
+
const fastModeEnabled = state.model ? shouldApplyCodexFastMode(state.model, fastModeSettings, this.session.orchestrationContext, this.session.modelRuntime.getCredentialSnapshot?.("github-copilot")) : false;
|
|
26657
26680
|
let modelLabel2 = modelName;
|
|
26658
26681
|
if (state.model?.reasoning) {
|
|
26659
26682
|
const thinkingLevel = state.thinkingLevel || "off";
|
|
@@ -45421,14 +45444,18 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
45421
45444
|
|
|
45422
45445
|
class WorkflowStageAdmissionBoundary {
|
|
45423
45446
|
open = true;
|
|
45424
|
-
completed
|
|
45447
|
+
completed;
|
|
45425
45448
|
inFlight = new Map;
|
|
45426
45449
|
pending = new Set;
|
|
45427
45450
|
invocationContext = new AsyncLocalStorage;
|
|
45428
45451
|
closePromise;
|
|
45429
45452
|
drainAdmittedWork;
|
|
45430
|
-
constructor(drainAdmittedWork =
|
|
45431
|
-
this.drainAdmittedWork = drainAdmittedWork;
|
|
45453
|
+
constructor(drainAdmittedWork = undefined, completedKeys = []) {
|
|
45454
|
+
this.drainAdmittedWork = drainAdmittedWork ?? (async () => {});
|
|
45455
|
+
this.completed = new Set(completedKeys);
|
|
45456
|
+
}
|
|
45457
|
+
static restore(entries, drainAdmittedWork) {
|
|
45458
|
+
return new WorkflowStageAdmissionBoundary(drainAdmittedWork, Array.from(entries).flatMap((entry) => entry.type === "custom_message" && typeof entry.stageAdmissionKey === "string" ? [entry.stageAdmissionKey] : []));
|
|
45432
45459
|
}
|
|
45433
45460
|
admit(key, deliver, routeLate) {
|
|
45434
45461
|
if (key !== undefined) {
|
|
@@ -45667,7 +45694,7 @@ class AgentSessionBase {
|
|
|
45667
45694
|
this._subagentPolicy = config.subagentPolicy;
|
|
45668
45695
|
this._systemPromptTransform = config.systemPromptTransform;
|
|
45669
45696
|
const stageContext = config.orchestrationContext?.kind === "workflow-stage" ? config.orchestrationContext : undefined;
|
|
45670
|
-
this._workflowStageAdmission = stageContext?.messageAdmission?.boundary ?? (stageContext ?
|
|
45697
|
+
this._workflowStageAdmission = stageContext?.messageAdmission?.boundary ?? (stageContext ? WorkflowStageAdmissionBoundary.restore(this.sessionManager.getBranch()) : undefined);
|
|
45671
45698
|
if (this._workflowStageAdmission && stageContext && stageContext.messageAdmission === undefined) {
|
|
45672
45699
|
stageContext.messageAdmission = {
|
|
45673
45700
|
boundary: this._workflowStageAdmission,
|
|
@@ -45999,6 +46026,9 @@ class AuthStorage {
|
|
|
45999
46026
|
this.data = this.parseStorageData(content);
|
|
46000
46027
|
} catch {}
|
|
46001
46028
|
}
|
|
46029
|
+
peek(provider) {
|
|
46030
|
+
return this.data[provider];
|
|
46031
|
+
}
|
|
46002
46032
|
async read(provider) {
|
|
46003
46033
|
const credential = this.data[provider];
|
|
46004
46034
|
if (credential?.type !== "api_key")
|
|
@@ -47052,6 +47082,10 @@ function getReloadableStore(store) {
|
|
|
47052
47082
|
const reloadable = store;
|
|
47053
47083
|
return typeof reloadable.reload === "function" ? reloadable : undefined;
|
|
47054
47084
|
}
|
|
47085
|
+
function getSnapshotStore(store) {
|
|
47086
|
+
const snapshotStore = store;
|
|
47087
|
+
return typeof snapshotStore.peek === "function" ? snapshotStore : undefined;
|
|
47088
|
+
}
|
|
47055
47089
|
|
|
47056
47090
|
class RuntimeCredentials {
|
|
47057
47091
|
store;
|
|
@@ -47071,6 +47105,10 @@ class RuntimeCredentials {
|
|
|
47071
47105
|
async reload() {
|
|
47072
47106
|
await getReloadableStore(this.store)?.reload();
|
|
47073
47107
|
}
|
|
47108
|
+
peek(providerId) {
|
|
47109
|
+
const override = this.overrides.get(providerId);
|
|
47110
|
+
return override ? { type: "api_key", key: override } : getSnapshotStore(this.store)?.peek(providerId);
|
|
47111
|
+
}
|
|
47074
47112
|
async read(providerId, options) {
|
|
47075
47113
|
const override = this.overrides.get(providerId);
|
|
47076
47114
|
return override ? { type: "api_key", key: override } : this.store.read(providerId, options);
|
|
@@ -47506,6 +47544,9 @@ class ModelRuntime {
|
|
|
47506
47544
|
hasConfiguredAuth(providerId) {
|
|
47507
47545
|
return this.snapshot.configuredProviders.has(providerId);
|
|
47508
47546
|
}
|
|
47547
|
+
getCredentialSnapshot(providerId) {
|
|
47548
|
+
return this.credentials.peek(providerId);
|
|
47549
|
+
}
|
|
47509
47550
|
async getAuth(providerOrModel, overrides = {}) {
|
|
47510
47551
|
if (typeof providerOrModel === "string")
|
|
47511
47552
|
return this.models.getAuth(providerOrModel, overrides);
|
|
@@ -55461,7 +55502,7 @@ async function createAgentSession(options = {}) {
|
|
|
55461
55502
|
return filtered;
|
|
55462
55503
|
};
|
|
55463
55504
|
const extensionRunnerRef = {};
|
|
55464
|
-
const isCodexFastModeEnabled = (requestModel) => shouldApplyCodexFastMode(requestModel, settingsManager.getCodexFastModeSettings(), options.orchestrationContext);
|
|
55505
|
+
const isCodexFastModeEnabled = (requestModel) => shouldApplyCodexFastMode(requestModel, settingsManager.getCodexFastModeSettings(), options.orchestrationContext, modelRuntime.getCredentialSnapshot("github-copilot"));
|
|
55465
55506
|
agent = new Agent2({
|
|
55466
55507
|
initialState: {
|
|
55467
55508
|
systemPrompt: "",
|
|
@@ -55497,7 +55538,7 @@ async function createAgentSession(options = {}) {
|
|
|
55497
55538
|
const extensionProvider = modelRuntime.getRegisteredProviderConfig(requestModel.provider);
|
|
55498
55539
|
const usesExtensionStream = extensionProvider?.streamSimple !== undefined && requestModel.api === extensionProvider.api;
|
|
55499
55540
|
const transportHeaders = usesExtensionStream ? assembledHeaders : removeUnownedModelHeaders(assembledHeaders, model2.headers, requestHeaders);
|
|
55500
|
-
if (fastModeEnabled && !usesExtensionStream && !authResult) {
|
|
55541
|
+
if (fastModeEnabled && !isGitHubCopilotModel(model2) && !usesExtensionStream && !authResult) {
|
|
55501
55542
|
throw new Error(`No API key found for "${model2.provider}"`);
|
|
55502
55543
|
}
|
|
55503
55544
|
const codexFastModeStreamOptions = withCodexFastModeStreamOptions(requestModel, {
|
|
@@ -55514,7 +55555,7 @@ async function createAgentSession(options = {}) {
|
|
|
55514
55555
|
if (usesExtensionStream) {
|
|
55515
55556
|
return modelRuntime.streamSimple(requestModel, context, codexFastModeStreamOptions);
|
|
55516
55557
|
}
|
|
55517
|
-
if (fastModeEnabled) {
|
|
55558
|
+
if (fastModeEnabled && !isGitHubCopilotModel(requestModel)) {
|
|
55518
55559
|
return streamWithCodexFastMode(requestModel, context, codexFastModeStreamOptions);
|
|
55519
55560
|
}
|
|
55520
55561
|
const transportOptions = usesChatGptCodexTransport(requestModel) && codexFastModeStreamOptions ? withChatGptCodexTransportRouting(requestModel, codexFastModeStreamOptions, false) : codexFastModeStreamOptions;
|
|
@@ -55522,7 +55563,7 @@ async function createAgentSession(options = {}) {
|
|
|
55522
55563
|
},
|
|
55523
55564
|
onPayload: async (payload, model2) => {
|
|
55524
55565
|
const fastModeEnabled = isCodexFastModeEnabled(model2);
|
|
55525
|
-
const guardedPayload = withCodexFastModePayload(payload, fastModeEnabled);
|
|
55566
|
+
const guardedPayload = withCodexFastModePayload(payload, fastModeEnabled, model2);
|
|
55526
55567
|
const sourceMessages = lastConvertedLlmMessages;
|
|
55527
55568
|
const replayGuardedPayload = sourceMessages ? restoreAnthropicReplayThinkingBlocks(guardedPayload, sourceMessages, model2) : guardedPayload;
|
|
55528
55569
|
const runner = extensionRunnerRef.current;
|
|
@@ -59987,6 +60028,31 @@ class RemoteQueuePause {
|
|
|
59987
60028
|
var init_remote_queue_pause = () => {};
|
|
59988
60029
|
|
|
59989
60030
|
// src/modes/interactive-engine/isolated-runtime.ts
|
|
60031
|
+
import { clampThinkingLevel as clampThinkingLevel5 } from "@bastani/pi-ai/compat";
|
|
60032
|
+
function applyPersistedModelDefault(session, model, alreadyInScope) {
|
|
60033
|
+
session.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
|
|
60034
|
+
if (alreadyInScope || session.scopedModels.length === 0)
|
|
60035
|
+
return;
|
|
60036
|
+
const enabledModels = session.settingsManager.getEnabledModels();
|
|
60037
|
+
if (!enabledModels?.length)
|
|
60038
|
+
return;
|
|
60039
|
+
const modelReference = `${model.provider}/${model.id}`;
|
|
60040
|
+
if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
|
|
60041
|
+
return;
|
|
60042
|
+
session.settingsManager.setEnabledModels([...enabledModels, modelReference]);
|
|
60043
|
+
}
|
|
60044
|
+
function thinkingPersistTarget(result) {
|
|
60045
|
+
if (!result.provider || !result.modelId)
|
|
60046
|
+
return;
|
|
60047
|
+
return { provider: result.provider, modelId: result.modelId };
|
|
60048
|
+
}
|
|
60049
|
+
function applyPersistedThinkingDefault(session, level, target) {
|
|
60050
|
+
if (target) {
|
|
60051
|
+
session.settingsManager.setModelThinkingLevel(target.provider, target.modelId, level);
|
|
60052
|
+
return;
|
|
60053
|
+
}
|
|
60054
|
+
session.settingsManager.setDefaultThinkingLevel(level);
|
|
60055
|
+
}
|
|
59990
60056
|
var IsolatedInteractiveRuntime;
|
|
59991
60057
|
var init_isolated_runtime = __esm(() => {
|
|
59992
60058
|
init_agent_session_runtime();
|
|
@@ -60005,6 +60071,7 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60005
60071
|
steeringMessages = [];
|
|
60006
60072
|
followUpMessages = [];
|
|
60007
60073
|
queueUpdateGeneration = 0;
|
|
60074
|
+
thinkingEpoch = 0;
|
|
60008
60075
|
pendingQueueClear;
|
|
60009
60076
|
engineCallbackActive = false;
|
|
60010
60077
|
queuePause;
|
|
@@ -60369,43 +60436,56 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60369
60436
|
},
|
|
60370
60437
|
setModel: {
|
|
60371
60438
|
configurable: true,
|
|
60372
|
-
value: async (model) => {
|
|
60373
|
-
const selected = await this.client.setModel(model.provider, model.id);
|
|
60374
|
-
|
|
60439
|
+
value: async (model, options) => {
|
|
60440
|
+
const selected = await this.client.setModel(model.provider, model.id, options);
|
|
60441
|
+
const nextModel = session.modelRuntime.getModel(selected.provider, selected.id) ?? model;
|
|
60442
|
+
session.agent.state.model = nextModel;
|
|
60375
60443
|
this.resolveModelFallback();
|
|
60444
|
+
if (options?.persist === true)
|
|
60445
|
+
await this.syncPersistedModelCatalog(session, nextModel);
|
|
60376
60446
|
}
|
|
60377
60447
|
},
|
|
60378
60448
|
setThinkingLevel: {
|
|
60379
60449
|
configurable: true,
|
|
60380
|
-
value: (level) => {
|
|
60381
|
-
|
|
60382
|
-
|
|
60450
|
+
value: (level, options) => {
|
|
60451
|
+
const availableLevels = session.getAvailableThinkingLevels();
|
|
60452
|
+
const effectiveLevel = availableLevels.includes(level) ? level : session.model ? clampThinkingLevel5(session.model, level) : "off";
|
|
60453
|
+
session.agent.state.thinkingLevel = effectiveLevel;
|
|
60454
|
+
const epoch = ++this.thinkingEpoch;
|
|
60455
|
+
this.dispatchBestEffort("set thinking level", this.client.setThinkingLevelAck(level, options).then((result) => {
|
|
60456
|
+
this.applyThinkingAck(session, epoch, result, options?.persist === true);
|
|
60457
|
+
}));
|
|
60383
60458
|
}
|
|
60384
60459
|
},
|
|
60385
60460
|
cycleModel: {
|
|
60386
60461
|
configurable: true,
|
|
60387
|
-
value: async (direction) => {
|
|
60462
|
+
value: async (direction, options) => {
|
|
60388
60463
|
const previousModel = session.model;
|
|
60389
|
-
const result = await this.client.cycleModel(direction);
|
|
60464
|
+
const result = await this.client.cycleModel(direction, options);
|
|
60390
60465
|
if (!result)
|
|
60391
60466
|
return;
|
|
60392
60467
|
const model = session.modelRuntime.getModel(result.model.provider, result.model.id) ?? result.model;
|
|
60393
60468
|
session.agent.state.model = model;
|
|
60394
60469
|
session.agent.state.thinkingLevel = result.thinkingLevel;
|
|
60395
60470
|
this.resolveModelFallbackAfterExplicitModelSelection(previousModel, model);
|
|
60471
|
+
if (options?.persist === true)
|
|
60472
|
+
await this.syncPersistedModelCatalog(session, model);
|
|
60396
60473
|
return { ...result, model };
|
|
60397
60474
|
}
|
|
60398
60475
|
},
|
|
60399
60476
|
cycleThinkingLevel: {
|
|
60400
60477
|
configurable: true,
|
|
60401
|
-
value: () => {
|
|
60478
|
+
value: (options) => {
|
|
60402
60479
|
const levels = session.getAvailableThinkingLevels();
|
|
60403
60480
|
if (levels.length <= 1)
|
|
60404
60481
|
return;
|
|
60405
60482
|
const current = levels.indexOf(session.thinkingLevel);
|
|
60406
60483
|
const level = levels[(current + 1) % levels.length];
|
|
60407
60484
|
session.agent.state.thinkingLevel = level;
|
|
60408
|
-
|
|
60485
|
+
const epoch = ++this.thinkingEpoch;
|
|
60486
|
+
this.dispatchBestEffort("cycle thinking level", this.client.setThinkingLevelAck(level, options).then((result) => {
|
|
60487
|
+
this.applyThinkingAck(session, epoch, result, options?.persist === true);
|
|
60488
|
+
}));
|
|
60409
60489
|
return level;
|
|
60410
60490
|
}
|
|
60411
60491
|
},
|
|
@@ -60449,6 +60529,14 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60449
60529
|
this.engineCallbackActive = false;
|
|
60450
60530
|
}
|
|
60451
60531
|
}
|
|
60532
|
+
applyThinkingAck(session, epoch, result, persist) {
|
|
60533
|
+
if (persist) {
|
|
60534
|
+
applyPersistedThinkingDefault(session, result.level, thinkingPersistTarget(result));
|
|
60535
|
+
}
|
|
60536
|
+
if (epoch === this.thinkingEpoch) {
|
|
60537
|
+
session.agent.state.thinkingLevel = result.level;
|
|
60538
|
+
}
|
|
60539
|
+
}
|
|
60452
60540
|
dispatchBestEffort(label, operation) {
|
|
60453
60541
|
operation.catch((error) => {
|
|
60454
60542
|
if (this.health.isRecovering())
|
|
@@ -60489,6 +60577,12 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60489
60577
|
}
|
|
60490
60578
|
});
|
|
60491
60579
|
}
|
|
60580
|
+
async syncPersistedModelCatalog(session, model) {
|
|
60581
|
+
const alreadyInScope = session.scopedModels.some((scoped) => scoped.model.provider === model.provider && scoped.model.id === model.id);
|
|
60582
|
+
const catalog = await this.client.requestInternal({ type: "get_available_models" });
|
|
60583
|
+
this.remoteModelCatalog.apply(catalog);
|
|
60584
|
+
applyPersistedModelDefault(session, model, alreadyInScope);
|
|
60585
|
+
}
|
|
60492
60586
|
refreshSessionView() {
|
|
60493
60587
|
const session = super.session;
|
|
60494
60588
|
const sessionFile = session.sessionFile;
|
|
@@ -60528,6 +60622,7 @@ var init_isolated_runtime = __esm(() => {
|
|
|
60528
60622
|
session.agent.state.model = event.model;
|
|
60529
60623
|
break;
|
|
60530
60624
|
case "thinking_level_changed":
|
|
60625
|
+
this.thinkingEpoch += 1;
|
|
60531
60626
|
session.agent.state.thinkingLevel = event.level;
|
|
60532
60627
|
break;
|
|
60533
60628
|
case "session_info_changed":
|
|
@@ -61741,7 +61836,7 @@ var init_slash_commands = __esm(() => {
|
|
|
61741
61836
|
{ name: "tree", description: "Navigate session tree (switch branches)" },
|
|
61742
61837
|
{ name: "thinking", description: "Set thinking level", argumentHint: "<level>" },
|
|
61743
61838
|
{ name: "scoped-models", description: "Enable/disable models for ctrl+p cycling" },
|
|
61744
|
-
{ name: "fast", description: "Configure
|
|
61839
|
+
{ name: "fast", description: "Configure OpenAI fast mode for chat and workflows in supported models" },
|
|
61745
61840
|
{ name: "export", description: "Export session (HTML default, or specify path: .html/.jsonl)" },
|
|
61746
61841
|
{ name: "import", description: "Import and resume a session from a JSONL file" },
|
|
61747
61842
|
{ name: "share", description: "Share session as a secret GitHub gist" },
|
|
@@ -63203,7 +63298,7 @@ var init_interactive_autocomplete = __esm(() => {
|
|
|
63203
63298
|
return [...this.session.modelRuntime.getAvailableSnapshot()];
|
|
63204
63299
|
};
|
|
63205
63300
|
InteractiveModeBase.prototype.hasCodexFastModeSupportedModels = function() {
|
|
63206
|
-
return hasSupportedCodexFastModeModel(this.getCodexFastModeCandidateModels());
|
|
63301
|
+
return hasSupportedCodexFastModeModel(this.getCodexFastModeCandidateModels(), this.session.modelRuntime.getCredentialSnapshot?.("github-copilot"));
|
|
63207
63302
|
};
|
|
63208
63303
|
InteractiveModeBase.prototype.buildRemoteSlashCommands = function(localCommands) {
|
|
63209
63304
|
const remote = getInteractiveEngineRemoteCommands(this.runtimeHost);
|
|
@@ -63891,7 +63986,7 @@ var init_interactive_startup = __esm(() => {
|
|
|
63891
63986
|
if (!model) {
|
|
63892
63987
|
return modelLabel2;
|
|
63893
63988
|
}
|
|
63894
|
-
const fastModeEnabled = shouldApplyCodexFastMode(model, this.session.settingsManager.getCodexFastModeSettings(), this.session.orchestrationContext);
|
|
63989
|
+
const fastModeEnabled = shouldApplyCodexFastMode(model, this.session.settingsManager.getCodexFastModeSettings(), this.session.orchestrationContext, this.session.modelRuntime.getCredentialSnapshot?.("github-copilot"));
|
|
63895
63990
|
return formatCodexFastModeModelLabel(modelLabel2, fastModeEnabled);
|
|
63896
63991
|
};
|
|
63897
63992
|
InteractiveModeBase.prototype.getStartupIdentityText = function(maxWidth, gap = 0, manifestoPhase = 4) {
|
|
@@ -68406,7 +68501,7 @@ var init_interactive_selectors = __esm(() => {
|
|
|
68406
68501
|
});
|
|
68407
68502
|
|
|
68408
68503
|
// src/modes/interactive/interactive-model-routing.ts
|
|
68409
|
-
import { clampThinkingLevel as
|
|
68504
|
+
import { clampThinkingLevel as clampThinkingLevel6 } from "@bastani/pi-ai/compat";
|
|
68410
68505
|
function resolveThinkingSelectorDefault(rawDefault, availableLevels, model) {
|
|
68411
68506
|
if (rawDefault === undefined)
|
|
68412
68507
|
return;
|
|
@@ -68414,7 +68509,7 @@ function resolveThinkingSelectorDefault(rawDefault, availableLevels, model) {
|
|
|
68414
68509
|
return rawDefault;
|
|
68415
68510
|
if (!model)
|
|
68416
68511
|
return availableLevels.includes("off") ? "off" : availableLevels[0];
|
|
68417
|
-
const clamped =
|
|
68512
|
+
const clamped = clampThinkingLevel6(model, rawDefault);
|
|
68418
68513
|
if (availableLevels.includes(clamped))
|
|
68419
68514
|
return clamped;
|
|
68420
68515
|
return availableLevels.includes("off") ? "off" : availableLevels[0];
|
|
@@ -70778,11 +70873,20 @@ class RpcClientApi {
|
|
|
70778
70873
|
async getState() {
|
|
70779
70874
|
return this.data(await this.request({ type: "get_state" }));
|
|
70780
70875
|
}
|
|
70781
|
-
async setModel(provider, modelId) {
|
|
70782
|
-
return this.data(await this.request({
|
|
70876
|
+
async setModel(provider, modelId, options) {
|
|
70877
|
+
return this.data(await this.request({
|
|
70878
|
+
type: "set_model",
|
|
70879
|
+
provider,
|
|
70880
|
+
modelId,
|
|
70881
|
+
...options?.persist === true ? { persist: true } : {}
|
|
70882
|
+
}));
|
|
70783
70883
|
}
|
|
70784
|
-
async cycleModel(direction) {
|
|
70785
|
-
return this.data(await this.request({
|
|
70884
|
+
async cycleModel(direction, options) {
|
|
70885
|
+
return this.data(await this.request({
|
|
70886
|
+
type: "cycle_model",
|
|
70887
|
+
direction,
|
|
70888
|
+
...options?.persist === true ? { persist: true } : {}
|
|
70889
|
+
}));
|
|
70786
70890
|
}
|
|
70787
70891
|
async getAvailableModels() {
|
|
70788
70892
|
return this.data(await this.request({ type: "get_available_models" })).models;
|
|
@@ -70816,6 +70920,20 @@ class RpcClientApi {
|
|
|
70816
70920
|
async setThinkingLevel(level) {
|
|
70817
70921
|
await this.request({ type: "set_thinking_level", level });
|
|
70818
70922
|
}
|
|
70923
|
+
async setThinkingLevelAck(level, options) {
|
|
70924
|
+
const response = await this.request({
|
|
70925
|
+
type: "set_thinking_level",
|
|
70926
|
+
level,
|
|
70927
|
+
...options?.persist === true ? { persist: true } : {}
|
|
70928
|
+
});
|
|
70929
|
+
if (!response.success) {
|
|
70930
|
+
return this.data(response);
|
|
70931
|
+
}
|
|
70932
|
+
if (response.command === "set_thinking_level" && "data" in response && response.data) {
|
|
70933
|
+
return response.data;
|
|
70934
|
+
}
|
|
70935
|
+
return { level };
|
|
70936
|
+
}
|
|
70819
70937
|
async cycleThinkingLevel() {
|
|
70820
70938
|
return this.data(await this.request({ type: "cycle_thinking_level" }));
|
|
70821
70939
|
}
|
|
@@ -72834,13 +72952,13 @@ function createRpcCommandHandler({
|
|
|
72834
72952
|
if (!model) {
|
|
72835
72953
|
return createRpcErrorResponse(id, "set_model", `Model not found: ${command.provider}/${command.modelId}`);
|
|
72836
72954
|
}
|
|
72837
|
-
await session.setModel(model);
|
|
72955
|
+
await session.setModel(model, command.persist === true ? { persist: true } : {});
|
|
72838
72956
|
runtimeHost.resolveModelFallback();
|
|
72839
72957
|
return createRpcSuccessResponse(id, "set_model", session.model ?? model);
|
|
72840
72958
|
}
|
|
72841
72959
|
case "cycle_model": {
|
|
72842
72960
|
const previousModel = session.model;
|
|
72843
|
-
const result = await session.cycleModel(command.direction);
|
|
72961
|
+
const result = await session.cycleModel(command.direction, command.persist === true ? { persist: true } : {});
|
|
72844
72962
|
runtimeHost.resolveModelFallbackAfterExplicitModelSelection(previousModel, result?.model);
|
|
72845
72963
|
return createRpcSuccessResponse(id, "cycle_model", result ?? null);
|
|
72846
72964
|
}
|
|
@@ -72903,8 +73021,12 @@ function createRpcCommandHandler({
|
|
|
72903
73021
|
}
|
|
72904
73022
|
}
|
|
72905
73023
|
case "set_thinking_level": {
|
|
72906
|
-
session.setThinkingLevel(command.level);
|
|
72907
|
-
|
|
73024
|
+
session.setThinkingLevel(command.level, command.persist === true ? { persist: true } : {});
|
|
73025
|
+
const model = session.model;
|
|
73026
|
+
return createRpcSuccessResponse(id, "set_thinking_level", {
|
|
73027
|
+
level: session.thinkingLevel,
|
|
73028
|
+
...model ? { provider: model.provider, modelId: model.id } : {}
|
|
73029
|
+
});
|
|
72908
73030
|
}
|
|
72909
73031
|
case "cycle_thinking_level": {
|
|
72910
73032
|
const level = session.cycleThinkingLevel();
|
|
@@ -76717,6 +76839,152 @@ function subscribeIntercomControl(pi, callbacks) {
|
|
|
76717
76839
|
};
|
|
76718
76840
|
}
|
|
76719
76841
|
|
|
76842
|
+
// dist/builtin/workflows/src/shared/pending-stage-delivery.ts
|
|
76843
|
+
var PENDING_STAGE_MESSAGE_LIMIT = 50;
|
|
76844
|
+
var PENDING_STAGE_UNDELIVERABLE_NOTIFICATION_PREFIX = "atomic-pending-stage-undeliverable";
|
|
76845
|
+
function queueStageMessage(messages2, input2, senderGroup, runGroup, stageIdentity) {
|
|
76846
|
+
if (normalizeDeliveryGroup(senderGroup) !== normalizeDeliveryGroup(runGroup)) {
|
|
76847
|
+
return { ok: false, reason: "group_mismatch", runId: input2.runId, stageKey: input2.stageKey };
|
|
76848
|
+
}
|
|
76849
|
+
const messageId = input2.message.id;
|
|
76850
|
+
const queued = pendingStageMessagesFor(messages2, input2.runId, input2.stageKey, stageIdentity);
|
|
76851
|
+
const existing = messages2.find((entry2) => entry2.runId === input2.runId && entry2.id === messageId);
|
|
76852
|
+
if (existing !== undefined) {
|
|
76853
|
+
if (pendingStageMessageSignature(existing, stageIdentity) !== pendingStageMessageSignature(input2, stageIdentity)) {
|
|
76854
|
+
return {
|
|
76855
|
+
ok: false,
|
|
76856
|
+
reason: "message_id_conflict",
|
|
76857
|
+
runId: input2.runId,
|
|
76858
|
+
stageKey: input2.stageKey,
|
|
76859
|
+
messageId
|
|
76860
|
+
};
|
|
76861
|
+
}
|
|
76862
|
+
const queuedPosition = queued.indexOf(existing);
|
|
76863
|
+
return {
|
|
76864
|
+
ok: true,
|
|
76865
|
+
messages: messages2,
|
|
76866
|
+
entry: existing,
|
|
76867
|
+
...queuedPosition >= 0 ? { position: queuedPosition + 1 } : {},
|
|
76868
|
+
deduplicated: true
|
|
76869
|
+
};
|
|
76870
|
+
}
|
|
76871
|
+
if (queued.length >= PENDING_STAGE_MESSAGE_LIMIT) {
|
|
76872
|
+
return {
|
|
76873
|
+
ok: false,
|
|
76874
|
+
reason: "capacity",
|
|
76875
|
+
limit: PENDING_STAGE_MESSAGE_LIMIT,
|
|
76876
|
+
runId: input2.runId,
|
|
76877
|
+
stageKey: input2.stageKey
|
|
76878
|
+
};
|
|
76879
|
+
}
|
|
76880
|
+
const entry = {
|
|
76881
|
+
...input2,
|
|
76882
|
+
id: messageId,
|
|
76883
|
+
...stageIdentity !== undefined ? { stageId: stageIdentity.id } : {},
|
|
76884
|
+
...stageIdentity?.replayKey !== undefined ? { stageReplayKey: stageIdentity.replayKey } : {},
|
|
76885
|
+
admissionOrder: nextAdmissionOrder(messages2, input2.runId),
|
|
76886
|
+
status: "queued"
|
|
76887
|
+
};
|
|
76888
|
+
return {
|
|
76889
|
+
ok: true,
|
|
76890
|
+
messages: [...messages2, entry],
|
|
76891
|
+
entry,
|
|
76892
|
+
position: queued.length + 1,
|
|
76893
|
+
deduplicated: false
|
|
76894
|
+
};
|
|
76895
|
+
}
|
|
76896
|
+
function pendingStageMessagesFor(messages2, runId, stageKey, stageIdentity) {
|
|
76897
|
+
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);
|
|
76898
|
+
}
|
|
76899
|
+
function markPendingStageMessageDelivered(messages2, runId, stageKey, messageId, deliveredAt, stageIdentity) {
|
|
76900
|
+
return updateQueuedPendingStageMessage(messages2, runId, stageKey, messageId, stageIdentity, (entry) => ({
|
|
76901
|
+
...entry,
|
|
76902
|
+
status: "delivered",
|
|
76903
|
+
deliveredAt
|
|
76904
|
+
}));
|
|
76905
|
+
}
|
|
76906
|
+
function markPendingStageMessageUndeliverable(messages2, runId, stageKey, messageId, reason, stageIdentity) {
|
|
76907
|
+
return updateQueuedPendingStageMessage(messages2, runId, stageKey, messageId, stageIdentity, (entry) => ({
|
|
76908
|
+
...entry,
|
|
76909
|
+
status: "undeliverable",
|
|
76910
|
+
undeliverableReason: reason,
|
|
76911
|
+
undeliverableNotificationId: pendingStageUndeliverableNotificationId(entry)
|
|
76912
|
+
}));
|
|
76913
|
+
}
|
|
76914
|
+
function markPendingStageMessageUndeliverableNotified(messages2, runId, stageKey, messageId, notificationId, notifiedAt) {
|
|
76915
|
+
const index = messages2.findIndex((entry) => matchesPendingStage(entry, runId, stageKey) && entry.id === messageId && entry.status === "undeliverable" && entry.undeliverableNotificationId === notificationId && entry.undeliverableNotifiedAt === undefined);
|
|
76916
|
+
if (index < 0)
|
|
76917
|
+
return messages2;
|
|
76918
|
+
const next = [...messages2];
|
|
76919
|
+
next[index] = { ...next[index], undeliverableNotifiedAt: notifiedAt };
|
|
76920
|
+
return next;
|
|
76921
|
+
}
|
|
76922
|
+
function pendingStageUndeliverableNotificationId(entry) {
|
|
76923
|
+
return [
|
|
76924
|
+
PENDING_STAGE_UNDELIVERABLE_NOTIFICATION_PREFIX,
|
|
76925
|
+
encodeURIComponent(entry.runId),
|
|
76926
|
+
encodeURIComponent(entry.stageKey),
|
|
76927
|
+
encodeURIComponent(entry.id)
|
|
76928
|
+
].join(":");
|
|
76929
|
+
}
|
|
76930
|
+
function updateQueuedPendingStageMessage(messages2, runId, stageKey, messageId, stageIdentity, update2) {
|
|
76931
|
+
const index = messages2.findIndex((entry) => matchesPendingStage(entry, runId, stageKey, stageIdentity) && entry.id === messageId && entry.status === "queued");
|
|
76932
|
+
if (index < 0)
|
|
76933
|
+
return messages2;
|
|
76934
|
+
const next = [...messages2];
|
|
76935
|
+
next[index] = update2(next[index]);
|
|
76936
|
+
return next;
|
|
76937
|
+
}
|
|
76938
|
+
function matchesPendingStage(entry, runId, stageKey, stageIdentity) {
|
|
76939
|
+
if (entry.runId !== runId)
|
|
76940
|
+
return false;
|
|
76941
|
+
if (stageIdentity === undefined)
|
|
76942
|
+
return entry.stageKey === stageKey;
|
|
76943
|
+
return entry.stageId === stageIdentity.id || entry.stageReplayKey !== undefined && entry.stageReplayKey === stageIdentity.replayKey || entry.stageId === undefined && stageIdentity.aliases.includes(entry.stageKey);
|
|
76944
|
+
}
|
|
76945
|
+
function nextAdmissionOrder(messages2, runId) {
|
|
76946
|
+
let greatest = 0;
|
|
76947
|
+
let legacyPosition = 0;
|
|
76948
|
+
for (const entry of messages2) {
|
|
76949
|
+
if (entry.runId !== runId)
|
|
76950
|
+
continue;
|
|
76951
|
+
legacyPosition += 1;
|
|
76952
|
+
greatest = Math.max(greatest, entry.admissionOrder ?? legacyPosition);
|
|
76953
|
+
}
|
|
76954
|
+
return greatest + 1;
|
|
76955
|
+
}
|
|
76956
|
+
function pendingStageMessageSignature(entry, stageIdentity) {
|
|
76957
|
+
const storedTarget = "status" in entry ? entry.stageReplayKey ?? entry.stageId : undefined;
|
|
76958
|
+
const { timestamp: transportTimestamp, ...logicalMessage } = entry.message;
|
|
76959
|
+
return stableJson({
|
|
76960
|
+
target: storedTarget ?? stageIdentity?.replayKey ?? stageIdentity?.id ?? entry.stageKey,
|
|
76961
|
+
sender: entry.senderReturnAddress ?? entry.from.id,
|
|
76962
|
+
message: {
|
|
76963
|
+
...logicalMessage,
|
|
76964
|
+
expectsReply: logicalMessage.expectsReply ?? false,
|
|
76965
|
+
content: {
|
|
76966
|
+
...logicalMessage.content,
|
|
76967
|
+
attachments: logicalMessage.content.attachments ?? []
|
|
76968
|
+
}
|
|
76969
|
+
}
|
|
76970
|
+
});
|
|
76971
|
+
}
|
|
76972
|
+
function stableJson(value) {
|
|
76973
|
+
return JSON.stringify(sortJsonValue(value));
|
|
76974
|
+
}
|
|
76975
|
+
function sortJsonValue(value) {
|
|
76976
|
+
if (Array.isArray(value))
|
|
76977
|
+
return value.map(sortJsonValue);
|
|
76978
|
+
if (typeof value !== "object" || value === null)
|
|
76979
|
+
return value;
|
|
76980
|
+
return Object.fromEntries(Object.entries(value).filter(([, nested]) => nested !== undefined).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, sortJsonValue(nested)]));
|
|
76981
|
+
}
|
|
76982
|
+
function normalizeDeliveryGroup(value) {
|
|
76983
|
+
if (typeof value !== "string")
|
|
76984
|
+
return "default";
|
|
76985
|
+
const trimmed = value.trim();
|
|
76986
|
+
return trimmed.length > 0 ? trimmed : "default";
|
|
76987
|
+
}
|
|
76720
76988
|
// dist/builtin/workflows/src/shared/session-scoped-singleton.ts
|
|
76721
76989
|
init_src();
|
|
76722
76990
|
var SHARED_STATES_KEY = Symbol.for("atomic-workflows/session-scoped-singleton-pre-adoption@1");
|
|
@@ -77229,6 +77497,7 @@ function compactStage(stage) {
|
|
|
77229
77497
|
inputRequest,
|
|
77230
77498
|
notices,
|
|
77231
77499
|
mcpScope: _mcpScope,
|
|
77500
|
+
pendingStageDeliveryAvailable: _pendingStageDeliveryAvailable,
|
|
77232
77501
|
attemptedModels: _attemptedModels,
|
|
77233
77502
|
modelAttempts: _modelAttempts,
|
|
77234
77503
|
result: _result,
|
|
@@ -77484,6 +77753,133 @@ function createStoreContext(state = createStoreState()) {
|
|
|
77484
77753
|
};
|
|
77485
77754
|
}
|
|
77486
77755
|
|
|
77756
|
+
// dist/builtin/workflows/src/shared/store-pending-stage-delivery-methods.ts
|
|
77757
|
+
function createPendingStageDeliveryStoreMethods(context) {
|
|
77758
|
+
const transitions = new Map;
|
|
77759
|
+
const serialize = async (runId, transition) => {
|
|
77760
|
+
const previous2 = transitions.get(runId) ?? Promise.resolve();
|
|
77761
|
+
const result = previous2.catch(() => {
|
|
77762
|
+
return;
|
|
77763
|
+
}).then(transition);
|
|
77764
|
+
const settled = result.then(() => {
|
|
77765
|
+
return;
|
|
77766
|
+
}, () => {
|
|
77767
|
+
return;
|
|
77768
|
+
});
|
|
77769
|
+
transitions.set(runId, settled);
|
|
77770
|
+
settled.finally(() => {
|
|
77771
|
+
if (transitions.get(runId) === settled)
|
|
77772
|
+
transitions.delete(runId);
|
|
77773
|
+
});
|
|
77774
|
+
return await result;
|
|
77775
|
+
};
|
|
77776
|
+
return {
|
|
77777
|
+
async queueStageMessage(input2, senderGroup, runGroup, backend) {
|
|
77778
|
+
return await serialize(input2.runId, async () => {
|
|
77779
|
+
const run = context.findRun(input2.runId);
|
|
77780
|
+
if (run === undefined)
|
|
77781
|
+
return;
|
|
77782
|
+
const stageIdentity = resolvePendingStageIdentity(run, input2.stageKey);
|
|
77783
|
+
const result = queueStageMessage(run.pendingStageMessages ?? [], input2, senderGroup, runGroup, stageIdentity);
|
|
77784
|
+
if (result.ok && !result.deduplicated) {
|
|
77785
|
+
await persistTransition(backend, input2.runId, result.messages);
|
|
77786
|
+
run.pendingStageMessages = [...result.messages];
|
|
77787
|
+
context.bumpAndNotify();
|
|
77788
|
+
}
|
|
77789
|
+
return result;
|
|
77790
|
+
});
|
|
77791
|
+
},
|
|
77792
|
+
async validateLiveStageMessage(input2) {
|
|
77793
|
+
return await serialize(input2.runId, async () => {
|
|
77794
|
+
const run = context.findRun(input2.runId);
|
|
77795
|
+
if (run === undefined)
|
|
77796
|
+
return;
|
|
77797
|
+
const result = queueStageMessage(run.pendingStageMessages ?? [], input2, undefined, undefined, resolvePendingStageIdentity(run, input2.stageKey));
|
|
77798
|
+
if (!result.ok) {
|
|
77799
|
+
return result.reason === "message_id_conflict" ? { outcome: "message_id_conflict", messageId: result.messageId } : { outcome: "forward" };
|
|
77800
|
+
}
|
|
77801
|
+
if (!result.deduplicated)
|
|
77802
|
+
return { outcome: "forward" };
|
|
77803
|
+
if (result.entry.status === "delivered")
|
|
77804
|
+
return { outcome: "delivered" };
|
|
77805
|
+
if (result.entry.status === "undeliverable") {
|
|
77806
|
+
return { outcome: "undeliverable", reason: result.entry.undeliverableReason };
|
|
77807
|
+
}
|
|
77808
|
+
if (result.position === undefined) {
|
|
77809
|
+
throw new Error(`atomic-workflows: queued message ${input2.message.id} has no active position`);
|
|
77810
|
+
}
|
|
77811
|
+
return { outcome: "queued", position: result.position };
|
|
77812
|
+
});
|
|
77813
|
+
},
|
|
77814
|
+
pendingStageMessagesFor(runId, stageKey) {
|
|
77815
|
+
const run = context.findRun(runId);
|
|
77816
|
+
return pendingStageMessagesFor(run?.pendingStageMessages ?? [], runId, stageKey, run === undefined ? undefined : resolvePendingStageIdentity(run, stageKey));
|
|
77817
|
+
},
|
|
77818
|
+
async markPendingStageMessageDelivered(runId, stageKey, messageId, deliveredAt, backend) {
|
|
77819
|
+
return await serialize(runId, async () => {
|
|
77820
|
+
const run = context.findRun(runId);
|
|
77821
|
+
if (run === undefined)
|
|
77822
|
+
return false;
|
|
77823
|
+
const current = run.pendingStageMessages ?? [];
|
|
77824
|
+
const next = markPendingStageMessageDelivered(current, runId, stageKey, messageId, deliveredAt, resolvePendingStageIdentity(run, stageKey));
|
|
77825
|
+
if (next === current)
|
|
77826
|
+
return false;
|
|
77827
|
+
await persistTransition(backend, runId, next);
|
|
77828
|
+
run.pendingStageMessages = [...next];
|
|
77829
|
+
context.bumpAndNotify();
|
|
77830
|
+
return true;
|
|
77831
|
+
});
|
|
77832
|
+
},
|
|
77833
|
+
async markPendingStageMessageUndeliverable(runId, stageKey, messageId, reason, backend) {
|
|
77834
|
+
return await serialize(runId, async () => {
|
|
77835
|
+
const run = context.findRun(runId);
|
|
77836
|
+
if (run === undefined)
|
|
77837
|
+
return false;
|
|
77838
|
+
const current = run.pendingStageMessages ?? [];
|
|
77839
|
+
const next = markPendingStageMessageUndeliverable(current, runId, stageKey, messageId, reason, resolvePendingStageIdentity(run, stageKey));
|
|
77840
|
+
if (next === current)
|
|
77841
|
+
return false;
|
|
77842
|
+
await persistTransition(backend, runId, next);
|
|
77843
|
+
run.pendingStageMessages = [...next];
|
|
77844
|
+
context.bumpAndNotify();
|
|
77845
|
+
return true;
|
|
77846
|
+
});
|
|
77847
|
+
},
|
|
77848
|
+
async markPendingStageMessageUndeliverableNotified(runId, stageKey, messageId, notificationId, notifiedAt, backend) {
|
|
77849
|
+
return await serialize(runId, async () => {
|
|
77850
|
+
const run = context.findRun(runId);
|
|
77851
|
+
if (run === undefined)
|
|
77852
|
+
return false;
|
|
77853
|
+
const current = run.pendingStageMessages ?? [];
|
|
77854
|
+
const next = markPendingStageMessageUndeliverableNotified(current, runId, stageKey, messageId, notificationId, notifiedAt);
|
|
77855
|
+
if (next === current)
|
|
77856
|
+
return false;
|
|
77857
|
+
await persistTransition(backend, runId, next);
|
|
77858
|
+
run.pendingStageMessages = [...next];
|
|
77859
|
+
context.bumpAndNotify();
|
|
77860
|
+
return true;
|
|
77861
|
+
});
|
|
77862
|
+
}
|
|
77863
|
+
};
|
|
77864
|
+
}
|
|
77865
|
+
function resolvePendingStageIdentity(run, stageKey) {
|
|
77866
|
+
const exactIds = run.stages.filter((stage2) => stage2.id === stageKey);
|
|
77867
|
+
const candidates = exactIds.length > 0 ? exactIds : run.stages.filter((stage2) => stage2.name === stageKey);
|
|
77868
|
+
if (candidates.length !== 1)
|
|
77869
|
+
return;
|
|
77870
|
+
const stage = candidates[0];
|
|
77871
|
+
return {
|
|
77872
|
+
id: stage.id,
|
|
77873
|
+
...stage.replayKey !== undefined ? { replayKey: stage.replayKey } : {},
|
|
77874
|
+
aliases: stage.id === stage.name ? [stage.id] : [stage.id, stage.name]
|
|
77875
|
+
};
|
|
77876
|
+
}
|
|
77877
|
+
async function persistTransition(backend, runId, messages2) {
|
|
77878
|
+
if (!await backend.persistPendingStageMessages(runId, messages2)) {
|
|
77879
|
+
throw new Error(`atomic-workflows: durable workflow ${runId} is unavailable for pending-stage persistence`);
|
|
77880
|
+
}
|
|
77881
|
+
}
|
|
77882
|
+
|
|
77487
77883
|
// dist/builtin/workflows/src/shared/store-prompt-methods.ts
|
|
77488
77884
|
function createPromptStoreMethods(context) {
|
|
77489
77885
|
const { state } = context;
|
|
@@ -78401,6 +78797,7 @@ function createStore() {
|
|
|
78401
78797
|
const context = createStoreContext();
|
|
78402
78798
|
return {
|
|
78403
78799
|
...createRunStoreMethods(context),
|
|
78800
|
+
...createPendingStageDeliveryStoreMethods(context),
|
|
78404
78801
|
...createStageStoreMethods(context),
|
|
78405
78802
|
...createToolNodeStoreMethods(context),
|
|
78406
78803
|
...createPromptStoreMethods(context)
|
|
@@ -90556,6 +90953,26 @@ function canonicalJsonString(value) {
|
|
|
90556
90953
|
}
|
|
90557
90954
|
|
|
90558
90955
|
// dist/builtin/workflows/src/durable/backend.ts
|
|
90956
|
+
function replacePendingStageMessagesForRun(existing, logicalRunId, messages2) {
|
|
90957
|
+
if (messages2.some((entry) => entry.runId !== logicalRunId)) {
|
|
90958
|
+
throw new Error(`atomic-workflows: pending-stage persistence mixed logical run ${logicalRunId}`);
|
|
90959
|
+
}
|
|
90960
|
+
const firstOwnedIndex = existing.findIndex((entry) => entry.runId === logicalRunId);
|
|
90961
|
+
if (firstOwnedIndex < 0)
|
|
90962
|
+
return [...existing, ...messages2];
|
|
90963
|
+
const merged = [];
|
|
90964
|
+
for (let index = 0;index < existing.length; index += 1) {
|
|
90965
|
+
const entry = existing[index];
|
|
90966
|
+
if (index === firstOwnedIndex)
|
|
90967
|
+
merged.push(...messages2);
|
|
90968
|
+
if (entry.runId !== logicalRunId)
|
|
90969
|
+
merged.push(entry);
|
|
90970
|
+
}
|
|
90971
|
+
return merged;
|
|
90972
|
+
}
|
|
90973
|
+
function pendingStageMessagesForDurableRun(backend, logicalRunId, rootWorkflowId = logicalRunId) {
|
|
90974
|
+
return (backend.getWorkflow(rootWorkflowId)?.pendingStageMessages ?? []).filter((entry) => entry.runId === logicalRunId);
|
|
90975
|
+
}
|
|
90559
90976
|
function checkpointKey(c2) {
|
|
90560
90977
|
return `${c2.kind}:${c2.checkpointId}`;
|
|
90561
90978
|
}
|
|
@@ -90582,6 +90999,7 @@ class InMemoryDurableBackend {
|
|
|
90582
90999
|
...handle.workflowCwd !== undefined ? { workflowCwd: handle.workflowCwd } : existing?.handle.workflowCwd !== undefined ? { workflowCwd: existing.handle.workflowCwd } : {},
|
|
90583
91000
|
...handle.repositoryRoot !== undefined ? { repositoryRoot: handle.repositoryRoot } : existing?.handle.repositoryRoot !== undefined ? { repositoryRoot: existing.handle.repositoryRoot } : {},
|
|
90584
91001
|
...handle.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: handle.gitWorktreeRoot } : existing?.handle.gitWorktreeRoot !== undefined ? { gitWorktreeRoot: existing.handle.gitWorktreeRoot } : {},
|
|
91002
|
+
pendingStageMessages: handle.pendingStageMessages ?? existing?.handle.pendingStageMessages ?? [],
|
|
90585
91003
|
...handle.sessionFile !== undefined ? { sessionFile: handle.sessionFile } : {},
|
|
90586
91004
|
completedCheckpoints,
|
|
90587
91005
|
pendingPrompts,
|
|
@@ -90606,6 +91024,17 @@ class InMemoryDurableBackend {
|
|
|
90606
91024
|
if (handle.pendingPrompts !== undefined)
|
|
90607
91025
|
this.promptReservations.delete(handle.workflowId);
|
|
90608
91026
|
}
|
|
91027
|
+
async persistPendingStageMessages(workflowId, messages2, logicalRunId = workflowId) {
|
|
91028
|
+
const handle = this.getWorkflow(workflowId);
|
|
91029
|
+
if (handle === undefined)
|
|
91030
|
+
return false;
|
|
91031
|
+
this.registerWorkflow({
|
|
91032
|
+
...handle,
|
|
91033
|
+
pendingStageMessages: replacePendingStageMessagesForRun(handle.pendingStageMessages ?? [], logicalRunId, messages2),
|
|
91034
|
+
updatedAt: nextMetadataTimestamp(handle.updatedAt)
|
|
91035
|
+
});
|
|
91036
|
+
return true;
|
|
91037
|
+
}
|
|
90609
91038
|
recordCheckpoint(checkpoint) {
|
|
90610
91039
|
const currentCheckpoint = withCurrentStageTopology(checkpoint);
|
|
90611
91040
|
const rec = this.workflows.get(currentCheckpoint.workflowId);
|
|
@@ -90798,6 +91227,7 @@ class InMemoryDurableBackend {
|
|
|
90798
91227
|
createdAt: h.createdAt,
|
|
90799
91228
|
completedCheckpoints: h.completedCheckpoints,
|
|
90800
91229
|
pendingPrompts: h.pendingPrompts,
|
|
91230
|
+
pendingStageMessages: h.pendingStageMessages ?? [],
|
|
90801
91231
|
...h.ownerExecutorId !== undefined ? { ownerExecutorId: h.ownerExecutorId } : {},
|
|
90802
91232
|
...h.sessionFile !== undefined ? { sessionFile: h.sessionFile } : {},
|
|
90803
91233
|
...h.label !== undefined ? { label: h.label } : {},
|
|
@@ -90886,6 +91316,9 @@ function toResumableEntry(handle) {
|
|
|
90886
91316
|
updatedAt: handle.updatedAt
|
|
90887
91317
|
};
|
|
90888
91318
|
}
|
|
91319
|
+
function nextMetadataTimestamp(previous2) {
|
|
91320
|
+
return Math.max(Date.now(), previous2 + 1);
|
|
91321
|
+
}
|
|
90889
91322
|
|
|
90890
91323
|
// dist/builtin/workflows/src/durable/stage-topology-validation.ts
|
|
90891
91324
|
function immutableStageGroupError(stages) {
|
|
@@ -92076,6 +92509,7 @@ function encodeMetadata(metadata) {
|
|
|
92076
92509
|
completedCheckpoints: metadata.completedCheckpoints,
|
|
92077
92510
|
pendingPrompts: metadata.pendingPrompts,
|
|
92078
92511
|
promptReservationEpoch: metadata.promptReservationEpoch,
|
|
92512
|
+
...metadata.pendingStageMessages !== undefined ? { pendingStageMessages: serializePendingStageMessages(metadata.pendingStageMessages) } : {},
|
|
92079
92513
|
...metadata.ownerExecutorId !== undefined ? { ownerExecutorId: metadata.ownerExecutorId } : {},
|
|
92080
92514
|
...metadata.transitionClaimId !== undefined ? { transitionClaimId: metadata.transitionClaimId } : {},
|
|
92081
92515
|
...metadata.sessionFile !== undefined ? { sessionFile: metadata.sessionFile } : {},
|
|
@@ -92133,15 +92567,101 @@ function metadataTimestamp(record) {
|
|
|
92133
92567
|
function parseDurableWorkflowMetadata(value, workflowId) {
|
|
92134
92568
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
92135
92569
|
return;
|
|
92570
|
+
const serialized = value;
|
|
92571
|
+
const pendingStageMessages = parsePendingStageMessages(serialized.pendingStageMessages);
|
|
92572
|
+
if (pendingStageMessages === null)
|
|
92573
|
+
return;
|
|
92136
92574
|
const metadata = value;
|
|
92137
92575
|
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
92576
|
return;
|
|
92139
92577
|
const { origin, ...metadataWithoutOrigin } = metadata;
|
|
92140
92578
|
return {
|
|
92141
92579
|
...metadataWithoutOrigin,
|
|
92580
|
+
pendingStageMessages,
|
|
92142
92581
|
...isWorkflowActor(origin) ? { origin } : {}
|
|
92143
92582
|
};
|
|
92144
92583
|
}
|
|
92584
|
+
function serializePendingStageMessages(messages2) {
|
|
92585
|
+
return messages2.map((entry) => ({
|
|
92586
|
+
id: entry.id,
|
|
92587
|
+
runId: entry.runId,
|
|
92588
|
+
stageKey: entry.stageKey,
|
|
92589
|
+
...entry.stageId !== undefined ? { stageId: entry.stageId } : {},
|
|
92590
|
+
...entry.stageReplayKey !== undefined ? { stageReplayKey: entry.stageReplayKey } : {},
|
|
92591
|
+
...entry.senderRegistrationName !== undefined ? { senderRegistrationName: entry.senderRegistrationName } : {},
|
|
92592
|
+
...entry.senderReturnAddress !== undefined ? { senderReturnAddress: entry.senderReturnAddress } : {},
|
|
92593
|
+
from: {
|
|
92594
|
+
id: entry.from.id,
|
|
92595
|
+
...entry.from.name !== undefined ? { name: entry.from.name } : {},
|
|
92596
|
+
...entry.from.group !== undefined ? { group: entry.from.group } : {},
|
|
92597
|
+
...entry.from.cwd !== undefined ? { cwd: entry.from.cwd } : {},
|
|
92598
|
+
...entry.from.model !== undefined ? { model: entry.from.model } : {},
|
|
92599
|
+
...entry.from.pid !== undefined ? { pid: entry.from.pid } : {},
|
|
92600
|
+
...entry.from.startedAt !== undefined ? { startedAt: entry.from.startedAt } : {},
|
|
92601
|
+
...entry.from.lastActivity !== undefined ? { lastActivity: entry.from.lastActivity } : {},
|
|
92602
|
+
...entry.from.status !== undefined ? { status: entry.from.status } : {}
|
|
92603
|
+
},
|
|
92604
|
+
message: {
|
|
92605
|
+
id: entry.message.id,
|
|
92606
|
+
timestamp: entry.message.timestamp,
|
|
92607
|
+
...entry.message.replyTo !== undefined ? { replyTo: entry.message.replyTo } : {},
|
|
92608
|
+
...entry.message.expectsReply !== undefined ? { expectsReply: entry.message.expectsReply } : {},
|
|
92609
|
+
...entry.message.replyError !== undefined ? { replyError: entry.message.replyError } : {},
|
|
92610
|
+
...entry.message.source !== undefined ? { source: { ...entry.message.source } } : {},
|
|
92611
|
+
content: {
|
|
92612
|
+
text: entry.message.content.text,
|
|
92613
|
+
...entry.message.content.attachments !== undefined ? { attachments: entry.message.content.attachments.map((attachment) => ({ ...attachment })) } : {}
|
|
92614
|
+
}
|
|
92615
|
+
},
|
|
92616
|
+
queuedAt: entry.queuedAt,
|
|
92617
|
+
...entry.admissionOrder !== undefined ? { admissionOrder: entry.admissionOrder } : {},
|
|
92618
|
+
status: entry.status,
|
|
92619
|
+
...entry.deliveredAt !== undefined ? { deliveredAt: entry.deliveredAt } : {},
|
|
92620
|
+
...entry.undeliverableReason !== undefined ? { undeliverableReason: entry.undeliverableReason } : {},
|
|
92621
|
+
...entry.undeliverableNotificationId !== undefined ? { undeliverableNotificationId: entry.undeliverableNotificationId } : {},
|
|
92622
|
+
...entry.undeliverableNotifiedAt !== undefined ? { undeliverableNotifiedAt: entry.undeliverableNotifiedAt } : {}
|
|
92623
|
+
}));
|
|
92624
|
+
}
|
|
92625
|
+
function parsePendingStageMessages(value) {
|
|
92626
|
+
if (value === undefined)
|
|
92627
|
+
return [];
|
|
92628
|
+
if (!Array.isArray(value) || !value.every(isPendingStageMessage))
|
|
92629
|
+
return null;
|
|
92630
|
+
return value;
|
|
92631
|
+
}
|
|
92632
|
+
function isPendingStageMessage(value) {
|
|
92633
|
+
if (!isSerializableObject(value))
|
|
92634
|
+
return false;
|
|
92635
|
+
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);
|
|
92636
|
+
}
|
|
92637
|
+
function isPendingStageSender(value) {
|
|
92638
|
+
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");
|
|
92639
|
+
}
|
|
92640
|
+
function isPendingStageIntercomMessage(value) {
|
|
92641
|
+
if (!isSerializableObject(value) || typeof value.id !== "string" || typeof value.timestamp !== "number")
|
|
92642
|
+
return false;
|
|
92643
|
+
if (value.replyTo !== undefined && typeof value.replyTo !== "string")
|
|
92644
|
+
return false;
|
|
92645
|
+
if (value.expectsReply !== undefined && typeof value.expectsReply !== "boolean")
|
|
92646
|
+
return false;
|
|
92647
|
+
if (value.replyError !== undefined && typeof value.replyError !== "string")
|
|
92648
|
+
return false;
|
|
92649
|
+
if (!isSerializableObject(value.content) || typeof value.content.text !== "string")
|
|
92650
|
+
return false;
|
|
92651
|
+
const attachments = value.content.attachments;
|
|
92652
|
+
if (attachments !== undefined && (!Array.isArray(attachments) || !attachments.every(isPendingStageAttachment)))
|
|
92653
|
+
return false;
|
|
92654
|
+
return value.source === undefined || isPendingStageSource(value.source);
|
|
92655
|
+
}
|
|
92656
|
+
function isPendingStageAttachment(value) {
|
|
92657
|
+
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");
|
|
92658
|
+
}
|
|
92659
|
+
function isPendingStageSource(value) {
|
|
92660
|
+
return isSerializableObject(value) && typeof value.subagentRunId === "string" && (value.subagentAgent === undefined || typeof value.subagentAgent === "string") && (value.subagentIndex === undefined || typeof value.subagentIndex === "number");
|
|
92661
|
+
}
|
|
92662
|
+
function isSerializableObject(value) {
|
|
92663
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
92664
|
+
}
|
|
92145
92665
|
function isWorkflowActor(value) {
|
|
92146
92666
|
return value === "user" || value === "agent";
|
|
92147
92667
|
}
|
|
@@ -92676,6 +93196,29 @@ class DbosDurableBackend {
|
|
|
92676
93196
|
await this.writeMetadata(handle.workflowId);
|
|
92677
93197
|
});
|
|
92678
93198
|
}
|
|
93199
|
+
async persistPendingStageMessages(workflowId, messages2, logicalRunId = workflowId) {
|
|
93200
|
+
let persisted = false;
|
|
93201
|
+
await this.enqueueWrite(async () => {
|
|
93202
|
+
if (!this.isWorkflowLoadable(workflowId))
|
|
93203
|
+
return;
|
|
93204
|
+
const handle = this.mem.getWorkflow(workflowId);
|
|
93205
|
+
const value = this.mem.toMetadata(workflowId);
|
|
93206
|
+
if (handle === undefined || value === undefined)
|
|
93207
|
+
return;
|
|
93208
|
+
const updatedAt = Math.max(Date.now(), handle.updatedAt + 1);
|
|
93209
|
+
const pendingStageMessages = replacePendingStageMessagesForRun(handle.pendingStageMessages ?? [], logicalRunId, messages2);
|
|
93210
|
+
const metadata = {
|
|
93211
|
+
...this.promptReservations.metadata(workflowId, value),
|
|
93212
|
+
pendingStageMessages,
|
|
93213
|
+
ownerExecutorId: this.executorId,
|
|
93214
|
+
updatedAt
|
|
93215
|
+
};
|
|
93216
|
+
await this.sdk.recordStepOutput(workflowId, metadataStepName(updatedAt), encodeMetadata(metadata));
|
|
93217
|
+
this.mem.registerWorkflow({ ...handle, pendingStageMessages, updatedAt });
|
|
93218
|
+
persisted = true;
|
|
93219
|
+
});
|
|
93220
|
+
return persisted;
|
|
93221
|
+
}
|
|
92679
93222
|
recordCheckpoint(checkpoint) {
|
|
92680
93223
|
if (!this.isWorkflowLoadable(checkpoint.workflowId))
|
|
92681
93224
|
return;
|
|
@@ -95378,6 +95921,10 @@ function withMidSessionResumePrompt(stage, enabled) {
|
|
|
95378
95921
|
});
|
|
95379
95922
|
return stage;
|
|
95380
95923
|
}
|
|
95924
|
+
function pendingStageIdForReplay(backend, workflowId, replayKey, stageName) {
|
|
95925
|
+
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));
|
|
95926
|
+
return candidates.size === 1 ? candidates.values().next().value : undefined;
|
|
95927
|
+
}
|
|
95381
95928
|
function createDurableStagePrimitive(input2) {
|
|
95382
95929
|
return (name, options) => {
|
|
95383
95930
|
const replayKey = input2.nextReplayKey(name);
|
|
@@ -95389,13 +95936,12 @@ function createDurableStagePrimitive(input2) {
|
|
|
95389
95936
|
const session = input2.backend.getStageSession(input2.workflowId, replayKey);
|
|
95390
95937
|
const isMidSessionResume = session?.sessionFile !== undefined;
|
|
95391
95938
|
const topology = activeStageTopology(input2.backend, input2.workflowId, replayKey);
|
|
95939
|
+
const durableStageId = topology?.stageId ?? pendingStageIdForReplay(input2.backend, input2.workflowId, replayKey, name);
|
|
95392
95940
|
const liveOptions = {
|
|
95393
95941
|
...options ?? {},
|
|
95394
95942
|
durableReplayKey: replayKey,
|
|
95395
|
-
...
|
|
95396
|
-
|
|
95397
|
-
durableParentIds: [...topology.parentIds]
|
|
95398
|
-
} : {},
|
|
95943
|
+
...durableStageId !== undefined ? { durableStageId } : {},
|
|
95944
|
+
...topology !== undefined ? { durableParentIds: [...topology.parentIds] } : {},
|
|
95399
95945
|
...isMidSessionResume ? {
|
|
95400
95946
|
resumeFromSessionFile: session.sessionFile,
|
|
95401
95947
|
durableAccumulatedDurationMs: session.durationMs ?? 0
|
|
@@ -96093,6 +96639,7 @@ function appendStageStart(api, payload) {
|
|
|
96093
96639
|
name: payload.name,
|
|
96094
96640
|
parentIds: [...payload.parentIds],
|
|
96095
96641
|
...payload.model !== undefined ? { model: payload.model } : {},
|
|
96642
|
+
...payload.pendingStageDeliveryAvailable !== undefined ? { pendingStageDeliveryAvailable: payload.pendingStageDeliveryAvailable } : {},
|
|
96096
96643
|
...payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {},
|
|
96097
96644
|
...payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {},
|
|
96098
96645
|
...payload.replayed !== undefined ? { replayed: payload.replayed } : {},
|
|
@@ -96636,6 +97183,7 @@ function installCompactionHook(api, store2) {
|
|
|
96636
97183
|
stageId: stage.id,
|
|
96637
97184
|
name: stage.name,
|
|
96638
97185
|
parentIds: [...stage.parentIds],
|
|
97186
|
+
pendingStageDeliveryAvailable: stage.pendingStageDeliveryAvailable,
|
|
96639
97187
|
ts: stage.startedAt ?? now
|
|
96640
97188
|
});
|
|
96641
97189
|
}
|
|
@@ -97212,7 +97760,7 @@ function formatWorkflowLifecycleNoticeText(details) {
|
|
|
97212
97760
|
return `? Workflow "${workflowName}" needs input (run ${details.runId}).${prompt2} Respond: /workflow connect ${details.runId} to answer this run-level prompt.`;
|
|
97213
97761
|
}
|
|
97214
97762
|
const stage = details.stageName ?? details.stageId ?? "unknown";
|
|
97215
|
-
const responseHint = details.stageId && details.promptId ? `/workflow connect ${details.runId} or workflow({ action: "
|
|
97763
|
+
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
97764
|
return `? Workflow "${workflowName}" needs input (run ${details.runId}, stage ${stage}).${prompt2} Respond: ${responseHint}.`;
|
|
97217
97765
|
}
|
|
97218
97766
|
function makeTerminalNotice(run, kind) {
|
|
@@ -98512,6 +99060,12 @@ function workflow(spec) {
|
|
|
98512
99060
|
return Object.freeze(branded);
|
|
98513
99061
|
}
|
|
98514
99062
|
|
|
99063
|
+
// dist/builtin/workflows/builtin/steering-context.ts
|
|
99064
|
+
var exports_steering_context = {};
|
|
99065
|
+
__export(exports_steering_context, {
|
|
99066
|
+
withSteeringPropagationContext: () => withSteeringPropagationContext
|
|
99067
|
+
});
|
|
99068
|
+
|
|
98515
99069
|
// dist/builtin/workflows/src/authoring/keep-context.ts
|
|
98516
99070
|
var KEEP_CONTEXT_OPEN_TAG = "<keepContext>";
|
|
98517
99071
|
var KEEP_CONTEXT_CLOSE_TAG = "</keepContext>";
|
|
@@ -98525,6 +99079,12 @@ ${KEEP_CONTEXT_CLOSE_TAG}`;
|
|
|
98525
99079
|
}
|
|
98526
99080
|
|
|
98527
99081
|
// dist/builtin/workflows/builtin/shared-prompts.ts
|
|
99082
|
+
var PENDING_STAGE_DELIVERY_GUIDANCE_LINES = [
|
|
99083
|
+
"Send material updates through Intercom to every affected workflow stage, including stages that have not started.",
|
|
99084
|
+
"Atomic queues messages for known pending stages addressed as `<runId>:<stageKey>` and delivers them when their sessions initialize."
|
|
99085
|
+
];
|
|
99086
|
+
var PENDING_STAGE_DELIVERY_GUIDANCE = PENDING_STAGE_DELIVERY_GUIDANCE_LINES.join(`
|
|
99087
|
+
`);
|
|
98528
99088
|
var STEERING_PROPAGATION_CONTRACT = [
|
|
98529
99089
|
"Steering propagation contract:",
|
|
98530
99090
|
"- 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 +99092,7 @@ var STEERING_PROPAGATION_CONTRACT = [
|
|
|
98532
99092
|
"- Keep user-authored amendments visibly separate from your own observations, so later stages can tell a required clause from an agent proposal.",
|
|
98533
99093
|
"- 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
99094
|
"- 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.",
|
|
99095
|
+
...PENDING_STAGE_DELIVERY_GUIDANCE_LINES.map((line) => `- ${line}`),
|
|
98535
99096
|
"- 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
99097
|
].join(`
|
|
98537
99098
|
`);
|
|
@@ -98572,6 +99133,19 @@ var E2E_VERIFICATION_GUIDANCE = [
|
|
|
98572
99133
|
"If E2E remains impractical, record the commands attempted, observed failure output, smallest missing prerequisite, and narrower validation run; an unattempted assumption is never valid grounds to skip."
|
|
98573
99134
|
].join(`
|
|
98574
99135
|
`);
|
|
99136
|
+
var CODE_QUALITY_VERIFICATION_GUIDANCE = [
|
|
99137
|
+
'For code-quality verification — linting, auto-formatting, complexity and duplication metrics, and code smells — use the qlty skill or delegate with `skill: "qlty"`; it drives one CLI across the repository\'s languages instead of ad-hoc per-tool linter invocations.',
|
|
99138
|
+
"Weight this higher when the objective asks for verifiers or high code quality: enable the qlty plugins that fit this codebase, then run the check/format/metrics/smells loop and act on what it reports.",
|
|
99139
|
+
"Repository-defined checks in AGENTS.md/CLAUDE.md, package scripts, and CI stay authoritative; qlty supplements them rather than replacing them, and its findings count as evidence only with the command and observed output recorded."
|
|
99140
|
+
].join(`
|
|
99141
|
+
`);
|
|
99142
|
+
var REPO_INTENT_MINING_GUIDANCE = [
|
|
99143
|
+
"Infer maintainer and requesting-user intent from repository behavior, not only written docs: mine git history (`git log`, `git log --show-signature`), merged PRs, issues and their comments, review comments, commit subjects and trailers, and CI/branch-protection config for unwritten conventions.",
|
|
99144
|
+
"Read for commit-signing habits, commit-message style and issue linking, changelog discipline, PR size and stacking norms, review etiquette, formatting and lint norms, and branch naming. Prefer the dominant, recent, intentional pattern over accidental drift; when signals conflict, the requesting user's own commits, PRs, and comments weigh highest — different users of one repository keep different preferences.",
|
|
99145
|
+
"Match inferred conventions in delivered work (for example, sign commits when the surrounding history is signed rather than skipping signing because no doc required it); in review, report deviations as convention findings backed by the mined evidence.",
|
|
99146
|
+
"Behavioral evidence fills gaps where the contract is silent; it never overrides the literal objective, acceptance criteria, or explicit AGENTS.md/CLAUDE.md guidance, and it does not license new contract requirements."
|
|
99147
|
+
].join(`
|
|
99148
|
+
`);
|
|
98575
99149
|
function renderE2eQaVideoReviewGuidance(knownVideoPath) {
|
|
98576
99150
|
const target = knownVideoPath === undefined || knownVideoPath.length === 0 ? "Look for QA E2E video references in the goal ledger, implementation receipt, implementation notes, orchestrator report, or other review context artifacts." : `Known QA E2E video path for this run: ${knownVideoPath}`;
|
|
98577
99151
|
return [
|
|
@@ -101269,6 +101843,8 @@ function renderGoalContinuationPrompt(ledger, ledgerPath, blockerThreshold, late
|
|
|
101269
101843
|
["worktree_discipline", WORKTREE_DISCIPLINE_CONTRACT],
|
|
101270
101844
|
["pr_handoff_policy", INTERMEDIATE_PR_HANDOFF_GUARDRAIL],
|
|
101271
101845
|
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
101846
|
+
["code_quality_verification", CODE_QUALITY_VERIFICATION_GUIDANCE],
|
|
101847
|
+
["repository_intent", REPO_INTENT_MINING_GUIDANCE],
|
|
101272
101848
|
["goal_guidelines", GOAL_CONTINUATION_REFERENCE],
|
|
101273
101849
|
["objective", ["Continue working toward the active goal using the ledger as authoritative state for status, receipts, reviews, blockers, reducer decisions, and lifecycle events.", `The same blocker must repeat for at least ${blockerThreshold} controller observations before blocked status is available.`, "Reviewer quorum plus the reducer decides completion from reviewers' authoritative stop_review_loop signals."].join(`
|
|
101274
101850
|
`)]
|
|
@@ -101294,6 +101870,8 @@ function renderReviewerPrompt(args) {
|
|
|
101294
101870
|
["pr_handoff_policy", INTERMEDIATE_PR_HANDOFF_GUARDRAIL],
|
|
101295
101871
|
["auditability", RECEIPT_EXPECTATIONS],
|
|
101296
101872
|
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
101873
|
+
["code_quality_verification", CODE_QUALITY_VERIFICATION_GUIDANCE],
|
|
101874
|
+
["repository_intent", REPO_INTENT_MINING_GUIDANCE],
|
|
101297
101875
|
["final_action_policy", args.createPr ? "PR/MR/review creation is an authorized post-approval final action. If implementation and validation are proven and only that action remains, set goal_oracle_satisfied=true and stop_review_loop=true with no blocking findings, and record it as the remaining final action." : "PR/MR/review creation is not enabled; do not require or attempt it during review."],
|
|
101298
101876
|
["project_guidance", [
|
|
101299
101877
|
"Apply AGENTS.md/CLAUDE.md and nearby code, test, script, config, generated-artifact, and CI conventions; specific project guidance overrides general guidance.",
|
|
@@ -103490,6 +104068,8 @@ function renderRalphReviewerPrompt(args) {
|
|
|
103490
104068
|
["reviewer_coordination", REVIEWER_INTERCOM_COORDINATION_PROTOCOL],
|
|
103491
104069
|
["regression_evidence", REGRESSION_EVIDENCE_CONTRACT],
|
|
103492
104070
|
["e2e_verification", E2E_VERIFICATION_GUIDANCE],
|
|
104071
|
+
["code_quality_verification", CODE_QUALITY_VERIFICATION_GUIDANCE],
|
|
104072
|
+
["repository_intent", REPO_INTENT_MINING_GUIDANCE],
|
|
103493
104073
|
["qa_e2e_video_review", renderE2eQaVideoReviewGuidance(args.qaVideoPath)],
|
|
103494
104074
|
["evidence_closure", EVIDENCE_CLOSURE_POLICY],
|
|
103495
104075
|
[
|
|
@@ -103884,6 +104464,8 @@ Read it before implementation or delegation because it is the primary current im
|
|
|
103884
104464
|
["project_setup", WORKER_PREFLIGHT_CONTRACT],
|
|
103885
104465
|
["worktree_discipline", WORKTREE_DISCIPLINE_CONTRACT],
|
|
103886
104466
|
["qa_e2e_video", renderQaE2eVideoGuidance(qaVideoPath)],
|
|
104467
|
+
["code_quality_verification", CODE_QUALITY_VERIFICATION_GUIDANCE],
|
|
104468
|
+
["repository_intent", REPO_INTENT_MINING_GUIDANCE],
|
|
103887
104469
|
[
|
|
103888
104470
|
"delegation",
|
|
103889
104471
|
[
|
|
@@ -106172,6 +106754,9 @@ class ScopedDurableBackend {
|
|
|
106172
106754
|
this.persistent = inner.persistent;
|
|
106173
106755
|
}
|
|
106174
106756
|
registerWorkflow(_handle) {}
|
|
106757
|
+
persistPendingStageMessages(workflowId, messages2, logicalRunId = workflowId) {
|
|
106758
|
+
return this.inner.persistPendingStageMessages(this.scope.rootWorkflowId, messages2, logicalRunId);
|
|
106759
|
+
}
|
|
106175
106760
|
recordCheckpoint(checkpoint) {
|
|
106176
106761
|
this.inner.recordCheckpoint(this.remap(checkpoint));
|
|
106177
106762
|
}
|
|
@@ -109509,6 +110094,7 @@ import { randomUUID as randomUUID16 } from "node:crypto";
|
|
|
109509
110094
|
|
|
109510
110095
|
// dist/builtin/workflows/src/shared/intercom-group.ts
|
|
109511
110096
|
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
110097
|
+
var DEFAULT_INTERCOM_GROUP = "default";
|
|
109512
110098
|
function workflowInvocationIntercomGroup(rootRunId) {
|
|
109513
110099
|
return `workflow:${rootRunId}`;
|
|
109514
110100
|
}
|
|
@@ -109518,6 +110104,12 @@ function normalizeAutoGroupSentinel(group) {
|
|
|
109518
110104
|
const sentinel = group.trim().toLowerCase();
|
|
109519
110105
|
return sentinel === "true" || sentinel === "auto" ? true : group;
|
|
109520
110106
|
}
|
|
110107
|
+
function normalizeGroup(value) {
|
|
110108
|
+
if (typeof value !== "string")
|
|
110109
|
+
return DEFAULT_INTERCOM_GROUP;
|
|
110110
|
+
const trimmed = value.trim();
|
|
110111
|
+
return trimmed.length > 0 ? trimmed : DEFAULT_INTERCOM_GROUP;
|
|
110112
|
+
}
|
|
109521
110113
|
function resolveStageGroup(stageOptions, workflowGroup) {
|
|
109522
110114
|
if (!stageOptions)
|
|
109523
110115
|
return workflowGroup;
|
|
@@ -109542,6 +110134,11 @@ function stageHasIntercomAccess(stageOptions) {
|
|
|
109542
110134
|
return false;
|
|
109543
110135
|
return true;
|
|
109544
110136
|
}
|
|
110137
|
+
function stageCanUseWorkflowPendingStageRoute(stageOptions, workflowGroup) {
|
|
110138
|
+
if (!stageHasIntercomAccess(stageOptions) || stageOptions?.group === true)
|
|
110139
|
+
return false;
|
|
110140
|
+
return normalizeGroup(resolveStageGroup(stageOptions, workflowGroup)) === normalizeGroup(workflowGroup);
|
|
110141
|
+
}
|
|
109545
110142
|
|
|
109546
110143
|
// dist/builtin/workflows/src/shared/budget-meter.ts
|
|
109547
110144
|
var usageFields = ["input", "output", "cacheRead", "cacheWrite", "cost"];
|
|
@@ -109796,9 +110393,9 @@ function createRunBudgetController(input2) {
|
|
|
109796
110393
|
function createParallelPrimitive(input2) {
|
|
109797
110394
|
return async (steps, options = {}) => {
|
|
109798
110395
|
input2.runtime.exit.throwIfWorkflowExitSelected();
|
|
109799
|
-
const
|
|
109800
|
-
const normalizedOptions =
|
|
109801
|
-
const normalizedSteps = steps.map(
|
|
110396
|
+
const normalizeGroup2 = (value) => value.group === undefined ? value : { ...value, group: normalizeAutoGroupSentinel(value.group) };
|
|
110397
|
+
const normalizedOptions = normalizeGroup2(options);
|
|
110398
|
+
const normalizedSteps = steps.map(normalizeGroup2);
|
|
109802
110399
|
const needsAutoGroup = normalizedOptions.group === true || normalizedSteps.some((step) => step.group === true);
|
|
109803
110400
|
const autoGroup = needsAutoGroup ? randomUUID16() : undefined;
|
|
109804
110401
|
const resolveAutoGroup = (value) => value.group === true && autoGroup ? { ...value, group: autoGroup } : value;
|
|
@@ -111769,7 +112366,7 @@ function createAdmittedToolExecutionTracker(options = {}) {
|
|
|
111769
112366
|
const inFlight = new Set;
|
|
111770
112367
|
const admissions = [];
|
|
111771
112368
|
const failures = [];
|
|
111772
|
-
let
|
|
112369
|
+
let nextAdmissionOrder2 = 0;
|
|
111773
112370
|
let state = "OPEN";
|
|
111774
112371
|
let closing;
|
|
111775
112372
|
const abandonment = Promise.withResolvers();
|
|
@@ -111820,7 +112417,7 @@ function createAdmittedToolExecutionTracker(options = {}) {
|
|
|
111820
112417
|
return { accepted: false, error, bindNode() {}, noteCancelled() {} };
|
|
111821
112418
|
}
|
|
111822
112419
|
const admission = {
|
|
111823
|
-
admissionOrder: ++
|
|
112420
|
+
admissionOrder: ++nextAdmissionOrder2,
|
|
111824
112421
|
nodeId: undefined,
|
|
111825
112422
|
failure: undefined,
|
|
111826
112423
|
cancelled: false,
|
|
@@ -113122,6 +113719,150 @@ function createReplayStageContext(input2) {
|
|
|
113122
113719
|
};
|
|
113123
113720
|
}
|
|
113124
113721
|
|
|
113722
|
+
// dist/builtin/workflows/src/durable/run-owner-backend.ts
|
|
113723
|
+
function durableRootRunIdForRun(runs, runId) {
|
|
113724
|
+
return reciprocalWorkflowRootRunId(new Map(runs.map((run2) => [run2.id, run2])), runId);
|
|
113725
|
+
}
|
|
113726
|
+
function durableBackendForRun(backend, runs, runId) {
|
|
113727
|
+
const rootRunId = durableRootRunIdForRun(runs, runId);
|
|
113728
|
+
if (rootRunId === undefined)
|
|
113729
|
+
return;
|
|
113730
|
+
const runById = new Map(runs.map((run2) => [run2.id, run2]));
|
|
113731
|
+
if (rootRunId === runId)
|
|
113732
|
+
return backend;
|
|
113733
|
+
const scopes = [];
|
|
113734
|
+
let current = runById.get(runId);
|
|
113735
|
+
while (current !== undefined && current.id !== rootRunId) {
|
|
113736
|
+
const parent = current.parentRunId === undefined ? undefined : runById.get(current.parentRunId);
|
|
113737
|
+
const boundary = parent?.stages.find((stage) => stage.id === current?.parentStageId);
|
|
113738
|
+
if (parent === undefined || boundary?.replayKey === undefined)
|
|
113739
|
+
return;
|
|
113740
|
+
scopes.push(boundary.replayKey);
|
|
113741
|
+
current = parent;
|
|
113742
|
+
}
|
|
113743
|
+
if (current?.id !== rootRunId)
|
|
113744
|
+
return;
|
|
113745
|
+
let view = backend;
|
|
113746
|
+
for (const scopePrefix of scopes.reverse()) {
|
|
113747
|
+
view = new ScopedDurableBackend(view, { rootWorkflowId: rootRunId, scopePrefix });
|
|
113748
|
+
}
|
|
113749
|
+
return view;
|
|
113750
|
+
}
|
|
113751
|
+
|
|
113752
|
+
// dist/builtin/workflows/src/shared/pending-stage-route-capability.ts
|
|
113753
|
+
import { randomUUID as randomUUID17 } from "node:crypto";
|
|
113754
|
+
var routeCapabilities = new WeakMap;
|
|
113755
|
+
function workflowPendingStageRouteCapability(store2, runId) {
|
|
113756
|
+
let capabilities = routeCapabilities.get(store2);
|
|
113757
|
+
if (capabilities === undefined) {
|
|
113758
|
+
capabilities = new Map;
|
|
113759
|
+
routeCapabilities.set(store2, capabilities);
|
|
113760
|
+
}
|
|
113761
|
+
let capability = capabilities.get(runId);
|
|
113762
|
+
if (capability === undefined) {
|
|
113763
|
+
capability = randomUUID17();
|
|
113764
|
+
capabilities.set(runId, capability);
|
|
113765
|
+
}
|
|
113766
|
+
return capability;
|
|
113767
|
+
}
|
|
113768
|
+
|
|
113769
|
+
// dist/builtin/workflows/src/runs/foreground/pending-stage-delivery.ts
|
|
113770
|
+
var pendingDeliveryClaims = new WeakMap;
|
|
113771
|
+
function createWorkflowPendingStageDelivery(activeStore, runId, stageId, stageName3) {
|
|
113772
|
+
let resolveReady;
|
|
113773
|
+
let rejectReady;
|
|
113774
|
+
let readyPromise;
|
|
113775
|
+
let drainError;
|
|
113776
|
+
let drainPromise;
|
|
113777
|
+
const pendingReady = () => {
|
|
113778
|
+
if (readyPromise === undefined) {
|
|
113779
|
+
readyPromise = new Promise((resolve35, reject) => {
|
|
113780
|
+
resolveReady = resolve35;
|
|
113781
|
+
rejectReady = reject;
|
|
113782
|
+
});
|
|
113783
|
+
}
|
|
113784
|
+
return readyPromise;
|
|
113785
|
+
};
|
|
113786
|
+
return {
|
|
113787
|
+
routeCapability: workflowPendingStageRouteCapability(activeStore, runId),
|
|
113788
|
+
deliverPending(deliver) {
|
|
113789
|
+
if (drainPromise === undefined) {
|
|
113790
|
+
drainError = undefined;
|
|
113791
|
+
const attempt = deliverPendingStageMessages(activeStore, runId, stageId, stageName3, deliver);
|
|
113792
|
+
const drain2 = attempt.then(() => resolveReady?.(), (error) => {
|
|
113793
|
+
drainError = error;
|
|
113794
|
+
rejectReady?.(error);
|
|
113795
|
+
readyPromise = undefined;
|
|
113796
|
+
resolveReady = undefined;
|
|
113797
|
+
rejectReady = undefined;
|
|
113798
|
+
if (drainPromise === drain2)
|
|
113799
|
+
drainPromise = undefined;
|
|
113800
|
+
throw error;
|
|
113801
|
+
});
|
|
113802
|
+
drainPromise = drain2;
|
|
113803
|
+
}
|
|
113804
|
+
return drainPromise;
|
|
113805
|
+
},
|
|
113806
|
+
ready() {
|
|
113807
|
+
if (activeStore.pendingStageMessagesFor(runId, stageId).length === 0 && (stageId === stageName3 || activeStore.pendingStageMessagesFor(runId, stageName3).length === 0)) {
|
|
113808
|
+
return;
|
|
113809
|
+
}
|
|
113810
|
+
return drainError === undefined ? pendingReady() : Promise.reject(drainError);
|
|
113811
|
+
}
|
|
113812
|
+
};
|
|
113813
|
+
}
|
|
113814
|
+
async function deliverPendingStageMessages(activeStore, runId, stageId, stageName3, deliver) {
|
|
113815
|
+
const candidateIds = new Set([
|
|
113816
|
+
...activeStore.pendingStageMessagesFor(runId, stageId),
|
|
113817
|
+
...activeStore.pendingStageMessagesFor(runId, stageName3)
|
|
113818
|
+
].map((entry) => entry.id));
|
|
113819
|
+
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);
|
|
113820
|
+
const rootBackend = getDurableBackend();
|
|
113821
|
+
const backend = durableBackendForRun(rootBackend, activeStore.runs(), runId);
|
|
113822
|
+
if (backend === undefined) {
|
|
113823
|
+
throw new Error(`atomic-workflows: workflow run ${runId} has no durable owner for pending-stage delivery`);
|
|
113824
|
+
}
|
|
113825
|
+
for (const entry of entries) {
|
|
113826
|
+
const releaseClaim = claimPendingDelivery(activeStore, runId, entry.stageKey, entry.id);
|
|
113827
|
+
if (releaseClaim === undefined)
|
|
113828
|
+
continue;
|
|
113829
|
+
try {
|
|
113830
|
+
await deliver(toPendingStageSender(entry), entry.message);
|
|
113831
|
+
if (!await activeStore.markPendingStageMessageDelivered(runId, entry.stageKey, entry.id, new Date().toISOString(), backend)) {
|
|
113832
|
+
throw new Error(`atomic-workflows: pending-stage message ${entry.id} changed during delivery`);
|
|
113833
|
+
}
|
|
113834
|
+
} finally {
|
|
113835
|
+
releaseClaim();
|
|
113836
|
+
}
|
|
113837
|
+
}
|
|
113838
|
+
}
|
|
113839
|
+
function claimPendingDelivery(store2, runId, stageKey, messageId) {
|
|
113840
|
+
let claims = pendingDeliveryClaims.get(store2);
|
|
113841
|
+
if (claims === undefined) {
|
|
113842
|
+
claims = new Set;
|
|
113843
|
+
pendingDeliveryClaims.set(store2, claims);
|
|
113844
|
+
}
|
|
113845
|
+
const key2 = JSON.stringify([runId, stageKey, messageId]);
|
|
113846
|
+
if (claims.has(key2))
|
|
113847
|
+
return;
|
|
113848
|
+
claims.add(key2);
|
|
113849
|
+
return () => {
|
|
113850
|
+
claims?.delete(key2);
|
|
113851
|
+
if (claims?.size === 0)
|
|
113852
|
+
pendingDeliveryClaims.delete(store2);
|
|
113853
|
+
};
|
|
113854
|
+
}
|
|
113855
|
+
function toPendingStageSender(entry) {
|
|
113856
|
+
return {
|
|
113857
|
+
...entry.from,
|
|
113858
|
+
cwd: entry.from.cwd ?? "",
|
|
113859
|
+
model: entry.from.model ?? "unknown",
|
|
113860
|
+
pid: entry.from.pid ?? 0,
|
|
113861
|
+
startedAt: entry.from.startedAt ?? entry.message.timestamp,
|
|
113862
|
+
lastActivity: entry.from.lastActivity ?? entry.message.timestamp
|
|
113863
|
+
};
|
|
113864
|
+
}
|
|
113865
|
+
|
|
113125
113866
|
// dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts
|
|
113126
113867
|
init_src();
|
|
113127
113868
|
|
|
@@ -113513,7 +114254,7 @@ function workflowSessionOptions(meta2) {
|
|
|
113513
114254
|
workflow: { runId: meta2.runId, stageId: meta2.stageId, stageName: meta2.stageName }
|
|
113514
114255
|
};
|
|
113515
114256
|
}
|
|
113516
|
-
function workflowOrchestrationContext(meta2, stageOptions) {
|
|
114257
|
+
function workflowOrchestrationContext(meta2, stageOptions, pendingStageDelivery) {
|
|
113517
114258
|
const base = {
|
|
113518
114259
|
kind: "workflow-stage",
|
|
113519
114260
|
workflowRunId: meta2.runId,
|
|
@@ -113522,11 +114263,12 @@ function workflowOrchestrationContext(meta2, stageOptions) {
|
|
|
113522
114263
|
constraints: { disableWorkflowTool: true }
|
|
113523
114264
|
};
|
|
113524
114265
|
const intercomGroup = stageHasIntercomAccess(stageOptions) ? resolveStageGroup(stageOptions, meta2.workflowIntercomGroup) : undefined;
|
|
113525
|
-
|
|
114266
|
+
const context = intercomGroup ? { ...base, intercomGroup } : base;
|
|
114267
|
+
return pendingStageDelivery === undefined ? context : { ...context, pendingStageDelivery };
|
|
113526
114268
|
}
|
|
113527
|
-
function stripWorkflowOnlyOptions(options, defaultSessionDir, meta2) {
|
|
114269
|
+
function stripWorkflowOnlyOptions(options, defaultSessionDir, meta2, pendingStageDelivery) {
|
|
113528
114270
|
const classification = workflowSessionOptions(meta2);
|
|
113529
|
-
const orchestrationContext = workflowOrchestrationContext(meta2, options);
|
|
114271
|
+
const orchestrationContext = workflowOrchestrationContext(meta2, options, pendingStageDelivery);
|
|
113530
114272
|
if (!options) {
|
|
113531
114273
|
return defaultSessionDir === undefined ? { orchestrationContext } : {
|
|
113532
114274
|
orchestrationContext,
|
|
@@ -114892,7 +115634,7 @@ class StageSessionController {
|
|
|
114892
115634
|
});
|
|
114893
115635
|
let created;
|
|
114894
115636
|
try {
|
|
114895
|
-
created = this.opts.adapters.agentSession ? await this.opts.adapters.agentSession.create(stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta), {
|
|
115637
|
+
created = this.opts.adapters.agentSession ? await this.opts.adapters.agentSession.create(stripWorkflowOnlyOptions(stageOptions, this.opts.defaultSessionDir, this.meta, this.opts.pendingStageDelivery), {
|
|
114896
115638
|
...this.meta,
|
|
114897
115639
|
stageOptions,
|
|
114898
115640
|
...this.sharedOrchestrationContext !== undefined ? { orchestrationContext: this.sharedOrchestrationContext } : {}
|
|
@@ -114909,10 +115651,12 @@ class StageSessionController {
|
|
|
114909
115651
|
throw this.staleCreationReason(startGeneration);
|
|
114910
115652
|
}
|
|
114911
115653
|
const session = attachCreatedStageSession(created, this.disposed, this.opts.stageName, (result) => this.attachSession(result));
|
|
114912
|
-
|
|
114913
|
-
|
|
115654
|
+
const attachedSession = session instanceof Promise ? await session : session;
|
|
115655
|
+
const pendingStageDeliveryReady = this.sharedOrchestrationContext?.pendingStageDelivery?.ready();
|
|
115656
|
+
if (pendingStageDeliveryReady !== undefined)
|
|
115657
|
+
await pendingStageDeliveryReady;
|
|
114914
115658
|
await this.opts.onSessionReady?.();
|
|
114915
|
-
return
|
|
115659
|
+
return attachedSession;
|
|
114916
115660
|
}
|
|
114917
115661
|
attachSession(created) {
|
|
114918
115662
|
const result = normalizeSessionCreateResult(created);
|
|
@@ -115664,6 +116408,12 @@ function createWorkflowStageFactory(input2) {
|
|
|
115664
116408
|
const replaySource = replayDecision.kind === "replay" ? replayDecision.source : undefined;
|
|
115665
116409
|
const executeReplaySource = replayDecision.kind === "execute" ? replayDecision.source : undefined;
|
|
115666
116410
|
const shouldReplay = replaySource !== undefined;
|
|
116411
|
+
const stageOptionsForContext = executeReplaySource?.sessionFile === undefined ? options : {
|
|
116412
|
+
...options ?? {},
|
|
116413
|
+
context: options?.context ?? "fork",
|
|
116414
|
+
forkFromSessionFile: options?.forkFromSessionFile ?? executeReplaySource.sessionFile
|
|
116415
|
+
};
|
|
116416
|
+
const pendingStageDeliveryAvailable = stageCanUseWorkflowPendingStageRoute(stageOptionsForContext, input2.workflowIntercomGroup);
|
|
115667
116417
|
const stageSnapshot = {
|
|
115668
116418
|
id: stageId,
|
|
115669
116419
|
name,
|
|
@@ -115671,6 +116421,7 @@ function createWorkflowStageFactory(input2) {
|
|
|
115671
116421
|
status: shouldReplay ? "completed" : "pending",
|
|
115672
116422
|
parentIds: Object.freeze(parentIds),
|
|
115673
116423
|
toolEvents: [],
|
|
116424
|
+
pendingStageDeliveryAvailable,
|
|
115674
116425
|
...shouldReplay ? {
|
|
115675
116426
|
startedAt: Date.now(),
|
|
115676
116427
|
endedAt: Date.now(),
|
|
@@ -115699,11 +116450,6 @@ function createWorkflowStageFactory(input2) {
|
|
|
115699
116450
|
throwIfWorkflowExitSelected: input2.exit.throwIfWorkflowExitSelected
|
|
115700
116451
|
});
|
|
115701
116452
|
}
|
|
115702
|
-
const stageOptionsForContext = executeReplaySource?.sessionFile === undefined ? options : {
|
|
115703
|
-
...options ?? {},
|
|
115704
|
-
context: options?.context ?? "fork",
|
|
115705
|
-
forkFromSessionFile: options?.forkFromSessionFile ?? executeReplaySource.sessionFile
|
|
115706
|
-
};
|
|
115707
116453
|
const applyModelFallbackMeta = (meta2) => {
|
|
115708
116454
|
if (meta2.model !== undefined)
|
|
115709
116455
|
stageSnapshot.model = meta2.model;
|
|
@@ -115741,6 +116487,9 @@ function createWorkflowStageFactory(input2) {
|
|
|
115741
116487
|
workflowIntercomGroup: input2.workflowIntercomGroup,
|
|
115742
116488
|
signal: input2.signal,
|
|
115743
116489
|
stageOptions: stageOptionsForContext,
|
|
116490
|
+
...pendingStageDeliveryAvailable ? {
|
|
116491
|
+
pendingStageDelivery: createWorkflowPendingStageDelivery(input2.activeStore, input2.runId, stageId, name)
|
|
116492
|
+
} : {},
|
|
115744
116493
|
models: input2.opts.models,
|
|
115745
116494
|
executionMode: input2.opts.executionMode,
|
|
115746
116495
|
defaultSessionDir: input2.opts.defaultSessionDir,
|
|
@@ -115866,6 +116615,7 @@ function createWorkflowStageFactory(input2) {
|
|
|
115866
116615
|
name,
|
|
115867
116616
|
parentIds: stageSnapshot.parentIds,
|
|
115868
116617
|
...stageReplayFields(stageSnapshot),
|
|
116618
|
+
pendingStageDeliveryAvailable,
|
|
115869
116619
|
ts: stageSnapshot.startedAt ?? Date.now()
|
|
115870
116620
|
});
|
|
115871
116621
|
};
|
|
@@ -116228,6 +116978,9 @@ async function run(def, inputs, opts = {}) {
|
|
|
116228
116978
|
status: "running",
|
|
116229
116979
|
stages: [],
|
|
116230
116980
|
toolNodes: [],
|
|
116981
|
+
pendingStageMessages: [
|
|
116982
|
+
...pendingStageMessagesForDurableRun(rootBackend, runId, opts.parentRun?.rootRunId ?? runId)
|
|
116983
|
+
],
|
|
116231
116984
|
startedAt: Date.now(),
|
|
116232
116985
|
...opts.parentRun !== undefined ? {
|
|
116233
116986
|
parentRunId: opts.parentRun.runId,
|
|
@@ -116801,8 +117554,8 @@ var runWorkflow = () => {
|
|
|
116801
117554
|
};
|
|
116802
117555
|
|
|
116803
117556
|
// dist/builtin/workflows/src/extension/workflow-module-loader.ts
|
|
116804
|
-
var WORKFLOWS_MODULE_SPECIFIER = "@bastani/workflows";
|
|
116805
|
-
var
|
|
117557
|
+
var WORKFLOWS_MODULE_SPECIFIER = "@bastani/atomic/workflows";
|
|
117558
|
+
var LEGACY_WORKFLOWS_MODULE_SPECIFIER = "@bastani/workflows";
|
|
116806
117559
|
var TYPEBOX_MODULE_SPECIFIER = "typebox";
|
|
116807
117560
|
var WORKFLOWS_SDK_MODULE = {
|
|
116808
117561
|
...exports_sdk_surface
|
|
@@ -116821,19 +117574,27 @@ var WORKFLOWS_BUILTIN_MODULE = {
|
|
|
116821
117574
|
var TYPEBOX_MODULE = {
|
|
116822
117575
|
...typeboxModule
|
|
116823
117576
|
};
|
|
117577
|
+
function createWorkflowVirtualModules(moduleSpecifier) {
|
|
117578
|
+
const builtinModuleSpecifier = `${moduleSpecifier}/builtin`;
|
|
117579
|
+
return {
|
|
117580
|
+
[moduleSpecifier]: WORKFLOWS_SDK_MODULE,
|
|
117581
|
+
[builtinModuleSpecifier]: WORKFLOWS_BUILTIN_MODULE,
|
|
117582
|
+
[`${builtinModuleSpecifier}/adversarial-verification`]: { default: adversarial_verification_default },
|
|
117583
|
+
[`${builtinModuleSpecifier}/classify-and-act`]: { default: classify_and_act_default },
|
|
117584
|
+
[`${builtinModuleSpecifier}/fan-out-and-synthesize`]: { default: fan_out_and_synthesize_default },
|
|
117585
|
+
[`${builtinModuleSpecifier}/generate-and-filter`]: { default: generate_and_filter_default },
|
|
117586
|
+
[`${builtinModuleSpecifier}/goal`]: { default: goal_default },
|
|
117587
|
+
[`${builtinModuleSpecifier}/loop-until-done`]: { default: loop_until_done_default },
|
|
117588
|
+
[`${builtinModuleSpecifier}/open-claude-design`]: { default: open_claude_design_default },
|
|
117589
|
+
[`${builtinModuleSpecifier}/ralph`]: { default: ralph_default },
|
|
117590
|
+
[`${builtinModuleSpecifier}/tournament`]: { default: tournament_default },
|
|
117591
|
+
[`${builtinModuleSpecifier}/steering-context`]: exports_steering_context
|
|
117592
|
+
};
|
|
117593
|
+
}
|
|
116824
117594
|
var WORKFLOWS_VIRTUAL_MODULES = {
|
|
116825
|
-
|
|
116826
|
-
|
|
116827
|
-
[TYPEBOX_MODULE_SPECIFIER]: TYPEBOX_MODULE
|
|
116828
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/adversarial-verification`]: { default: adversarial_verification_default },
|
|
116829
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/classify-and-act`]: { default: classify_and_act_default },
|
|
116830
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/fan-out-and-synthesize`]: { default: fan_out_and_synthesize_default },
|
|
116831
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/generate-and-filter`]: { default: generate_and_filter_default },
|
|
116832
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/goal`]: { default: goal_default },
|
|
116833
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/loop-until-done`]: { default: loop_until_done_default },
|
|
116834
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/open-claude-design`]: { default: open_claude_design_default },
|
|
116835
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/ralph`]: { default: ralph_default },
|
|
116836
|
-
[`${WORKFLOWS_BUILTIN_MODULE_SPECIFIER}/tournament`]: { default: tournament_default }
|
|
117595
|
+
...createWorkflowVirtualModules(WORKFLOWS_MODULE_SPECIFIER),
|
|
117596
|
+
...createWorkflowVirtualModules(LEGACY_WORKFLOWS_MODULE_SPECIFIER),
|
|
117597
|
+
[TYPEBOX_MODULE_SPECIFIER]: TYPEBOX_MODULE
|
|
116837
117598
|
};
|
|
116838
117599
|
var workflowModuleLoader = createJiti2(import.meta.url, {
|
|
116839
117600
|
moduleCache: false,
|
|
@@ -117478,27 +118239,6 @@ function ensurePostMortemStageHandle(runId, stage, deps) {
|
|
|
117478
118239
|
const handle = deps.registry.getOrCreateDetached(runId, stage.id, () => createPostMortemStageHandle(runId, stage, sessionFile, adapters, deps.cwd, deps.defaultSessionDir));
|
|
117479
118240
|
return { ok: true, handle };
|
|
117480
118241
|
}
|
|
117481
|
-
function acquirePostMortemStageHandle(runId, stage, deps) {
|
|
117482
|
-
if (!TERMINAL_POSTMORTEM_STATUSES.has(stage.status))
|
|
117483
|
-
return { ok: false, reason: "not_terminal" };
|
|
117484
|
-
const existing = deps.registry.peek(runId, stage.id);
|
|
117485
|
-
if (existing !== undefined && existing.isDisposed !== true) {
|
|
117486
|
-
return {
|
|
117487
|
-
ok: true,
|
|
117488
|
-
lease: deps.registry.acquireDetached(runId, stage.id, () => existing)
|
|
117489
|
-
};
|
|
117490
|
-
}
|
|
117491
|
-
if (deps.adapters?.agentSession === undefined)
|
|
117492
|
-
return { ok: false, reason: "no_adapter" };
|
|
117493
|
-
const sessionFile = stage.sessionFile;
|
|
117494
|
-
if (typeof sessionFile !== "string" || sessionFile.length === 0)
|
|
117495
|
-
return { ok: false, reason: "no_session" };
|
|
117496
|
-
if (!isReopenableSessionTranscript(sessionFile))
|
|
117497
|
-
return { ok: false, reason: "invalid_session" };
|
|
117498
|
-
const adapters = deps.adapters;
|
|
117499
|
-
const lease = deps.registry.acquireDetached(runId, stage.id, () => createPostMortemStageHandle(runId, stage, sessionFile, adapters, deps.cwd, deps.defaultSessionDir));
|
|
117500
|
-
return { ok: true, lease };
|
|
117501
|
-
}
|
|
117502
118242
|
function createPostMortemStageHandle(runId, stage, sessionFile, adapters, cwd, defaultSessionDir) {
|
|
117503
118243
|
const context = createStageContext2({
|
|
117504
118244
|
runId,
|
|
@@ -118228,7 +118968,7 @@ function formatWorkflowHeartbeatNoticeText(details) {
|
|
|
118228
118968
|
const workflowName = escapeQuotedText3(details.workflowName);
|
|
118229
118969
|
const elapsed = formatWorkflowHeartbeatElapsed(details);
|
|
118230
118970
|
const cadence = formatWorkflowHeartbeatCadence(details.intervalMinutes);
|
|
118231
|
-
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
|
|
118971
|
+
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}`;
|
|
118232
118972
|
}
|
|
118233
118973
|
function registerWorkflowHeartbeatRenderer(options) {
|
|
118234
118974
|
const register = options.registerMessageRenderer;
|
|
@@ -119460,6 +120200,241 @@ function createWorkflowExtensionRuntimeState(pi, adapters, resolveCwd = () => pi
|
|
|
119460
120200
|
};
|
|
119461
120201
|
}
|
|
119462
120202
|
|
|
120203
|
+
// dist/builtin/workflows/src/extension/pending-stage-intercom.ts
|
|
120204
|
+
var PENDING_STAGE_ROUTE_EVENT = "atomic:workflow-pending-stage-route";
|
|
120205
|
+
var PENDING_STAGE_MESSAGE_EVENT = "atomic:workflow-pending-stage-message";
|
|
120206
|
+
var PENDING_STAGE_UNDELIVERABLE_EVENT = "atomic:workflow-pending-stage-undeliverable";
|
|
120207
|
+
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.";
|
|
120208
|
+
function registerPendingStageIntercomBridge(pi, activeStore) {
|
|
120209
|
+
let disposed = false;
|
|
120210
|
+
let sweepPromise = Promise.resolve();
|
|
120211
|
+
const notifyUndeliverable = async (entry, reason, notificationId) => {
|
|
120212
|
+
const payload = {
|
|
120213
|
+
handled: false,
|
|
120214
|
+
runId: entry.runId,
|
|
120215
|
+
senderId: entry.from.id,
|
|
120216
|
+
...entry.senderRegistrationName === undefined ? {} : { senderRegistrationName: entry.senderRegistrationName },
|
|
120217
|
+
...entry.senderReturnAddress === undefined ? {} : { senderReturnAddress: entry.senderReturnAddress },
|
|
120218
|
+
messageId: entry.message.id,
|
|
120219
|
+
notificationId,
|
|
120220
|
+
reason
|
|
120221
|
+
};
|
|
120222
|
+
pi.events?.emit?.(PENDING_STAGE_UNDELIVERABLE_EVENT, payload);
|
|
120223
|
+
return payload.handled && await payload.completion === true;
|
|
120224
|
+
};
|
|
120225
|
+
const announceRoutes = () => {
|
|
120226
|
+
if (disposed)
|
|
120227
|
+
return;
|
|
120228
|
+
const runs = activeStore.runs();
|
|
120229
|
+
for (const run2 of runs) {
|
|
120230
|
+
const rootRunId = durableRootRunIdForRun(runs, run2.id);
|
|
120231
|
+
if (rootRunId === undefined)
|
|
120232
|
+
continue;
|
|
120233
|
+
pi.events?.emit?.(PENDING_STAGE_ROUTE_EVENT, {
|
|
120234
|
+
runId: run2.id,
|
|
120235
|
+
group: workflowInvocationIntercomGroup(rootRunId),
|
|
120236
|
+
capability: workflowPendingStageRouteCapability(activeStore, run2.id)
|
|
120237
|
+
});
|
|
120238
|
+
}
|
|
120239
|
+
sweepPromise = sweepPromise.then(() => settleUndeliverablePendingStageMessages(activeStore, notifyUndeliverable)).then(() => {
|
|
120240
|
+
return;
|
|
120241
|
+
}).catch((error) => console.warn("atomic-workflows: pending stage delivery sweep failed", error));
|
|
120242
|
+
};
|
|
120243
|
+
const unsubscribeStore = activeStore.subscribeInvalidation(announceRoutes);
|
|
120244
|
+
announceRoutes();
|
|
120245
|
+
const subscription = pi.events?.on?.(PENDING_STAGE_MESSAGE_EVENT, (payload) => {
|
|
120246
|
+
if (disposed || !isPendingStageMessageEvent(payload) || payload.handled)
|
|
120247
|
+
return;
|
|
120248
|
+
const runs = activeStore.runs();
|
|
120249
|
+
const run2 = runs.find((candidate) => candidate.id === payload.runId);
|
|
120250
|
+
if (run2 === undefined)
|
|
120251
|
+
return;
|
|
120252
|
+
const rootRunId = durableRootRunIdForRun(runs, run2.id);
|
|
120253
|
+
if (rootRunId === undefined)
|
|
120254
|
+
return;
|
|
120255
|
+
if (payload.live === true) {
|
|
120256
|
+
if (knownLiveStage(run2, payload.stageKey) === undefined)
|
|
120257
|
+
return;
|
|
120258
|
+
payload.handled = true;
|
|
120259
|
+
payload.completion = validateLiveDelivery(activeStore, payload);
|
|
120260
|
+
return;
|
|
120261
|
+
}
|
|
120262
|
+
const stage = knownUninitializedStage(run2, payload.stageKey);
|
|
120263
|
+
if (stage === undefined)
|
|
120264
|
+
return;
|
|
120265
|
+
payload.handled = true;
|
|
120266
|
+
payload.completion = queueAndPersist(activeStore, payload, workflowInvocationIntercomGroup(rootRunId), stage.pendingStageDeliveryAvailable === true);
|
|
120267
|
+
});
|
|
120268
|
+
const dispose2 = () => {
|
|
120269
|
+
disposed = true;
|
|
120270
|
+
unsubscribeStore();
|
|
120271
|
+
if (typeof subscription === "function")
|
|
120272
|
+
subscription();
|
|
120273
|
+
};
|
|
120274
|
+
pi.on?.("session_shutdown", dispose2);
|
|
120275
|
+
return dispose2;
|
|
120276
|
+
}
|
|
120277
|
+
function isPendingStageMessageEvent(value) {
|
|
120278
|
+
if (typeof value !== "object" || value === null)
|
|
120279
|
+
return false;
|
|
120280
|
+
const event = value;
|
|
120281
|
+
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";
|
|
120282
|
+
}
|
|
120283
|
+
function knownLiveStage(run2, stageKey) {
|
|
120284
|
+
const exactIds = run2.stages.filter((stage) => stage.id === stageKey);
|
|
120285
|
+
const candidates = exactIds.length > 0 ? exactIds : run2.stages.filter((stage) => stage.name === stageKey);
|
|
120286
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
120287
|
+
}
|
|
120288
|
+
async function validateLiveDelivery(activeStore, event) {
|
|
120289
|
+
const result = await activeStore.validateLiveStageMessage({
|
|
120290
|
+
runId: event.runId,
|
|
120291
|
+
stageKey: event.stageKey,
|
|
120292
|
+
from: event.from,
|
|
120293
|
+
message: event.message,
|
|
120294
|
+
queuedAt: new Date().toISOString()
|
|
120295
|
+
});
|
|
120296
|
+
if (result === undefined)
|
|
120297
|
+
return { outcome: "refused", reason: "Session not found" };
|
|
120298
|
+
if (result.outcome === "forward" || result.outcome === "delivered" || result.outcome === "queued")
|
|
120299
|
+
return result;
|
|
120300
|
+
if (result.outcome === "undeliverable") {
|
|
120301
|
+
return { outcome: "refused", reason: result.reason ?? "Pending-stage delivery was refused" };
|
|
120302
|
+
}
|
|
120303
|
+
return {
|
|
120304
|
+
outcome: "refused",
|
|
120305
|
+
reason: `Intercom message ID '${result.messageId}' conflicts with the durable identity for ${event.runId}:${event.stageKey}`,
|
|
120306
|
+
reasonCode: "message_id_conflict"
|
|
120307
|
+
};
|
|
120308
|
+
}
|
|
120309
|
+
async function queueAndPersist(activeStore, event, runGroup, pendingStageDeliveryAvailable) {
|
|
120310
|
+
if (event.message.expectsReply === true) {
|
|
120311
|
+
return { outcome: "refused", reason: PENDING_STAGE_ASK_REFUSAL };
|
|
120312
|
+
}
|
|
120313
|
+
if (!pendingStageDeliveryAvailable) {
|
|
120314
|
+
return {
|
|
120315
|
+
outcome: "refused",
|
|
120316
|
+
reason: `Workflow stage ${event.runId}:${event.stageKey} cannot receive Intercom messages before startup`
|
|
120317
|
+
};
|
|
120318
|
+
}
|
|
120319
|
+
const request = {
|
|
120320
|
+
runId: event.runId,
|
|
120321
|
+
stageKey: event.stageKey,
|
|
120322
|
+
from: event.from,
|
|
120323
|
+
...event.senderRegistrationName === undefined ? {} : { senderRegistrationName: event.senderRegistrationName },
|
|
120324
|
+
...event.senderReturnAddress === undefined ? {} : { senderReturnAddress: event.senderReturnAddress },
|
|
120325
|
+
message: event.message,
|
|
120326
|
+
queuedAt: new Date().toISOString()
|
|
120327
|
+
};
|
|
120328
|
+
const rootBackend = getDurableBackend();
|
|
120329
|
+
const backend = durableBackendForRun(rootBackend, activeStore.runs(), event.runId);
|
|
120330
|
+
if (backend === undefined)
|
|
120331
|
+
return { outcome: "refused", reason: "Session not found" };
|
|
120332
|
+
const result = await activeStore.queueStageMessage(request, event.from.group, runGroup, backend);
|
|
120333
|
+
if (result === undefined)
|
|
120334
|
+
return { outcome: "refused", reason: "Session not found" };
|
|
120335
|
+
if (!result.ok) {
|
|
120336
|
+
if (result.reason === "capacity") {
|
|
120337
|
+
return {
|
|
120338
|
+
outcome: "refused",
|
|
120339
|
+
reason: `Pending stage message queue is full (limit ${result.limit}) for ${result.runId}:${result.stageKey}`
|
|
120340
|
+
};
|
|
120341
|
+
}
|
|
120342
|
+
if (result.reason === "message_id_conflict") {
|
|
120343
|
+
return {
|
|
120344
|
+
outcome: "refused",
|
|
120345
|
+
reason: `Intercom message ID '${result.messageId}' was already queued for ${result.runId}:${result.stageKey} with a different target, sender, or payload`
|
|
120346
|
+
};
|
|
120347
|
+
}
|
|
120348
|
+
return { outcome: "refused", reason: "Target workflow run is in a different intercom group" };
|
|
120349
|
+
}
|
|
120350
|
+
if (result.entry.status === "delivered")
|
|
120351
|
+
return { outcome: "delivered" };
|
|
120352
|
+
if (result.entry.status === "undeliverable") {
|
|
120353
|
+
return {
|
|
120354
|
+
outcome: "refused",
|
|
120355
|
+
reason: result.entry.undeliverableReason ?? "Pending-stage delivery was refused"
|
|
120356
|
+
};
|
|
120357
|
+
}
|
|
120358
|
+
if (result.position === undefined)
|
|
120359
|
+
return { outcome: "refused", reason: "Pending-stage delivery was refused" };
|
|
120360
|
+
return { outcome: "queued", position: result.position };
|
|
120361
|
+
}
|
|
120362
|
+
function knownUninitializedStage(run2, stageKey) {
|
|
120363
|
+
const exactIds = run2.stages.filter((stage2) => stage2.id === stageKey);
|
|
120364
|
+
const candidates = exactIds.length > 0 ? exactIds : run2.stages.filter((stage2) => stage2.name === stageKey);
|
|
120365
|
+
if (candidates.length !== 1)
|
|
120366
|
+
return;
|
|
120367
|
+
const stage = candidates[0];
|
|
120368
|
+
return (stage.status === "pending" || stage.status === "running") && stage.sessionId === undefined && stage.sessionFile === undefined ? stage : undefined;
|
|
120369
|
+
}
|
|
120370
|
+
function pendingStageDestination(run2, entry) {
|
|
120371
|
+
if (entry.stageId !== undefined) {
|
|
120372
|
+
const candidates2 = run2.stages.filter((stage) => stage.id === entry.stageId);
|
|
120373
|
+
return candidates2.length === 1 ? candidates2[0] : undefined;
|
|
120374
|
+
}
|
|
120375
|
+
if (entry.stageReplayKey !== undefined) {
|
|
120376
|
+
const candidates2 = run2.stages.filter((stage) => stage.replayKey === entry.stageReplayKey);
|
|
120377
|
+
return candidates2.length === 1 ? candidates2[0] : undefined;
|
|
120378
|
+
}
|
|
120379
|
+
const exactIds = run2.stages.filter((stage) => stage.id === entry.stageKey);
|
|
120380
|
+
const candidates = exactIds.length > 0 ? exactIds : run2.stages.filter((stage) => stage.name === entry.stageKey);
|
|
120381
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
120382
|
+
}
|
|
120383
|
+
function pendingStageUndeliverableReason(run2, entry) {
|
|
120384
|
+
const stage = pendingStageDestination(run2, entry);
|
|
120385
|
+
if (run2.status === "cancelled") {
|
|
120386
|
+
return `Workflow run ${run2.id} terminated with status cancelled before stage ${entry.stageKey} started`;
|
|
120387
|
+
}
|
|
120388
|
+
if (stage?.status === "skipped") {
|
|
120389
|
+
return `Workflow stage ${entry.stageKey} was skipped${stage.skippedReason ? ` (${stage.skippedReason})` : ""}`;
|
|
120390
|
+
}
|
|
120391
|
+
if (isTerminalRunStatus(run2.status)) {
|
|
120392
|
+
return `Workflow run ${run2.id} terminated with status ${run2.status} before stage ${entry.stageKey} started`;
|
|
120393
|
+
}
|
|
120394
|
+
return;
|
|
120395
|
+
}
|
|
120396
|
+
function needsUndeliverableSettlement(run2, entry) {
|
|
120397
|
+
if (entry.status === "queued")
|
|
120398
|
+
return pendingStageUndeliverableReason(run2, entry) !== undefined;
|
|
120399
|
+
return entry.status === "undeliverable" && entry.undeliverableNotificationId !== undefined && entry.undeliverableNotifiedAt === undefined && entry.undeliverableReason !== undefined;
|
|
120400
|
+
}
|
|
120401
|
+
async function settleUndeliverablePendingStageMessages(activeStore, notify2) {
|
|
120402
|
+
const runs = activeStore.runs();
|
|
120403
|
+
if (!runs.some((run2) => run2.pendingStageMessages?.some((entry) => needsUndeliverableSettlement(run2, entry)))) {
|
|
120404
|
+
return 0;
|
|
120405
|
+
}
|
|
120406
|
+
let settled = 0;
|
|
120407
|
+
const rootBackend = getDurableBackend();
|
|
120408
|
+
for (const run2 of runs) {
|
|
120409
|
+
const backend = durableBackendForRun(rootBackend, runs, run2.id);
|
|
120410
|
+
if (backend === undefined) {
|
|
120411
|
+
throw new Error(`atomic-workflows: workflow run ${run2.id} has no durable owner for pending-stage settlement`);
|
|
120412
|
+
}
|
|
120413
|
+
for (const snapshotEntry of run2.pendingStageMessages ?? []) {
|
|
120414
|
+
let entry = snapshotEntry;
|
|
120415
|
+
if (entry.status === "queued") {
|
|
120416
|
+
const reason = pendingStageUndeliverableReason(run2, entry);
|
|
120417
|
+
if (reason === undefined)
|
|
120418
|
+
continue;
|
|
120419
|
+
if (await activeStore.markPendingStageMessageUndeliverable(run2.id, entry.stageKey, entry.id, reason, backend)) {
|
|
120420
|
+
settled += 1;
|
|
120421
|
+
}
|
|
120422
|
+
const currentRun2 = activeStore.runs().find((candidate) => candidate.id === run2.id);
|
|
120423
|
+
const currentEntry = currentRun2?.pendingStageMessages?.find((candidate) => candidate.stageKey === entry.stageKey && candidate.id === entry.id);
|
|
120424
|
+
if (currentEntry === undefined)
|
|
120425
|
+
continue;
|
|
120426
|
+
entry = currentEntry;
|
|
120427
|
+
}
|
|
120428
|
+
if (entry.status !== "undeliverable" || entry.undeliverableNotificationId === undefined || entry.undeliverableNotifiedAt !== undefined || entry.undeliverableReason === undefined)
|
|
120429
|
+
continue;
|
|
120430
|
+
if (!await notify2(entry, entry.undeliverableReason, entry.undeliverableNotificationId))
|
|
120431
|
+
continue;
|
|
120432
|
+
await activeStore.markPendingStageMessageUndeliverableNotified(run2.id, entry.stageKey, entry.id, entry.undeliverableNotificationId, new Date().toISOString(), backend);
|
|
120433
|
+
}
|
|
120434
|
+
}
|
|
120435
|
+
return settled;
|
|
120436
|
+
}
|
|
120437
|
+
|
|
119463
120438
|
// dist/builtin/workflows/src/extension/postmortem-deps.ts
|
|
119464
120439
|
function resolveStageCwd(runId) {
|
|
119465
120440
|
try {
|
|
@@ -119793,7 +120768,9 @@ function withWorkflowStageSessionOptions(options, meta2, pi) {
|
|
|
119793
120768
|
return {
|
|
119794
120769
|
...options,
|
|
119795
120770
|
excludedTools,
|
|
119796
|
-
...meta2 ? {
|
|
120771
|
+
...meta2 ? {
|
|
120772
|
+
orchestrationContext: meta2.orchestrationContext ?? options.orchestrationContext ?? makeWorkflowStageOrchestrationContext(meta2, pi)
|
|
120773
|
+
} : {}
|
|
119797
120774
|
};
|
|
119798
120775
|
}
|
|
119799
120776
|
function shouldBindStageUiContext(pi, meta2) {
|
|
@@ -119898,10 +120875,8 @@ function buildRuntimeAdapters(pi, options = {}) {
|
|
|
119898
120875
|
const sessionOptions = withWorkflowStageSessionOptions(stripWorkflowOnlyOptions2(stageOptions) ?? {}, meta2, pi);
|
|
119899
120876
|
const result = await createSession(sessionOptions);
|
|
119900
120877
|
const bindable = result.session;
|
|
119901
|
-
if (
|
|
119902
|
-
await bindable.bindExtensions({
|
|
119903
|
-
uiContext: makeStageExtensionUiContext(pi.ui ?? {}, meta2, broker)
|
|
119904
|
-
});
|
|
120878
|
+
if (typeof bindable.bindExtensions === "function") {
|
|
120879
|
+
await bindable.bindExtensions(shouldBindStageUiContext(pi, meta2) ? { uiContext: makeStageExtensionUiContext(pi.ui ?? {}, meta2, broker) } : {});
|
|
119905
120880
|
}
|
|
119906
120881
|
return result;
|
|
119907
120882
|
}
|
|
@@ -121995,6 +122970,139 @@ function buildWorkflowStatusListing(snapshots2, filter = "all", now = Date.now()
|
|
|
121995
122970
|
};
|
|
121996
122971
|
}
|
|
121997
122972
|
|
|
122973
|
+
// dist/builtin/workflows/src/extension/workflow-tool-answer.ts
|
|
122974
|
+
function answerResult(runId, stageId, status, message) {
|
|
122975
|
+
return { action: "answer", runId, stageId, status, message };
|
|
122976
|
+
}
|
|
122977
|
+
function terminalAnswerResult(runId, stageId, workflowStatus) {
|
|
122978
|
+
const message = `Cannot answer a prompt because workflow ${runId} has terminated with status ${workflowStatus}. If work remains, start a new workflow to address it.`;
|
|
122979
|
+
return {
|
|
122980
|
+
action: "answer",
|
|
122981
|
+
runId,
|
|
122982
|
+
stageId,
|
|
122983
|
+
status: "failed",
|
|
122984
|
+
code: "WORKFLOW_TERMINAL",
|
|
122985
|
+
workflowStatus,
|
|
122986
|
+
error: message,
|
|
122987
|
+
message
|
|
122988
|
+
};
|
|
122989
|
+
}
|
|
122990
|
+
function hasPayloadProperty(args) {
|
|
122991
|
+
return args.text !== undefined || args.response !== undefined || args.message !== undefined;
|
|
122992
|
+
}
|
|
122993
|
+
function promptPayloadFromArgs(args) {
|
|
122994
|
+
if (args.response !== undefined)
|
|
122995
|
+
return args.response;
|
|
122996
|
+
if (args.text !== undefined)
|
|
122997
|
+
return args.text;
|
|
122998
|
+
return args.message;
|
|
122999
|
+
}
|
|
123000
|
+
function textPayloadFromArgs(args) {
|
|
123001
|
+
if (args.text !== undefined)
|
|
123002
|
+
return args.text;
|
|
123003
|
+
if (typeof args.response === "string")
|
|
123004
|
+
return args.response;
|
|
123005
|
+
return args.message;
|
|
123006
|
+
}
|
|
123007
|
+
function brokerAnswerFromArgs(args) {
|
|
123008
|
+
if (args.response !== undefined) {
|
|
123009
|
+
const coerced = coerceStageInputAnswer(args.response);
|
|
123010
|
+
if (hasStageInputAnswerContent(coerced))
|
|
123011
|
+
return coerced;
|
|
123012
|
+
}
|
|
123013
|
+
const text = textPayloadFromArgs(args);
|
|
123014
|
+
return text !== undefined ? { text } : {};
|
|
123015
|
+
}
|
|
123016
|
+
function answerablePromptIds(stage) {
|
|
123017
|
+
const target = stage.workflowGraphTarget;
|
|
123018
|
+
const ids = [];
|
|
123019
|
+
const brokered = stageUiBroker.peekStagePrompt(target.runId, target.stageId);
|
|
123020
|
+
if (brokered !== undefined)
|
|
123021
|
+
ids.push(brokered.id);
|
|
123022
|
+
if (stage.pendingPrompt !== undefined)
|
|
123023
|
+
ids.push(stage.pendingPrompt.id);
|
|
123024
|
+
if (stage.status === "awaiting_input" && stage.promptFootprint?.kind === "custom")
|
|
123025
|
+
ids.push(stage.promptFootprint.id);
|
|
123026
|
+
return ids;
|
|
123027
|
+
}
|
|
123028
|
+
function inferPromptStageTarget(runId, promptId) {
|
|
123029
|
+
const pending = expandWorkflowGraph(readGraphStoreSnapshot(store), runId).stages.filter((stage) => {
|
|
123030
|
+
const ids = answerablePromptIds(stage);
|
|
123031
|
+
return promptId === undefined ? ids.length > 0 : ids.includes(promptId);
|
|
123032
|
+
});
|
|
123033
|
+
const only = pending[0];
|
|
123034
|
+
if (pending.length === 1 && only !== undefined) {
|
|
123035
|
+
return { ok: true, runId: only.workflowGraphTarget.runId, stageId: only.workflowGraphTarget.stageId };
|
|
123036
|
+
}
|
|
123037
|
+
if (pending.length === 0) {
|
|
123038
|
+
return promptId === undefined ? { ok: true, runId } : { ok: false, message: `No pending prompt ${promptId} in run ${runId}.` };
|
|
123039
|
+
}
|
|
123040
|
+
return {
|
|
123041
|
+
ok: false,
|
|
123042
|
+
message: `${pending.length} prompts pending; pass stageId: ${pending.map(expandedStageLabel).join(", ")}`
|
|
123043
|
+
};
|
|
123044
|
+
}
|
|
123045
|
+
async function workflowAnswerAction(args) {
|
|
123046
|
+
const target = resolveToolRunTarget(args, "No active run with a pending prompt.");
|
|
123047
|
+
if (target.kind === "all")
|
|
123048
|
+
return answerResult("--all", "", "noop", "Answer requires a single run.");
|
|
123049
|
+
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
123050
|
+
return answerResult(target.target, "", "noop", target.message);
|
|
123051
|
+
}
|
|
123052
|
+
const runs = store.runs();
|
|
123053
|
+
const runById = new Map(runs.map((run2) => [run2.id, run2]));
|
|
123054
|
+
const rootRunId = reciprocalWorkflowRootRunId(runById, target.runId) ?? target.runId;
|
|
123055
|
+
const rootRun = runById.get(rootRunId);
|
|
123056
|
+
if (rootRun !== undefined && isTerminalRunStatus(rootRun.status)) {
|
|
123057
|
+
return terminalAnswerResult(rootRun.id, args.stageId?.trim() ?? "", rootRun.status);
|
|
123058
|
+
}
|
|
123059
|
+
const requested = resolveToolStageTarget(target.runId, args.stageId);
|
|
123060
|
+
const stage = requested.ok && requested.stageId === undefined ? inferPromptStageTarget(target.runId, args.promptId) : requested;
|
|
123061
|
+
if (!stage.ok || stage.stageId === undefined) {
|
|
123062
|
+
return answerResult(target.runId, "", "noop", stage.ok ? "Stage id or name is required." : stage.message);
|
|
123063
|
+
}
|
|
123064
|
+
const stageRunId = stage.runId ?? target.runId;
|
|
123065
|
+
const snapshot2 = store.runs().find((run2) => run2.id === stageRunId)?.stages.find((item) => item.id === stage.stageId);
|
|
123066
|
+
const brokerPrompt = stageUiBroker.peekStagePrompt(stageRunId, stage.stageId);
|
|
123067
|
+
if (brokerPrompt !== undefined && (args.promptId === undefined || args.promptId === brokerPrompt.id)) {
|
|
123068
|
+
if (!hasPayloadProperty(args))
|
|
123069
|
+
return answerResult(stageRunId, stage.stageId, "noop", "Answer requires text, response, or message.");
|
|
123070
|
+
const ok2 = stageUiBroker.answerStagePrompt(stageRunId, stage.stageId, brokerAnswerFromArgs(args), {
|
|
123071
|
+
answerSource: "workflow_tool"
|
|
123072
|
+
});
|
|
123073
|
+
return answerResult(stageRunId, stage.stageId, ok2 ? "ok" : "noop", ok2 ? `Answered input request ${brokerPrompt.id}.` : `No matching pending input request ${brokerPrompt.id}.`);
|
|
123074
|
+
}
|
|
123075
|
+
const customPrompt = snapshot2?.status === "awaiting_input" && snapshot2.promptFootprint?.kind === "custom" ? snapshot2.promptFootprint : undefined;
|
|
123076
|
+
if (customPrompt !== undefined && (args.promptId === undefined || args.promptId === customPrompt.id)) {
|
|
123077
|
+
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.`);
|
|
123078
|
+
}
|
|
123079
|
+
const promptId = args.promptId ?? snapshot2?.pendingPrompt?.id;
|
|
123080
|
+
if (promptId === undefined) {
|
|
123081
|
+
return answerResult(stageRunId, stage.stageId, "noop", "No pending prompt to answer.");
|
|
123082
|
+
}
|
|
123083
|
+
if (!hasPayloadProperty(args))
|
|
123084
|
+
return answerResult(stageRunId, stage.stageId, "noop", "Answer requires text, response, or message.");
|
|
123085
|
+
if (stageUiBroker.wasStagePromptResolved(stageRunId, stage.stageId, promptId)) {
|
|
123086
|
+
return answerResult(stageRunId, stage.stageId, "ok", `Input request ${promptId} was already answered.`);
|
|
123087
|
+
}
|
|
123088
|
+
const rawPayload = promptPayloadFromArgs(args);
|
|
123089
|
+
const pendingPrompt = snapshot2?.pendingPrompt;
|
|
123090
|
+
const primitivePrompt = pendingPrompt?.id === promptId && isPrimitivePrompt(pendingPrompt) ? pendingPrompt : undefined;
|
|
123091
|
+
if (primitivePrompt !== undefined) {
|
|
123092
|
+
const coerced = coercePrimitivePromptAnswer(primitivePrompt, rawPayload);
|
|
123093
|
+
if (!coerced.ok)
|
|
123094
|
+
return answerResult(stageRunId, stage.stageId, "noop", primitivePromptAnswerRejection(promptId, primitivePrompt));
|
|
123095
|
+
const ok2 = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, coerced.value, {
|
|
123096
|
+
answerSource: "workflow_tool"
|
|
123097
|
+
});
|
|
123098
|
+
return answerResult(stageRunId, stage.stageId, ok2 ? "ok" : "noop", ok2 ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123099
|
+
}
|
|
123100
|
+
const ok = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, rawPayload, {
|
|
123101
|
+
answerSource: "workflow_tool"
|
|
123102
|
+
});
|
|
123103
|
+
return answerResult(stageRunId, stage.stageId, ok ? "ok" : "noop", ok ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123104
|
+
}
|
|
123105
|
+
|
|
121998
123106
|
// dist/builtin/workflows/src/extension/workflow-tool-content.ts
|
|
121999
123107
|
function stringifyWorkflowToolResult(result) {
|
|
122000
123108
|
return JSON.stringify(result, null, 2);
|
|
@@ -122003,7 +123111,7 @@ function compactWorkflowToolMessage(result) {
|
|
|
122003
123111
|
if (result.action === "reload") {
|
|
122004
123112
|
return `${result.action}: ${result.status} — ${result.message}`;
|
|
122005
123113
|
}
|
|
122006
|
-
const target = [result.runId, result.action === "
|
|
123114
|
+
const target = [result.runId, result.action === "answer" ? result.stageId : undefined].filter((part) => part !== undefined && part.length > 0).join("/");
|
|
122007
123115
|
return `${result.action}:${target ? ` ${target}` : ""} ${result.status} — ${result.message}`;
|
|
122008
123116
|
}
|
|
122009
123117
|
var STATUS_MESSAGE_CHAR_LIMIT = 120;
|
|
@@ -122079,7 +123187,7 @@ function renderStatusToolContent(result) {
|
|
|
122079
123187
|
for (const entry of run2.awaitingInput)
|
|
122080
123188
|
lines.push(statusAwaitingInputLine(entry));
|
|
122081
123189
|
});
|
|
122082
|
-
lines.push("hint: status with runId returns full run detail;
|
|
123190
|
+
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.");
|
|
122083
123191
|
return lines.join(`
|
|
122084
123192
|
`);
|
|
122085
123193
|
}
|
|
@@ -122207,7 +123315,7 @@ function renderWorkflowToolContent(result, args) {
|
|
|
122207
123315
|
return renderStagesToolContent(result);
|
|
122208
123316
|
case "stage":
|
|
122209
123317
|
return renderStageToolContent(result);
|
|
122210
|
-
case "
|
|
123318
|
+
case "answer":
|
|
122211
123319
|
case "pause":
|
|
122212
123320
|
case "reload":
|
|
122213
123321
|
case "interrupt":
|
|
@@ -122982,284 +124090,6 @@ function workflowTranscriptResult(args, source) {
|
|
|
122982
124090
|
});
|
|
122983
124091
|
}
|
|
122984
124092
|
|
|
122985
|
-
// dist/builtin/workflows/src/extension/workflow-tool-send.ts
|
|
122986
|
-
function hasPayloadProperty(args) {
|
|
122987
|
-
return args.text !== undefined || args.response !== undefined || args.message !== undefined;
|
|
122988
|
-
}
|
|
122989
|
-
function promptPayloadFromArgs(args) {
|
|
122990
|
-
if (args.response !== undefined)
|
|
122991
|
-
return args.response;
|
|
122992
|
-
if (args.text !== undefined)
|
|
122993
|
-
return args.text;
|
|
122994
|
-
return args.message;
|
|
122995
|
-
}
|
|
122996
|
-
function textPayloadFromArgs(args) {
|
|
122997
|
-
if (args.text !== undefined)
|
|
122998
|
-
return args.text;
|
|
122999
|
-
if (typeof args.response === "string")
|
|
123000
|
-
return args.response;
|
|
123001
|
-
if (args.message !== undefined)
|
|
123002
|
-
return args.message;
|
|
123003
|
-
return;
|
|
123004
|
-
}
|
|
123005
|
-
function brokerAnswerFromArgs(args) {
|
|
123006
|
-
if (args.response !== undefined) {
|
|
123007
|
-
const coerced = coerceStageInputAnswer(args.response);
|
|
123008
|
-
if (hasStageInputAnswerContent(coerced))
|
|
123009
|
-
return coerced;
|
|
123010
|
-
}
|
|
123011
|
-
const text = textPayloadFromArgs(args);
|
|
123012
|
-
return text !== undefined ? { text } : {};
|
|
123013
|
-
}
|
|
123014
|
-
function answersPendingPrompt(delivery, promptId) {
|
|
123015
|
-
return delivery === "answer" || delivery === "auto" || promptId !== undefined;
|
|
123016
|
-
}
|
|
123017
|
-
function answerablePromptIds(stage) {
|
|
123018
|
-
const target = stage.workflowGraphTarget;
|
|
123019
|
-
const ids = [];
|
|
123020
|
-
const brokered = stageUiBroker.peekStagePrompt(target.runId, target.stageId);
|
|
123021
|
-
if (brokered !== undefined)
|
|
123022
|
-
ids.push(brokered.id);
|
|
123023
|
-
if (stage.pendingPrompt !== undefined)
|
|
123024
|
-
ids.push(stage.pendingPrompt.id);
|
|
123025
|
-
if (stage.status === "awaiting_input" && stage.promptFootprint?.kind === "custom") {
|
|
123026
|
-
ids.push(stage.promptFootprint.id);
|
|
123027
|
-
}
|
|
123028
|
-
return ids;
|
|
123029
|
-
}
|
|
123030
|
-
function inferPromptStageTarget(runId, delivery, promptId) {
|
|
123031
|
-
if (!answersPendingPrompt(delivery, promptId))
|
|
123032
|
-
return { ok: true, runId };
|
|
123033
|
-
const pending = expandWorkflowGraph(readGraphStoreSnapshot(store), runId).stages.filter((stage) => {
|
|
123034
|
-
const ids = answerablePromptIds(stage);
|
|
123035
|
-
return promptId === undefined ? ids.length > 0 : ids.includes(promptId);
|
|
123036
|
-
});
|
|
123037
|
-
const only = pending[0];
|
|
123038
|
-
if (pending.length === 1 && only !== undefined) {
|
|
123039
|
-
return { ok: true, runId: only.workflowGraphTarget.runId, stageId: only.workflowGraphTarget.stageId };
|
|
123040
|
-
}
|
|
123041
|
-
if (pending.length === 0) {
|
|
123042
|
-
return promptId === undefined ? { ok: true, runId } : { ok: false, message: `No pending prompt ${promptId} in run ${runId}.` };
|
|
123043
|
-
}
|
|
123044
|
-
return {
|
|
123045
|
-
ok: false,
|
|
123046
|
-
message: `${pending.length} prompts pending; pass stageId: ${pending.map(expandedStageLabel).join(", ")}`
|
|
123047
|
-
};
|
|
123048
|
-
}
|
|
123049
|
-
function workflowSendResult(runId, stageId, delivery, status, message) {
|
|
123050
|
-
return { action: "send", runId, stageId, delivery, status, message };
|
|
123051
|
-
}
|
|
123052
|
-
function terminalWorkflowSendResult(runId, stageId, workflowStatus) {
|
|
123053
|
-
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.`;
|
|
123054
|
-
return {
|
|
123055
|
-
action: "send",
|
|
123056
|
-
runId,
|
|
123057
|
-
stageId,
|
|
123058
|
-
delivery: "rejected",
|
|
123059
|
-
status: "failed",
|
|
123060
|
-
code: "WORKFLOW_TERMINAL",
|
|
123061
|
-
workflowStatus,
|
|
123062
|
-
error: message,
|
|
123063
|
-
message
|
|
123064
|
-
};
|
|
123065
|
-
}
|
|
123066
|
-
|
|
123067
|
-
class WorkflowSendAdmissionError extends Error {
|
|
123068
|
-
result;
|
|
123069
|
-
constructor(result) {
|
|
123070
|
-
super(result.message);
|
|
123071
|
-
this.result = result;
|
|
123072
|
-
}
|
|
123073
|
-
}
|
|
123074
|
-
function terminalWorkflowSendResultForRoot(rootRunId, stageId) {
|
|
123075
|
-
const rootRun = store.runs().find((run2) => run2.id === rootRunId);
|
|
123076
|
-
return rootRun !== undefined && isTerminalRunStatus(rootRun.status) ? terminalWorkflowSendResult(rootRun.id, stageId, rootRun.status) : undefined;
|
|
123077
|
-
}
|
|
123078
|
-
async function deliverStageUserMessage(handle, text, deliverAs, beforeDelivery) {
|
|
123079
|
-
if (handle.sendUserMessage === undefined) {
|
|
123080
|
-
throw new Error("atomic-workflows: stage handle does not support admission-aware message delivery");
|
|
123081
|
-
}
|
|
123082
|
-
return handle.sendUserMessage(text, { deliverAs }, beforeDelivery);
|
|
123083
|
-
}
|
|
123084
|
-
function deliveryMessage(delivery) {
|
|
123085
|
-
if (delivery === "prompt")
|
|
123086
|
-
return "Prompt started for stage.";
|
|
123087
|
-
if (delivery === "steer")
|
|
123088
|
-
return "Steered live stage.";
|
|
123089
|
-
if (delivery === "followUp")
|
|
123090
|
-
return "Follow-up queued for stage.";
|
|
123091
|
-
return "Message handled by stage extension.";
|
|
123092
|
-
}
|
|
123093
|
-
async function workflowSendAction(args, deps = {}) {
|
|
123094
|
-
const target = resolveToolRunTarget(args, "No active run to message.");
|
|
123095
|
-
const requestedDelivery = args.delivery ?? "auto";
|
|
123096
|
-
if (target.kind === "all") {
|
|
123097
|
-
return workflowSendResult("--all", "", requestedDelivery, "noop", "Send requires a single run.");
|
|
123098
|
-
}
|
|
123099
|
-
if (target.kind === "malformed" || target.kind === "not_found") {
|
|
123100
|
-
return workflowSendResult(target.target, "", requestedDelivery, "noop", target.message);
|
|
123101
|
-
}
|
|
123102
|
-
const runs = store.runs();
|
|
123103
|
-
const runById = new Map(runs.map((run3) => [run3.id, run3]));
|
|
123104
|
-
const rootRunId = reciprocalWorkflowRootRunId(runById, target.runId) ?? target.runId;
|
|
123105
|
-
const rootRun = runById.get(rootRunId);
|
|
123106
|
-
if (rootRun !== undefined && isTerminalRunStatus(rootRun.status)) {
|
|
123107
|
-
return terminalWorkflowSendResult(rootRun.id, args.stageId?.trim() ?? "", rootRun.status);
|
|
123108
|
-
}
|
|
123109
|
-
const requested = resolveToolStageTarget(target.runId, args.stageId);
|
|
123110
|
-
const stage = requested.ok && requested.stageId === undefined ? inferPromptStageTarget(target.runId, requestedDelivery, args.promptId) : requested;
|
|
123111
|
-
if (!stage.ok || stage.stageId === undefined) {
|
|
123112
|
-
return workflowSendResult(target.runId, "", requestedDelivery, "noop", stage.ok ? "Stage id or name is required." : stage.message);
|
|
123113
|
-
}
|
|
123114
|
-
const resolvedStageId = stage.stageId;
|
|
123115
|
-
const stageRunId = stage.runId ?? target.runId;
|
|
123116
|
-
const run2 = store.runs().find((r) => r.id === stageRunId);
|
|
123117
|
-
const snapshot2 = run2?.stages.find((s) => s.id === stage.stageId);
|
|
123118
|
-
const brokerPrompt = stageUiBroker.peekStagePrompt(stageRunId, stage.stageId);
|
|
123119
|
-
const targetsBrokerPrompt = brokerPrompt !== undefined && (args.promptId === undefined || args.promptId === brokerPrompt.id) && (requestedDelivery === "answer" || args.promptId !== undefined || requestedDelivery === "auto");
|
|
123120
|
-
if (targetsBrokerPrompt && brokerPrompt !== undefined) {
|
|
123121
|
-
if (!hasPayloadProperty(args)) {
|
|
123122
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
|
|
123123
|
-
}
|
|
123124
|
-
const ok = stageUiBroker.answerStagePrompt(stageRunId, stage.stageId, brokerAnswerFromArgs(args), {
|
|
123125
|
-
answerSource: "workflow_tool"
|
|
123126
|
-
});
|
|
123127
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", ok ? "ok" : "noop", ok ? `Answered input request ${brokerPrompt.id}.` : `No matching pending input request ${brokerPrompt.id}.`);
|
|
123128
|
-
}
|
|
123129
|
-
const customPrompt = snapshot2?.status === "awaiting_input" && snapshot2.promptFootprint?.kind === "custom" ? snapshot2.promptFootprint : undefined;
|
|
123130
|
-
const targetsCustomPrompt = customPrompt !== undefined && (args.promptId === undefined || args.promptId === customPrompt.id) && (requestedDelivery === "answer" || args.promptId !== undefined || requestedDelivery === "auto");
|
|
123131
|
-
if (targetsCustomPrompt && customPrompt !== undefined) {
|
|
123132
|
-
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.`);
|
|
123133
|
-
}
|
|
123134
|
-
const targetsPrompt = requestedDelivery === "answer" || args.promptId !== undefined || requestedDelivery === "auto" && snapshot2?.pendingPrompt !== undefined;
|
|
123135
|
-
if (targetsPrompt) {
|
|
123136
|
-
const promptId = args.promptId ?? snapshot2?.pendingPrompt?.id;
|
|
123137
|
-
if (promptId === undefined) {
|
|
123138
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "No pending prompt to answer.");
|
|
123139
|
-
}
|
|
123140
|
-
if (!hasPayloadProperty(args)) {
|
|
123141
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", "Send requires text, response, or message.");
|
|
123142
|
-
}
|
|
123143
|
-
if (stageUiBroker.wasStagePromptResolved(stageRunId, stage.stageId, promptId)) {
|
|
123144
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "ok", `Input request ${promptId} was already answered.`);
|
|
123145
|
-
}
|
|
123146
|
-
const rawPayload = promptPayloadFromArgs(args);
|
|
123147
|
-
const pendingPrompt = snapshot2?.pendingPrompt;
|
|
123148
|
-
const primitivePrompt = pendingPrompt?.id === promptId && isPrimitivePrompt(pendingPrompt) ? pendingPrompt : undefined;
|
|
123149
|
-
if (primitivePrompt !== undefined) {
|
|
123150
|
-
const coercedPayload = coercePrimitivePromptAnswer(primitivePrompt, rawPayload);
|
|
123151
|
-
if (!coercedPayload.ok) {
|
|
123152
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", "noop", primitivePromptAnswerRejection(promptId, primitivePrompt));
|
|
123153
|
-
}
|
|
123154
|
-
const ok2 = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, coercedPayload.value, {
|
|
123155
|
-
answerSource: "workflow_tool"
|
|
123156
|
-
});
|
|
123157
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", ok2 ? "ok" : "noop", ok2 ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123158
|
-
}
|
|
123159
|
-
const ok = store.resolveStagePendingPrompt(stageRunId, stage.stageId, promptId, rawPayload, {
|
|
123160
|
-
answerSource: "workflow_tool"
|
|
123161
|
-
});
|
|
123162
|
-
return workflowSendResult(stageRunId, stage.stageId, "answer", ok ? "ok" : "noop", ok ? `Answered prompt ${promptId}.` : `No matching pending prompt ${promptId}.`);
|
|
123163
|
-
}
|
|
123164
|
-
const text = textPayloadFromArgs(args);
|
|
123165
|
-
if (text === undefined) {
|
|
123166
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Send requires text, response, or message.");
|
|
123167
|
-
}
|
|
123168
|
-
let lease;
|
|
123169
|
-
let handle;
|
|
123170
|
-
const existingHandle = stageControlRegistry.peek(stageRunId, stage.stageId);
|
|
123171
|
-
if (existingHandle !== undefined) {
|
|
123172
|
-
lease = stageControlRegistry.acquireDetached(stageRunId, stage.stageId, () => existingHandle);
|
|
123173
|
-
handle = lease.handle;
|
|
123174
|
-
} else if (deps.resolvePostMortemDeps !== undefined && snapshot2 !== undefined) {
|
|
123175
|
-
const acquired = acquirePostMortemStageHandle(stageRunId, snapshot2, deps.resolvePostMortemDeps(stageRunId));
|
|
123176
|
-
if (acquired.ok) {
|
|
123177
|
-
lease = acquired.lease;
|
|
123178
|
-
handle = lease.handle;
|
|
123179
|
-
}
|
|
123180
|
-
}
|
|
123181
|
-
if (handle === undefined) {
|
|
123182
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "No live handle for stage.");
|
|
123183
|
-
}
|
|
123184
|
-
let admitted = false;
|
|
123185
|
-
const admitDelivery = () => {
|
|
123186
|
-
const terminal = terminalWorkflowSendResultForRoot(rootRunId, args.stageId?.trim() ?? resolvedStageId);
|
|
123187
|
-
if (terminal !== undefined)
|
|
123188
|
-
throw new WorkflowSendAdmissionError(terminal);
|
|
123189
|
-
if (lease !== undefined && !lease.commit()) {
|
|
123190
|
-
throw new WorkflowSendAdmissionError(workflowSendResult(stageRunId, resolvedStageId, requestedDelivery, "noop", "Stage handle changed before message admission; retry against the current live stage."));
|
|
123191
|
-
}
|
|
123192
|
-
admitted = true;
|
|
123193
|
-
};
|
|
123194
|
-
const terminalPending = Promise.withResolvers();
|
|
123195
|
-
const unsubscribeTerminal = subscribeStoreInvalidation(store, () => {
|
|
123196
|
-
if (admitted)
|
|
123197
|
-
return;
|
|
123198
|
-
const terminal = terminalWorkflowSendResultForRoot(rootRunId, args.stageId?.trim() ?? resolvedStageId);
|
|
123199
|
-
if (terminal !== undefined)
|
|
123200
|
-
terminalPending.reject(new WorkflowSendAdmissionError(terminal));
|
|
123201
|
-
});
|
|
123202
|
-
const awaitAdmission = (operation) => Promise.race([operation, terminalPending.promise]);
|
|
123203
|
-
try {
|
|
123204
|
-
const isTerminalPostMortemStage = handle.status === "completed";
|
|
123205
|
-
if (requestedDelivery === "resume" && handle.status !== "paused" && !isTerminalPostMortemStage) {
|
|
123206
|
-
return workflowSendResult(stageRunId, stage.stageId, "resume", "noop", "Stage is not paused; no resume message was delivered.");
|
|
123207
|
-
}
|
|
123208
|
-
if (handle.status === "paused" && requestedDelivery !== "resume" && requestedDelivery !== "auto") {
|
|
123209
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Stage is paused; resume it before sending a new message.");
|
|
123210
|
-
}
|
|
123211
|
-
const resumesStage = requestedDelivery === "resume" || requestedDelivery === "auto" && handle.status === "paused";
|
|
123212
|
-
if (!resumesStage && handle.sendUserMessage === undefined) {
|
|
123213
|
-
return workflowSendResult(stageRunId, stage.stageId, requestedDelivery, "noop", "Stage handle does not support admission-aware message delivery.");
|
|
123214
|
-
}
|
|
123215
|
-
if (resumesStage) {
|
|
123216
|
-
if (isTerminalPostMortemStage) {
|
|
123217
|
-
return workflowSendResult(stageRunId, stage.stageId, "resume", "noop", 'Cannot resume a terminal post-mortem stage; use delivery "followUp" or "prompt" to continue its retained conversation.');
|
|
123218
|
-
}
|
|
123219
|
-
const resumedDelivery = await awaitAdmission(handle.resume(text, admitDelivery));
|
|
123220
|
-
if (resumedDelivery !== undefined && resumedDelivery !== "prompt") {
|
|
123221
|
-
return workflowSendResult(stageRunId, stage.stageId, resumedDelivery, "ok", deliveryMessage(resumedDelivery));
|
|
123222
|
-
}
|
|
123223
|
-
if (resumedDelivery === "prompt") {
|
|
123224
|
-
return workflowSendResult(stageRunId, stage.stageId, "prompt", "ok", "Resumed stage and started prompt.");
|
|
123225
|
-
}
|
|
123226
|
-
const hasResumeMessage = text.trim().length > 0;
|
|
123227
|
-
return workflowSendResult(stageRunId, stage.stageId, "resume", "ok", hasResumeMessage ? "Resumed interrupted stage with message." : "Resumed stage.");
|
|
123228
|
-
}
|
|
123229
|
-
if (requestedDelivery === "steer") {
|
|
123230
|
-
if (isTerminalPostMortemStage) {
|
|
123231
|
-
return workflowSendResult(stageRunId, stage.stageId, "steer", "noop", 'Cannot steer a terminal post-mortem stage; use delivery "followUp" or "prompt" to continue its retained conversation.');
|
|
123232
|
-
}
|
|
123233
|
-
const delivery2 = await awaitAdmission(deliverStageUserMessage(handle, text, "steer", admitDelivery));
|
|
123234
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery2, "ok", deliveryMessage(delivery2));
|
|
123235
|
-
}
|
|
123236
|
-
if (requestedDelivery === "auto" && handle.isStreaming && !isTerminalPostMortemStage) {
|
|
123237
|
-
const delivery2 = await awaitAdmission(deliverStageUserMessage(handle, text, "steer", admitDelivery));
|
|
123238
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery2, "ok", deliveryMessage(delivery2));
|
|
123239
|
-
}
|
|
123240
|
-
if (requestedDelivery === "prompt") {
|
|
123241
|
-
const delivery2 = await awaitAdmission(deliverStageUserMessage(handle, text, undefined, admitDelivery));
|
|
123242
|
-
const message = delivery2 === "prompt" ? "Prompt sent to stage." : deliveryMessage(delivery2);
|
|
123243
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery2, "ok", message);
|
|
123244
|
-
}
|
|
123245
|
-
const delivery = await awaitAdmission(deliverStageUserMessage(handle, text, "followUp", admitDelivery));
|
|
123246
|
-
return workflowSendResult(stageRunId, stage.stageId, delivery, "ok", deliveryMessage(delivery));
|
|
123247
|
-
} catch (error) {
|
|
123248
|
-
if (error instanceof WorkflowSendAdmissionError)
|
|
123249
|
-
return error.result;
|
|
123250
|
-
throw error;
|
|
123251
|
-
} finally {
|
|
123252
|
-
unsubscribeTerminal();
|
|
123253
|
-
if (!admitted) {
|
|
123254
|
-
try {
|
|
123255
|
-
await lease?.release();
|
|
123256
|
-
} catch (error) {
|
|
123257
|
-
console.warn("atomic-workflows: provisional workflow-send handle cleanup failed", error);
|
|
123258
|
-
}
|
|
123259
|
-
}
|
|
123260
|
-
}
|
|
123261
|
-
}
|
|
123262
|
-
|
|
123263
124093
|
// dist/builtin/workflows/src/extension/workflow-tool.ts
|
|
123264
124094
|
async function resolveDurableInspectionSource(args, runtime) {
|
|
123265
124095
|
const target = args.runId?.trim();
|
|
@@ -123287,7 +124117,7 @@ function durableInspectionError(action, runId, message) {
|
|
|
123287
124117
|
truncated: false
|
|
123288
124118
|
};
|
|
123289
124119
|
}
|
|
123290
|
-
function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflowResourcesLoaded = () => {}
|
|
124120
|
+
function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflowResourcesLoaded = () => {}) {
|
|
123291
124121
|
return async function executeWorkflowTool(args, ctx, signal, onRunAccepted) {
|
|
123292
124122
|
const action = args.action ?? "run";
|
|
123293
124123
|
const runId = args.runId ?? "";
|
|
@@ -123376,8 +124206,8 @@ function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflo
|
|
|
123376
124206
|
return workflowStageResult(args, source);
|
|
123377
124207
|
return workflowTranscriptResult(args, source);
|
|
123378
124208
|
}
|
|
123379
|
-
case "
|
|
123380
|
-
return awaitRequest(
|
|
124209
|
+
case "answer":
|
|
124210
|
+
return awaitRequest(workflowAnswerAction(args));
|
|
123381
124211
|
case "pause":
|
|
123382
124212
|
return awaitRequest(workflowPauseAction(args));
|
|
123383
124213
|
case "reload":
|
|
@@ -123438,8 +124268,8 @@ function renderCall(args, opts = {}) {
|
|
|
123438
124268
|
case "transcript":
|
|
123439
124269
|
line = name === undefined ? "workflow: read stage transcript" : `workflow: read stage transcript in ${quoted(name)}`;
|
|
123440
124270
|
break;
|
|
123441
|
-
case "
|
|
123442
|
-
line = name === undefined ? "workflow:
|
|
124271
|
+
case "answer":
|
|
124272
|
+
line = name === undefined ? "workflow: answer prompt" : `workflow: answer prompt in ${quoted(name)}`;
|
|
123443
124273
|
break;
|
|
123444
124274
|
case "pause":
|
|
123445
124275
|
line = name === undefined ? "workflow: pause run" : `workflow: pause run ${quoted(name)}`;
|
|
@@ -123631,9 +124461,9 @@ function renderResult(result, opts) {
|
|
|
123631
124461
|
const suffix = r.truncated ? " (truncated)" : "";
|
|
123632
124462
|
return renderNotice("WORKFLOW TRANSCRIPT", `${r.runId}/${r.stageId} ${r.source}: ${text}${suffix}`, opts, themed);
|
|
123633
124463
|
}
|
|
123634
|
-
case "
|
|
124464
|
+
case "answer": {
|
|
123635
124465
|
const r = result;
|
|
123636
|
-
return renderNotice("WORKFLOW
|
|
124466
|
+
return renderNotice("WORKFLOW ANSWER", `${r.runId}/${r.stageId}: ${r.message}`, opts, themed);
|
|
123637
124467
|
}
|
|
123638
124468
|
case "pause": {
|
|
123639
124469
|
const r = result;
|
|
@@ -123676,13 +124506,14 @@ function renderResult(result, opts) {
|
|
|
123676
124506
|
}
|
|
123677
124507
|
|
|
123678
124508
|
// dist/builtin/workflows/src/extension/workflow-prompts.ts
|
|
123679
|
-
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, " + "
|
|
124509
|
+
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.";
|
|
123680
124510
|
var DEFAULT_PROMPT_GUIDANCE = [
|
|
123681
124511
|
`**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.
|
|
123682
124512
|
- 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.
|
|
123683
124513
|
- Treat loop or stop-condition wording as a strong workflow signal, especially "do X until Y", "repeat until", "iterate until", "review/fix until passing", "run checks and fix until green", "keep going until done", or any prompt that names an approval gate or evidence requirement.
|
|
123684
124514
|
- Do not force-fit an installed workflow. When another graph better matches the task, write a task-specific TypeScript workflow inline. Rich custom workflows may use deterministic branching, dynamic fan-out, child workflows, artifacts, structured outputs, human-in-the-loop prompts, gates, retries, and explicit stop conditions.
|
|
123685
124515
|
- Before launching any workflow for a non-trivial task, perform a short workflow-architecture pass. Derive implementation lifecycle needs, whole-codebase research needs, independent slices, competing strategies, exact API/type/build contracts, schema or generated-artifact contracts, state transitions/lifecycle behavior, deterministic stop conditions, and required evidence. Enumerate implementation slices in this same pass, not a second planning ritual; give each slice its own objective, acceptance criteria, and gates, and require each to leave a buildable, testable repository state before the next slice. Use a compact internal coverage matrix: \`requirement/risk | required evidence | workflow/stage that produces it | gap\`. Add the topology row \`acyclic topology | node/edge sketch for branches and loops | architecture pass | unresolved back-edge\`. Unresolved material rows or back-edges must change the graph before launch.
|
|
124516
|
+
- In that same pass, for coding tasks, infer repository intent from repo-level behavior before freezing objectives and acceptance criteria: mine git history (including \`git log --show-signature\`), merged PRs, issues, commits, and review comments for unwritten conventions — commit signing, message style and issue linking, changelog discipline, PR size and review norms — weighing the requesting user's own activity highest, so authored workflow contracts capture norms no doc states. For non-coding tasks, mine the analogous available context sources (issue trackers, long-form docs, chat/comment threads, prior artifacts) the same way. Inferred conventions fill contract gaps; they never override the stated objective or explicit repository docs.
|
|
123686
124517
|
- In that architecture pass, sketch each branch, loop, and nested workflow boundary. Identify which stages repeat, require distinct tracked work for every iteration, name the current frontier before each repeat, reject self-edges and ancestor edges, compose nested workflows through \`ctx.workflow(...)\` boundaries rather than recursive \`run\` invocation, and preserve stable per-iteration identity and call order for resume/replay.
|
|
123687
124518
|
- Compare candidate workflows by guarantees, not broad objectives: run one named workflow only when it covers the lifecycle and produces evidence for every material requirement/risk. A generic implementation workflow may cover the lifecycle without covering exact API/type/build contracts, schemas/generated artifacts, state transitions, or domain-specific gates. Do not treat "has reviewers" as proof that a task-specific risk is covered.
|
|
123688
124519
|
- Use these routing signals without adding decorative stages: broad repository uncertainty → Fan-out-and-synthesize with repository-focused branches; independent slices → Fan-out-and-synthesize; plausible-but-wrong contract risk → Adversarial verification or a task-specific verification stage; competing architectures or implementations → Generate-and-filter or Tournament; an explicit repeat-until condition → Loop until done; implementation lifecycle → a task-specific worker/reviewer loop; exact API/build/schema requirements → dedicated deterministic gates.
|
|
@@ -123707,16 +124538,16 @@ var DEFAULT_PROMPT_GUIDANCE = [
|
|
|
123707
124538
|
`**Workflow discovery and lifecycle**:
|
|
123708
124539
|
- 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.
|
|
123709
124540
|
- 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.
|
|
123710
|
-
- Heartbeat cadence is 15 minutes by default.
|
|
124541
|
+
- 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.
|
|
123711
124542
|
- 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.
|
|
123712
|
-
- Tag steering the same way.
|
|
123713
|
-
- 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\`, \`
|
|
123714
|
-
- \`workflow
|
|
124543
|
+
- 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.
|
|
124544
|
+
- 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.
|
|
124545
|
+
- \`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.
|
|
123715
124546
|
- 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.
|
|
123716
124547
|
- 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.
|
|
123717
124548
|
- 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.
|
|
123718
124549
|
- 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.
|
|
123719
|
-
- 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\`
|
|
124550
|
+
- 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.
|
|
123720
124551
|
- 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.`,
|
|
123721
124552
|
`**Workflow authoring and handoffs**:
|
|
123722
124553
|
- 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.
|
|
@@ -123778,26 +124609,26 @@ var WorkflowParametersSchema = Type36.Object({
|
|
|
123778
124609
|
Type36.Literal("stages"),
|
|
123779
124610
|
Type36.Literal("stage"),
|
|
123780
124611
|
Type36.Literal("transcript"),
|
|
123781
|
-
Type36.Literal("
|
|
124612
|
+
Type36.Literal("answer"),
|
|
123782
124613
|
Type36.Literal("pause"),
|
|
123783
124614
|
Type36.Literal("interrupt"),
|
|
123784
124615
|
Type36.Literal("quit"),
|
|
123785
124616
|
Type36.Literal("resume"),
|
|
123786
124617
|
Type36.Literal("reload")
|
|
123787
124618
|
], {
|
|
123788
|
-
description: "Workflow action: run/list/get/inputs/models/status, inspect stage metadata,
|
|
124619
|
+
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."
|
|
123789
124620
|
})),
|
|
123790
124621
|
runId: Type36.Optional(Type36.String({
|
|
123791
|
-
description: "Full 36-character run UUID for status/stages/stage/transcript/
|
|
124622
|
+
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."
|
|
123792
124623
|
})),
|
|
123793
124624
|
all: Type36.Optional(Type36.Boolean({
|
|
123794
124625
|
description: "Apply supported run-control actions (pause/interrupt/quit) to all in-flight runs instead of one run; cannot be combined with stageId."
|
|
123795
124626
|
})),
|
|
123796
124627
|
stageId: Type36.Optional(Type36.String({
|
|
123797
|
-
description: "Exact stage id or exact stage name for stage-scoped inspection, transcript,
|
|
124628
|
+
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."
|
|
123798
124629
|
})),
|
|
123799
124630
|
message: Type36.Optional(Type36.String({
|
|
123800
|
-
description: "
|
|
124631
|
+
description: "Prompt answer text for answer, or optional text forwarded when resuming paused work."
|
|
123801
124632
|
})),
|
|
123802
124633
|
statusFilter: Type36.Optional(Type36.Union([
|
|
123803
124634
|
Type36.Literal("pending"),
|
|
@@ -123829,21 +124660,11 @@ var WorkflowParametersSchema = Type36.Object({
|
|
|
123829
124660
|
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."
|
|
123830
124661
|
})),
|
|
123831
124662
|
text: Type36.Optional(Type36.String({
|
|
123832
|
-
description: "Text
|
|
124663
|
+
description: "Text for a pending prompt answer."
|
|
123833
124664
|
})),
|
|
123834
124665
|
response: Type36.Optional(WorkflowResponseSchema),
|
|
123835
|
-
delivery: Type36.Optional(Type36.Union([
|
|
123836
|
-
Type36.Literal("auto"),
|
|
123837
|
-
Type36.Literal("answer"),
|
|
123838
|
-
Type36.Literal("prompt"),
|
|
123839
|
-
Type36.Literal("steer"),
|
|
123840
|
-
Type36.Literal("followUp"),
|
|
123841
|
-
Type36.Literal("resume")
|
|
123842
|
-
], {
|
|
123843
|
-
description: "Delivery mode for the send action: auto answers pending prompts first, then resumes paused stages, steers streaming stages, or queues a follow-up."
|
|
123844
|
-
})),
|
|
123845
124666
|
promptId: Type36.Optional(Type36.String({
|
|
123846
|
-
description: "Pending prompt identifier
|
|
124667
|
+
description: "Pending prompt identifier for the answer action."
|
|
123847
124668
|
})),
|
|
123848
124669
|
reason: Type36.Optional(Type36.String({
|
|
123849
124670
|
description: "Human-readable reason for the reload action, echoed in the reload result."
|
|
@@ -123855,7 +124676,7 @@ var WORKFLOW_TOOL_REQUEST_TIMEOUT_MS = 120000;
|
|
|
123855
124676
|
var MUTATING_WORKFLOW_ACTIONS = new Set([
|
|
123856
124677
|
"reload",
|
|
123857
124678
|
"run",
|
|
123858
|
-
"
|
|
124679
|
+
"answer",
|
|
123859
124680
|
"pause",
|
|
123860
124681
|
"resume",
|
|
123861
124682
|
"interrupt",
|
|
@@ -123976,10 +124797,11 @@ function factory(pi) {
|
|
|
123976
124797
|
const postMortemHandleResolver = createPostMortemHandleResolver(postMortemResolverDeps);
|
|
123977
124798
|
const overlay = buildWorkflowOverlay(pi, postMortemHandleResolver);
|
|
123978
124799
|
registerCompletedStageIntercomAskRouter(pi, postMortemHandleResolver);
|
|
124800
|
+
registerPendingStageIntercomBridge(pi, store);
|
|
123979
124801
|
const workflowCommands = new Map;
|
|
123980
124802
|
const storeWidgetRef = { current: null };
|
|
123981
124803
|
const intercomControlRef = { current: null };
|
|
123982
|
-
const executeWorkflowTool = makeExecuteWorkflowTool((ctx) => runtimeState.runtimeForContext(ctx), runtimeState.reloadWorkflowResources, runtimeState.ensureWorkflowResourcesLoaded
|
|
124804
|
+
const executeWorkflowTool = makeExecuteWorkflowTool((ctx) => runtimeState.runtimeForContext(ctx), runtimeState.reloadWorkflowResources, runtimeState.ensureWorkflowResourcesLoaded);
|
|
123983
124805
|
const executeWorkflowToolWithAutoAttach = async (args, ctx, signal, onRunAccepted) => {
|
|
123984
124806
|
const result = await executeWorkflowTool(args, ctx, signal, onRunAccepted);
|
|
123985
124807
|
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) {
|