@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
|
@@ -0,0 +1,2447 @@
|
|
|
1
|
+
import {
|
|
2
|
+
build_scoring_prompt,
|
|
3
|
+
scoring_prompt_reads
|
|
4
|
+
} from "./chunk-7430zyas.js";
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_FALL_DELTA,
|
|
7
|
+
DEFAULT_RISE_DELTA,
|
|
8
|
+
classify_trend
|
|
9
|
+
} from "./chunk-6fqs7c01.js";
|
|
10
|
+
import {
|
|
11
|
+
VERIFICATION_SCALE
|
|
12
|
+
} from "./chunk-cg9tmks0.js";
|
|
13
|
+
import {
|
|
14
|
+
sessionScopedExtensionState
|
|
15
|
+
} from "./chunk-5n10x7j2.js";
|
|
16
|
+
import {
|
|
17
|
+
getAgentDir,
|
|
18
|
+
getEnvValue
|
|
19
|
+
} from "./chunk-x2ghn0je.js";
|
|
20
|
+
|
|
21
|
+
// dist/builtin/workflows/src/shared/workflow-artifacts.ts
|
|
22
|
+
import { randomUUID } from "node:crypto";
|
|
23
|
+
import { mkdir, readdir, rm, stat } from "node:fs/promises";
|
|
24
|
+
import { dirname, join } from "node:path";
|
|
25
|
+
// dist/builtin/workflows/src/shared/workflow-failures-contract.ts
|
|
26
|
+
var WORKFLOW_FAILURE_KINDS = new Set([
|
|
27
|
+
"auth",
|
|
28
|
+
"rate_limit",
|
|
29
|
+
"provider",
|
|
30
|
+
"cancelled",
|
|
31
|
+
"unknown"
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
// dist/builtin/workflows/src/shared/workflow-failures-decisions.ts
|
|
35
|
+
var INVALID_API_KEY_CODES = new Set([
|
|
36
|
+
"401",
|
|
37
|
+
"invalid_api_key",
|
|
38
|
+
"incorrect_api_key",
|
|
39
|
+
"invalid_api_key_error",
|
|
40
|
+
"invalid_credentials",
|
|
41
|
+
"bad_credentials",
|
|
42
|
+
"authentication_error"
|
|
43
|
+
]);
|
|
44
|
+
var LOGIN_REQUIRED_CODES = new Set([
|
|
45
|
+
"auth",
|
|
46
|
+
"auth_required",
|
|
47
|
+
"authentication_required",
|
|
48
|
+
"login_required",
|
|
49
|
+
"not_logged_in"
|
|
50
|
+
]);
|
|
51
|
+
var MISSING_API_KEY_CODES = new Set(["missing_api_key", "api_key_missing", "no_api_key"]);
|
|
52
|
+
var RATE_LIMIT_CODES = new Set(["429", "rate_limit", "rate_limited", "rate_limit_exceeded", "too_many_requests"]);
|
|
53
|
+
var QUOTA_LIMIT_CODES = new Set([
|
|
54
|
+
"quota",
|
|
55
|
+
"quota_exceeded",
|
|
56
|
+
"insufficient_quota",
|
|
57
|
+
"usage_limit",
|
|
58
|
+
"usage_limit_exceeded"
|
|
59
|
+
]);
|
|
60
|
+
var CANCELLED_CODES = new Set(["aborterror", "aborted", "cancelled", "canceled"]);
|
|
61
|
+
var PROVIDER_UNAVAILABLE_CODES = new Set([
|
|
62
|
+
"500",
|
|
63
|
+
"502",
|
|
64
|
+
"503",
|
|
65
|
+
"504",
|
|
66
|
+
"provider_error",
|
|
67
|
+
"service_unavailable",
|
|
68
|
+
"temporarily_unavailable",
|
|
69
|
+
"overloaded",
|
|
70
|
+
"timeout",
|
|
71
|
+
"network_error"
|
|
72
|
+
]);
|
|
73
|
+
var UNKNOWN_MODEL_CODES = new Set(["unknown_model", "model_not_found", "model_not_available", "unsupported_model"]);
|
|
74
|
+
var FORBIDDEN_CONFIG_CODES = new Set([
|
|
75
|
+
"403",
|
|
76
|
+
"forbidden",
|
|
77
|
+
"permission_denied",
|
|
78
|
+
"access_denied",
|
|
79
|
+
"forbidden_config",
|
|
80
|
+
"invalid_model_config",
|
|
81
|
+
"model_access_denied"
|
|
82
|
+
]);
|
|
83
|
+
var INVALID_API_KEY_CONTEXT = new Set(["invalid", "incorrect"]);
|
|
84
|
+
var AUTH_CONTEXT = new Set([
|
|
85
|
+
"token",
|
|
86
|
+
"credential",
|
|
87
|
+
"credentials",
|
|
88
|
+
"required",
|
|
89
|
+
"expired",
|
|
90
|
+
"invalid",
|
|
91
|
+
"missing",
|
|
92
|
+
"unauthorized",
|
|
93
|
+
"login",
|
|
94
|
+
"signin"
|
|
95
|
+
]);
|
|
96
|
+
var MODEL_PROVIDER_CONTEXT = new Set(["unavailable", "overloaded", "temporarily", "service"]);
|
|
97
|
+
var PROVIDER_CONTEXT = new Set(["error", "failure", "failed", "overloaded", "unavailable", "temporarily", "service"]);
|
|
98
|
+
var STATUS_MESSAGE_REFINEMENT_CODES = new Set([
|
|
99
|
+
"invalid_api_key",
|
|
100
|
+
"missing_api_key",
|
|
101
|
+
"unknown_model",
|
|
102
|
+
"forbidden_config"
|
|
103
|
+
]);
|
|
104
|
+
var BROAD_AUTH_MESSAGE_REFINEMENT_CODES = new Set([
|
|
105
|
+
"invalid_api_key",
|
|
106
|
+
"missing_api_key"
|
|
107
|
+
]);
|
|
108
|
+
var STATUS_RELATED_MESSAGE_REFINEMENT_CODES = new Set([
|
|
109
|
+
"invalid_api_key",
|
|
110
|
+
"missing_api_key",
|
|
111
|
+
"unknown_model",
|
|
112
|
+
"forbidden_config",
|
|
113
|
+
"rate_limited",
|
|
114
|
+
"quota_limited",
|
|
115
|
+
"cancelled"
|
|
116
|
+
]);
|
|
117
|
+
// dist/builtin/workflows/src/durable/dbos-process-owner.ts
|
|
118
|
+
var DBOS_PROCESS_OWNER_KEY = Symbol.for("atomic-workflows/dbos-process-owner@1");
|
|
119
|
+
function emptyOwner() {
|
|
120
|
+
return {
|
|
121
|
+
version: 1,
|
|
122
|
+
state: "uninitialized",
|
|
123
|
+
configured: undefined,
|
|
124
|
+
active: undefined,
|
|
125
|
+
launchPromise: undefined,
|
|
126
|
+
shutdownPromise: undefined,
|
|
127
|
+
failure: undefined,
|
|
128
|
+
wrappers: undefined
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function ownerBag() {
|
|
132
|
+
return globalThis;
|
|
133
|
+
}
|
|
134
|
+
function getDbosProcessOwner() {
|
|
135
|
+
const bag = ownerBag();
|
|
136
|
+
const existing = bag[DBOS_PROCESS_OWNER_KEY];
|
|
137
|
+
if (existing !== undefined && existing.version === 1)
|
|
138
|
+
return existing;
|
|
139
|
+
const created = emptyOwner();
|
|
140
|
+
bag[DBOS_PROCESS_OWNER_KEY] = created;
|
|
141
|
+
return created;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// dist/builtin/workflows/src/durable/dbos-sdk-handle.ts
|
|
145
|
+
var ATOMIC_EXECUTOR_ID = `atomic-${process.pid.toString(36)}-${crypto.randomUUID().slice(0, 8)}`;
|
|
146
|
+
|
|
147
|
+
// dist/builtin/workflows/src/durable/dbos-embedded-postgres-root.ts
|
|
148
|
+
var HASH_CHUNK_BYTES = 64 * 1024;
|
|
149
|
+
|
|
150
|
+
// dist/builtin/workflows/src/durable/dbos-embedded-postgres.ts
|
|
151
|
+
var EMBEDDED_HOST = "127.0.0.1";
|
|
152
|
+
var EMBEDDED_PORT = 5439;
|
|
153
|
+
var EMBEDDED_USER = "postgres";
|
|
154
|
+
var EMBEDDED_PASSWORD = "atomic";
|
|
155
|
+
var EMBEDDED_DBOS_SYSTEM_DATABASE_URL = `postgresql://${EMBEDDED_USER}:${EMBEDDED_PASSWORD}@${EMBEDDED_HOST}:${EMBEDDED_PORT}/atomic_workflows_dbos_sys?connect_timeout=10&sslmode=disable`;
|
|
156
|
+
|
|
157
|
+
// dist/builtin/workflows/src/durable/dbos-lifecycle.ts
|
|
158
|
+
class DbosDurabilityError extends Error {
|
|
159
|
+
constructor(message, options) {
|
|
160
|
+
super(message, options);
|
|
161
|
+
this.name = "DbosDurabilityError";
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
class DbosNotReadyError extends DbosDurabilityError {
|
|
166
|
+
constructor() {
|
|
167
|
+
super("DBOS workflow durability is not ready. Await initializeDurableBackend() before accessing workflows.");
|
|
168
|
+
this.name = "DbosNotReadyError";
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function owner() {
|
|
172
|
+
return getDbosProcessOwner();
|
|
173
|
+
}
|
|
174
|
+
function getReadyDbosBackendSync() {
|
|
175
|
+
const slot = owner();
|
|
176
|
+
return slot.state === "ready" ? slot.active?.backend : undefined;
|
|
177
|
+
}
|
|
178
|
+
function dbosLifecycleState() {
|
|
179
|
+
return owner().state;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// dist/builtin/workflows/src/durable/factory.ts
|
|
183
|
+
var injectedBackend;
|
|
184
|
+
var initializedBackend;
|
|
185
|
+
function isMemoizedBackendUsable(backend) {
|
|
186
|
+
return !backend.persistent || dbosLifecycleState() === "ready";
|
|
187
|
+
}
|
|
188
|
+
function getDurableBackend() {
|
|
189
|
+
const memoized = initializedBackend !== undefined && isMemoizedBackendUsable(initializedBackend) ? initializedBackend : undefined;
|
|
190
|
+
const backend = injectedBackend ?? memoized ?? getReadyDbosBackendSync();
|
|
191
|
+
if (backend === undefined)
|
|
192
|
+
throw new DbosNotReadyError;
|
|
193
|
+
return backend;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// dist/builtin/workflows/src/shared/pending-stage-delivery.ts
|
|
197
|
+
var PENDING_STAGE_MESSAGE_LIMIT = 50;
|
|
198
|
+
var PENDING_STAGE_UNDELIVERABLE_NOTIFICATION_PREFIX = "atomic-pending-stage-undeliverable";
|
|
199
|
+
function queueStageMessage(messages, input, senderGroup, runGroup, stageIdentity) {
|
|
200
|
+
if (normalizeDeliveryGroup(senderGroup) !== normalizeDeliveryGroup(runGroup)) {
|
|
201
|
+
return { ok: false, reason: "group_mismatch", runId: input.runId, stageKey: input.stageKey };
|
|
202
|
+
}
|
|
203
|
+
const messageId = input.message.id;
|
|
204
|
+
const queued = pendingStageMessagesFor(messages, input.runId, input.stageKey, stageIdentity);
|
|
205
|
+
const existing = messages.find((entry2) => entry2.runId === input.runId && entry2.id === messageId);
|
|
206
|
+
if (existing !== undefined) {
|
|
207
|
+
if (pendingStageMessageSignature(existing, stageIdentity) !== pendingStageMessageSignature(input, stageIdentity)) {
|
|
208
|
+
return {
|
|
209
|
+
ok: false,
|
|
210
|
+
reason: "message_id_conflict",
|
|
211
|
+
runId: input.runId,
|
|
212
|
+
stageKey: input.stageKey,
|
|
213
|
+
messageId
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const queuedPosition = queued.indexOf(existing);
|
|
217
|
+
return {
|
|
218
|
+
ok: true,
|
|
219
|
+
messages,
|
|
220
|
+
entry: existing,
|
|
221
|
+
...queuedPosition >= 0 ? { position: queuedPosition + 1 } : {},
|
|
222
|
+
deduplicated: true
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
if (queued.length >= PENDING_STAGE_MESSAGE_LIMIT) {
|
|
226
|
+
return {
|
|
227
|
+
ok: false,
|
|
228
|
+
reason: "capacity",
|
|
229
|
+
limit: PENDING_STAGE_MESSAGE_LIMIT,
|
|
230
|
+
runId: input.runId,
|
|
231
|
+
stageKey: input.stageKey
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
const entry = {
|
|
235
|
+
...input,
|
|
236
|
+
id: messageId,
|
|
237
|
+
...stageIdentity !== undefined ? { stageId: stageIdentity.id } : {},
|
|
238
|
+
...stageIdentity?.replayKey !== undefined ? { stageReplayKey: stageIdentity.replayKey } : {},
|
|
239
|
+
admissionOrder: nextAdmissionOrder(messages, input.runId),
|
|
240
|
+
status: "queued"
|
|
241
|
+
};
|
|
242
|
+
return {
|
|
243
|
+
ok: true,
|
|
244
|
+
messages: [...messages, entry],
|
|
245
|
+
entry,
|
|
246
|
+
position: queued.length + 1,
|
|
247
|
+
deduplicated: false
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function pendingStageMessagesFor(messages, runId, stageKey, stageIdentity) {
|
|
251
|
+
return messages.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);
|
|
252
|
+
}
|
|
253
|
+
function markPendingStageMessageDelivered(messages, runId, stageKey, messageId, deliveredAt, stageIdentity) {
|
|
254
|
+
return updateQueuedPendingStageMessage(messages, runId, stageKey, messageId, stageIdentity, (entry) => ({
|
|
255
|
+
...entry,
|
|
256
|
+
status: "delivered",
|
|
257
|
+
deliveredAt
|
|
258
|
+
}));
|
|
259
|
+
}
|
|
260
|
+
function markPendingStageMessageUndeliverable(messages, runId, stageKey, messageId, reason, stageIdentity) {
|
|
261
|
+
return updateQueuedPendingStageMessage(messages, runId, stageKey, messageId, stageIdentity, (entry) => ({
|
|
262
|
+
...entry,
|
|
263
|
+
status: "undeliverable",
|
|
264
|
+
undeliverableReason: reason,
|
|
265
|
+
undeliverableNotificationId: pendingStageUndeliverableNotificationId(entry)
|
|
266
|
+
}));
|
|
267
|
+
}
|
|
268
|
+
function markPendingStageMessageUndeliverableNotified(messages, runId, stageKey, messageId, notificationId, notifiedAt) {
|
|
269
|
+
const index = messages.findIndex((entry) => matchesPendingStage(entry, runId, stageKey) && entry.id === messageId && entry.status === "undeliverable" && entry.undeliverableNotificationId === notificationId && entry.undeliverableNotifiedAt === undefined);
|
|
270
|
+
if (index < 0)
|
|
271
|
+
return messages;
|
|
272
|
+
const next = [...messages];
|
|
273
|
+
next[index] = { ...next[index], undeliverableNotifiedAt: notifiedAt };
|
|
274
|
+
return next;
|
|
275
|
+
}
|
|
276
|
+
function pendingStageUndeliverableNotificationId(entry) {
|
|
277
|
+
return [
|
|
278
|
+
PENDING_STAGE_UNDELIVERABLE_NOTIFICATION_PREFIX,
|
|
279
|
+
encodeURIComponent(entry.runId),
|
|
280
|
+
encodeURIComponent(entry.stageKey),
|
|
281
|
+
encodeURIComponent(entry.id)
|
|
282
|
+
].join(":");
|
|
283
|
+
}
|
|
284
|
+
function updateQueuedPendingStageMessage(messages, runId, stageKey, messageId, stageIdentity, update) {
|
|
285
|
+
const index = messages.findIndex((entry) => matchesPendingStage(entry, runId, stageKey, stageIdentity) && entry.id === messageId && entry.status === "queued");
|
|
286
|
+
if (index < 0)
|
|
287
|
+
return messages;
|
|
288
|
+
const next = [...messages];
|
|
289
|
+
next[index] = update(next[index]);
|
|
290
|
+
return next;
|
|
291
|
+
}
|
|
292
|
+
function matchesPendingStage(entry, runId, stageKey, stageIdentity) {
|
|
293
|
+
if (entry.runId !== runId)
|
|
294
|
+
return false;
|
|
295
|
+
if (stageIdentity === undefined)
|
|
296
|
+
return entry.stageKey === stageKey;
|
|
297
|
+
return entry.stageId === stageIdentity.id || entry.stageReplayKey !== undefined && entry.stageReplayKey === stageIdentity.replayKey || entry.stageId === undefined && stageIdentity.aliases.includes(entry.stageKey);
|
|
298
|
+
}
|
|
299
|
+
function nextAdmissionOrder(messages, runId) {
|
|
300
|
+
let greatest = 0;
|
|
301
|
+
let legacyPosition = 0;
|
|
302
|
+
for (const entry of messages) {
|
|
303
|
+
if (entry.runId !== runId)
|
|
304
|
+
continue;
|
|
305
|
+
legacyPosition += 1;
|
|
306
|
+
greatest = Math.max(greatest, entry.admissionOrder ?? legacyPosition);
|
|
307
|
+
}
|
|
308
|
+
return greatest + 1;
|
|
309
|
+
}
|
|
310
|
+
function pendingStageMessageSignature(entry, stageIdentity) {
|
|
311
|
+
const storedTarget = "status" in entry ? entry.stageReplayKey ?? entry.stageId : undefined;
|
|
312
|
+
const { timestamp: transportTimestamp, ...logicalMessage } = entry.message;
|
|
313
|
+
return stableJson({
|
|
314
|
+
target: storedTarget ?? stageIdentity?.replayKey ?? stageIdentity?.id ?? entry.stageKey,
|
|
315
|
+
sender: entry.senderReturnAddress ?? entry.from.id,
|
|
316
|
+
message: {
|
|
317
|
+
...logicalMessage,
|
|
318
|
+
expectsReply: logicalMessage.expectsReply ?? false,
|
|
319
|
+
content: {
|
|
320
|
+
...logicalMessage.content,
|
|
321
|
+
attachments: logicalMessage.content.attachments ?? []
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
function stableJson(value) {
|
|
327
|
+
return JSON.stringify(sortJsonValue(value));
|
|
328
|
+
}
|
|
329
|
+
function sortJsonValue(value) {
|
|
330
|
+
if (Array.isArray(value))
|
|
331
|
+
return value.map(sortJsonValue);
|
|
332
|
+
if (typeof value !== "object" || value === null)
|
|
333
|
+
return value;
|
|
334
|
+
return Object.fromEntries(Object.entries(value).filter(([, nested]) => nested !== undefined).sort(([left], [right]) => left.localeCompare(right)).map(([key, nested]) => [key, sortJsonValue(nested)]));
|
|
335
|
+
}
|
|
336
|
+
function normalizeDeliveryGroup(value) {
|
|
337
|
+
if (typeof value !== "string")
|
|
338
|
+
return "default";
|
|
339
|
+
const trimmed = value.trim();
|
|
340
|
+
return trimmed.length > 0 ? trimmed : "default";
|
|
341
|
+
}
|
|
342
|
+
// dist/builtin/workflows/src/shared/session-scoped-singleton.ts
|
|
343
|
+
var SHARED_STATES_KEY = Symbol.for("atomic-workflows/session-scoped-singleton-pre-adoption@1");
|
|
344
|
+
function processBag() {
|
|
345
|
+
return globalThis;
|
|
346
|
+
}
|
|
347
|
+
function recordLocal(key, local) {
|
|
348
|
+
const bag = processBag();
|
|
349
|
+
let states = bag[SHARED_STATES_KEY];
|
|
350
|
+
if (states === undefined || states.version !== 1) {
|
|
351
|
+
states = { version: 1, byKey: new Map };
|
|
352
|
+
bag[SHARED_STATES_KEY] = states;
|
|
353
|
+
}
|
|
354
|
+
const existing = states.byKey.get(key);
|
|
355
|
+
if (existing !== undefined)
|
|
356
|
+
return existing;
|
|
357
|
+
const created = { local, instance: undefined, localClaimed: false };
|
|
358
|
+
states.byKey.set(key, created);
|
|
359
|
+
return created;
|
|
360
|
+
}
|
|
361
|
+
function createSessionScopedSingleton(key, createLocal) {
|
|
362
|
+
const local = createLocal();
|
|
363
|
+
const shared = recordLocal(key, local);
|
|
364
|
+
let instance = local;
|
|
365
|
+
const live = () => shared.instance ?? instance;
|
|
366
|
+
const current = () => live();
|
|
367
|
+
const adoptWithResult = (scope, options) => {
|
|
368
|
+
const current2 = live();
|
|
369
|
+
let targetCreated = false;
|
|
370
|
+
const target = sessionScopedExtensionState(scope, key, () => {
|
|
371
|
+
targetCreated = true;
|
|
372
|
+
if (shared.localClaimed)
|
|
373
|
+
return createLocal();
|
|
374
|
+
shared.localClaimed = true;
|
|
375
|
+
return shared.local;
|
|
376
|
+
});
|
|
377
|
+
const preservedCurrent = !targetCreated && target !== current2 && options?.preserveCurrentWhenTargetExists?.(current2, target) === true;
|
|
378
|
+
shared.instance = preservedCurrent ? current2 : target;
|
|
379
|
+
instance = shared.instance;
|
|
380
|
+
return { instance: shared.instance, preservedCurrent };
|
|
381
|
+
};
|
|
382
|
+
const adopt = (scope, options) => adoptWithResult(scope, options).instance;
|
|
383
|
+
const facade = new Proxy(local, {
|
|
384
|
+
get(_target, prop) {
|
|
385
|
+
const value = Reflect.get(live(), prop, live());
|
|
386
|
+
if (typeof value === "function") {
|
|
387
|
+
return value.bind(live());
|
|
388
|
+
}
|
|
389
|
+
return value;
|
|
390
|
+
},
|
|
391
|
+
has(_target, prop) {
|
|
392
|
+
return Reflect.has(live(), prop);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
return { facade, adopt, adoptWithResult, current };
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// dist/builtin/workflows/src/shared/flat-string.ts
|
|
399
|
+
function flattenTruncatedString(value) {
|
|
400
|
+
return value.split("").join("");
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// dist/builtin/workflows/src/shared/tool-payload-bounds.ts
|
|
404
|
+
var TOOL_PAYLOAD_MAX_KEYS = 2048;
|
|
405
|
+
var TOOL_PAYLOAD_VALUE_LIMIT = 16384;
|
|
406
|
+
var TOOL_PAYLOAD_TRUNCATION_MARKER = "… [truncated]";
|
|
407
|
+
var TOOL_PAYLOAD_CYCLE_PLACEHOLDER = "<cycle>";
|
|
408
|
+
var TOOL_PAYLOAD_UNREADABLE_PLACEHOLDER = "<unreadable>";
|
|
409
|
+
var TOOL_PAYLOAD_UNSERIALIZABLE_PLACEHOLDER = "<unserializable>";
|
|
410
|
+
var TOOL_PAYLOAD_TRUNCATION_KEY = "…";
|
|
411
|
+
var TOOL_PAYLOAD_MAX_DEPTH = 256;
|
|
412
|
+
function isOmittedJsonValue(value) {
|
|
413
|
+
return value === undefined || typeof value === "function" || typeof value === "symbol";
|
|
414
|
+
}
|
|
415
|
+
function isToolPayloadObject(value) {
|
|
416
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
417
|
+
}
|
|
418
|
+
function isToolPayloadArray(value) {
|
|
419
|
+
return Array.isArray(value);
|
|
420
|
+
}
|
|
421
|
+
function isToolPayloadObjectLike(value) {
|
|
422
|
+
return value !== null && typeof value === "object";
|
|
423
|
+
}
|
|
424
|
+
function isToolPayloadCallable(value) {
|
|
425
|
+
return typeof value === "function";
|
|
426
|
+
}
|
|
427
|
+
function readToolPayloadProperty(value, key) {
|
|
428
|
+
try {
|
|
429
|
+
const property = Reflect.get(value, key);
|
|
430
|
+
return { ok: true, value: property };
|
|
431
|
+
} catch {
|
|
432
|
+
return { ok: false };
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function safeProperty(value, key) {
|
|
436
|
+
const result = readToolPayloadProperty(value, key);
|
|
437
|
+
return result.ok ? result.value : TOOL_PAYLOAD_UNREADABLE_PLACEHOLDER;
|
|
438
|
+
}
|
|
439
|
+
function safeOwnKeys(value, consumeKey) {
|
|
440
|
+
let stopped = false;
|
|
441
|
+
function* enumerate() {
|
|
442
|
+
let keys;
|
|
443
|
+
try {
|
|
444
|
+
keys = Reflect.ownKeys(value);
|
|
445
|
+
} catch {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
for (const key of keys) {
|
|
449
|
+
if (!consumeKey()) {
|
|
450
|
+
stopped = true;
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (typeof key !== "string")
|
|
454
|
+
continue;
|
|
455
|
+
let descriptor;
|
|
456
|
+
try {
|
|
457
|
+
descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
458
|
+
} catch {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (descriptor?.enumerable === true)
|
|
462
|
+
yield key;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return { keys: enumerate(), stoppedByLimit: () => stopped };
|
|
466
|
+
}
|
|
467
|
+
function safeArrayLength(value) {
|
|
468
|
+
const result = readToolPayloadProperty(value, "length");
|
|
469
|
+
if (!result.ok || typeof result.value !== "number")
|
|
470
|
+
return 0;
|
|
471
|
+
return Number.isSafeInteger(result.value) && result.value > 0 ? result.value : 0;
|
|
472
|
+
}
|
|
473
|
+
function resolveJsonValue(value) {
|
|
474
|
+
if (!isToolPayloadObjectLike(value))
|
|
475
|
+
return value;
|
|
476
|
+
const toJson = readToolPayloadProperty(value, "toJSON");
|
|
477
|
+
if (!toJson.ok)
|
|
478
|
+
return TOOL_PAYLOAD_UNREADABLE_PLACEHOLDER;
|
|
479
|
+
if (!isToolPayloadCallable(toJson.value))
|
|
480
|
+
return value;
|
|
481
|
+
try {
|
|
482
|
+
return toJson.value.call(value);
|
|
483
|
+
} catch {
|
|
484
|
+
return TOOL_PAYLOAD_UNSERIALIZABLE_PLACEHOLDER;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
var NULL_COST = 4;
|
|
488
|
+
var NUMBER_COST = 8;
|
|
489
|
+
var BOOLEAN_COST = 5;
|
|
490
|
+
var CONTAINER_COST = 2;
|
|
491
|
+
var SEPARATOR_COST = 1;
|
|
492
|
+
function consumeKeyBudget(state) {
|
|
493
|
+
if (state.keysRemaining <= 0)
|
|
494
|
+
return false;
|
|
495
|
+
state.keysRemaining -= 1;
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
function addTruncationMarker(record) {
|
|
499
|
+
let key = TOOL_PAYLOAD_TRUNCATION_KEY;
|
|
500
|
+
let suffix = 1;
|
|
501
|
+
while (Object.hasOwn(record, key))
|
|
502
|
+
key = `${TOOL_PAYLOAD_TRUNCATION_KEY}${suffix++}`;
|
|
503
|
+
record[key] = TOOL_PAYLOAD_TRUNCATION_MARKER;
|
|
504
|
+
}
|
|
505
|
+
function cloneObjectLike(state, value) {
|
|
506
|
+
if (state.seen.has(value))
|
|
507
|
+
return TOOL_PAYLOAD_CYCLE_PLACEHOLDER;
|
|
508
|
+
if (state.depth >= TOOL_PAYLOAD_MAX_DEPTH)
|
|
509
|
+
return TOOL_PAYLOAD_TRUNCATION_MARKER;
|
|
510
|
+
state.seen.add(value);
|
|
511
|
+
state.depth += 1;
|
|
512
|
+
state.remaining -= CONTAINER_COST;
|
|
513
|
+
try {
|
|
514
|
+
if (isToolPayloadArray(value)) {
|
|
515
|
+
const items = [];
|
|
516
|
+
const length = safeArrayLength(value);
|
|
517
|
+
for (let index = 0;index < length; index++) {
|
|
518
|
+
if (state.remaining <= 0) {
|
|
519
|
+
items.push(TOOL_PAYLOAD_TRUNCATION_MARKER);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
state.remaining -= SEPARATOR_COST;
|
|
523
|
+
const item = safeProperty(value, index);
|
|
524
|
+
if (isOmittedJsonValue(item)) {
|
|
525
|
+
state.remaining -= NULL_COST;
|
|
526
|
+
items.push(null);
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
items.push(cloneValue(state, item));
|
|
530
|
+
}
|
|
531
|
+
return items;
|
|
532
|
+
}
|
|
533
|
+
const cloned = {};
|
|
534
|
+
const scan = safeOwnKeys(value, () => state.remaining > 0 && consumeKeyBudget(state));
|
|
535
|
+
for (const key of scan.keys) {
|
|
536
|
+
state.remaining -= key.length + SEPARATOR_COST;
|
|
537
|
+
const child = safeProperty(value, key);
|
|
538
|
+
if (isOmittedJsonValue(child))
|
|
539
|
+
continue;
|
|
540
|
+
cloned[key] = cloneValue(state, child);
|
|
541
|
+
}
|
|
542
|
+
if (scan.stoppedByLimit())
|
|
543
|
+
addTruncationMarker(cloned);
|
|
544
|
+
return cloned;
|
|
545
|
+
} finally {
|
|
546
|
+
state.depth -= 1;
|
|
547
|
+
state.seen.delete(value);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
function cloneValue(state, value) {
|
|
551
|
+
const resolved = resolveJsonValue(value);
|
|
552
|
+
if (resolved === null) {
|
|
553
|
+
state.remaining -= NULL_COST;
|
|
554
|
+
return null;
|
|
555
|
+
}
|
|
556
|
+
switch (typeof resolved) {
|
|
557
|
+
case "string":
|
|
558
|
+
return cloneString(state, resolved);
|
|
559
|
+
case "number":
|
|
560
|
+
state.remaining -= NUMBER_COST;
|
|
561
|
+
return Number.isFinite(resolved) ? resolved : null;
|
|
562
|
+
case "boolean":
|
|
563
|
+
state.remaining -= BOOLEAN_COST;
|
|
564
|
+
return resolved;
|
|
565
|
+
case "object":
|
|
566
|
+
return cloneObjectLike(state, resolved);
|
|
567
|
+
case "bigint":
|
|
568
|
+
state.remaining -= NUMBER_COST;
|
|
569
|
+
return resolved;
|
|
570
|
+
default:
|
|
571
|
+
state.remaining -= TOOL_PAYLOAD_UNSERIALIZABLE_PLACEHOLDER.length;
|
|
572
|
+
return TOOL_PAYLOAD_UNSERIALIZABLE_PLACEHOLDER;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
function boundedToolPayload(value, limit = TOOL_PAYLOAD_VALUE_LIMIT) {
|
|
576
|
+
return cloneValue({ remaining: Math.max(1, limit), depth: 0, keysRemaining: TOOL_PAYLOAD_MAX_KEYS, seen: new Set }, value);
|
|
577
|
+
}
|
|
578
|
+
function boundedToolPayloadRecord(value, limit = TOOL_PAYLOAD_VALUE_LIMIT) {
|
|
579
|
+
const record = {};
|
|
580
|
+
if (!isToolPayloadObject(value) && !isToolPayloadArray(value))
|
|
581
|
+
return record;
|
|
582
|
+
const state = {
|
|
583
|
+
remaining: Math.max(1, limit),
|
|
584
|
+
depth: 0,
|
|
585
|
+
keysRemaining: TOOL_PAYLOAD_MAX_KEYS,
|
|
586
|
+
seen: new Set([value])
|
|
587
|
+
};
|
|
588
|
+
const scan = safeOwnKeys(value, () => state.remaining > 0 && consumeKeyBudget(state));
|
|
589
|
+
for (const key of scan.keys) {
|
|
590
|
+
state.remaining -= key.length + SEPARATOR_COST;
|
|
591
|
+
const child = safeProperty(value, key);
|
|
592
|
+
if (isOmittedJsonValue(child))
|
|
593
|
+
continue;
|
|
594
|
+
record[key] = cloneValue(state, child);
|
|
595
|
+
}
|
|
596
|
+
if (scan.stoppedByLimit())
|
|
597
|
+
addTruncationMarker(record);
|
|
598
|
+
return record;
|
|
599
|
+
}
|
|
600
|
+
function cloneString(state, value) {
|
|
601
|
+
if (state.remaining <= 0)
|
|
602
|
+
return TOOL_PAYLOAD_TRUNCATION_MARKER;
|
|
603
|
+
if (value.length <= state.remaining) {
|
|
604
|
+
state.remaining -= value.length;
|
|
605
|
+
return value;
|
|
606
|
+
}
|
|
607
|
+
const keep = state.remaining;
|
|
608
|
+
state.remaining = 0;
|
|
609
|
+
return `${flattenTruncatedString(value.slice(0, keep))}${TOOL_PAYLOAD_TRUNCATION_MARKER}`;
|
|
610
|
+
}
|
|
611
|
+
function boundedToolText(value, limit = TOOL_PAYLOAD_VALUE_LIMIT) {
|
|
612
|
+
const cap = Math.max(TOOL_PAYLOAD_TRUNCATION_MARKER.length + 1, limit);
|
|
613
|
+
if (value.length <= cap)
|
|
614
|
+
return value;
|
|
615
|
+
const keep = Math.max(0, cap - TOOL_PAYLOAD_TRUNCATION_MARKER.length);
|
|
616
|
+
return `${flattenTruncatedString(value.slice(0, keep))}${TOOL_PAYLOAD_TRUNCATION_MARKER}`;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
// dist/builtin/workflows/src/shared/graph-store-snapshot.ts
|
|
620
|
+
var COMPACT_RESULT_FIELD_LIMIT = 1024;
|
|
621
|
+
var COMPACT_EXIT_OUTPUT_LIMIT = COMPACT_RESULT_FIELD_LIMIT * 4;
|
|
622
|
+
function compactResultField(value) {
|
|
623
|
+
if (typeof value !== "string")
|
|
624
|
+
return;
|
|
625
|
+
if (value.length <= COMPACT_RESULT_FIELD_LIMIT)
|
|
626
|
+
return value;
|
|
627
|
+
return flattenTruncatedString(value.slice(0, COMPACT_RESULT_FIELD_LIMIT));
|
|
628
|
+
}
|
|
629
|
+
function compactRunResult(result, preserveExitedOutputs = false) {
|
|
630
|
+
if (result === undefined)
|
|
631
|
+
return;
|
|
632
|
+
const status = compactResultField(result.status);
|
|
633
|
+
const summary = compactResultField(result.summary);
|
|
634
|
+
const remainingWork = compactResultField(result.remaining_work);
|
|
635
|
+
const resultText = compactResultField(result.result);
|
|
636
|
+
const budgetDimension = status === "budget_exceeded" && (result.dimension === "duration" || result.dimension === "tokens" || result.dimension === "cost") ? result.dimension : undefined;
|
|
637
|
+
const compact = {
|
|
638
|
+
...status !== undefined ? { status } : {},
|
|
639
|
+
...summary !== undefined ? { summary } : {},
|
|
640
|
+
...remainingWork !== undefined ? { remaining_work: remainingWork } : {},
|
|
641
|
+
...resultText !== undefined ? { result: resultText } : {},
|
|
642
|
+
...budgetDimension !== undefined ? { dimension: budgetDimension } : {}
|
|
643
|
+
};
|
|
644
|
+
if (!preserveExitedOutputs)
|
|
645
|
+
return Object.keys(compact).length === 0 ? undefined : compact;
|
|
646
|
+
return compactExitedOutputs(result, compact);
|
|
647
|
+
}
|
|
648
|
+
function compactExitedOutputs(result, compact) {
|
|
649
|
+
try {
|
|
650
|
+
const serialized = JSON.stringify(result);
|
|
651
|
+
if (serialized !== undefined && serialized.length <= COMPACT_EXIT_OUTPUT_LIMIT) {
|
|
652
|
+
const parsed = JSON.parse(serialized);
|
|
653
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
654
|
+
return compactExitedObject(parsed);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
} catch {}
|
|
658
|
+
return Object.keys(compact).length === 0 ? undefined : compact;
|
|
659
|
+
}
|
|
660
|
+
function compactExitedObject(result) {
|
|
661
|
+
const compacted = { ...result };
|
|
662
|
+
for (const key of ["status", "summary", "remaining_work", "result"]) {
|
|
663
|
+
const value = compacted[key];
|
|
664
|
+
if (typeof value === "string")
|
|
665
|
+
compacted[key] = compactResultField(value) ?? "";
|
|
666
|
+
}
|
|
667
|
+
return Object.keys(compacted).length === 0 ? undefined : compacted;
|
|
668
|
+
}
|
|
669
|
+
function clonePrompt(prompt) {
|
|
670
|
+
return {
|
|
671
|
+
...prompt,
|
|
672
|
+
...prompt.choices !== undefined ? { choices: [...prompt.choices] } : {}
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
function cloneInputRequest(request) {
|
|
676
|
+
return {
|
|
677
|
+
...request,
|
|
678
|
+
questions: request.questions.map((question) => ({
|
|
679
|
+
...question,
|
|
680
|
+
options: question.options.map((option) => ({ ...option }))
|
|
681
|
+
}))
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
function compactToolEvents(events) {
|
|
685
|
+
const event = events.at(-1);
|
|
686
|
+
return event === undefined ? [] : [{ name: event.name }];
|
|
687
|
+
}
|
|
688
|
+
function compactWorkflowChild(child) {
|
|
689
|
+
return {
|
|
690
|
+
...child,
|
|
691
|
+
outputs: {},
|
|
692
|
+
outputCount: child.outputCount ?? Object.keys(child.outputs).length
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function compactStage(stage) {
|
|
696
|
+
const {
|
|
697
|
+
toolEvents,
|
|
698
|
+
workflowChild,
|
|
699
|
+
workflowChildRun,
|
|
700
|
+
pendingPrompt,
|
|
701
|
+
promptFootprint,
|
|
702
|
+
inputRequest,
|
|
703
|
+
notices,
|
|
704
|
+
mcpScope: _mcpScope,
|
|
705
|
+
pendingStageDeliveryAvailable: _pendingStageDeliveryAvailable,
|
|
706
|
+
attemptedModels: _attemptedModels,
|
|
707
|
+
modelAttempts: _modelAttempts,
|
|
708
|
+
result: _result,
|
|
709
|
+
...metadata
|
|
710
|
+
} = stage;
|
|
711
|
+
return {
|
|
712
|
+
...metadata,
|
|
713
|
+
parentIds: [...stage.parentIds],
|
|
714
|
+
toolEvents: compactToolEvents(toolEvents),
|
|
715
|
+
...workflowChild !== undefined ? { workflowChild: compactWorkflowChild(workflowChild) } : {},
|
|
716
|
+
...workflowChildRun !== undefined ? { workflowChildRun: { ...workflowChildRun } } : {},
|
|
717
|
+
...pendingPrompt !== undefined ? { pendingPrompt: clonePrompt(pendingPrompt) } : {},
|
|
718
|
+
...promptFootprint !== undefined ? { promptFootprint: clonePrompt(promptFootprint) } : {},
|
|
719
|
+
...inputRequest !== undefined ? { inputRequest: cloneInputRequest(inputRequest) } : {},
|
|
720
|
+
...notices !== undefined ? { notices: notices.map((notice) => ({ ...notice })) } : {}
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
function compactToolNode(node) {
|
|
724
|
+
return {
|
|
725
|
+
...node,
|
|
726
|
+
parentIds: [...node.parentIds],
|
|
727
|
+
...node.args !== undefined ? { args: boundedToolPayloadRecord(node.args) } : {},
|
|
728
|
+
...node.result !== undefined ? { result: boundedToolPayload(node.result) } : {},
|
|
729
|
+
...node.source !== undefined ? { source: boundedToolText(node.source) } : {}
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
function compactRun(run) {
|
|
733
|
+
const { inputs: _inputs, result: sourceResult, stages, toolNodes, pendingPrompt, ...metadata } = run;
|
|
734
|
+
const result = compactRunResult(sourceResult, run.exited === true && run.status === "failed");
|
|
735
|
+
return {
|
|
736
|
+
...metadata,
|
|
737
|
+
inputs: {},
|
|
738
|
+
stages: stages.map(compactStage),
|
|
739
|
+
...toolNodes !== undefined ? { toolNodes: toolNodes.map(compactToolNode) } : {},
|
|
740
|
+
...pendingPrompt !== undefined ? { pendingPrompt: clonePrompt(pendingPrompt) } : {},
|
|
741
|
+
...result !== undefined ? { result } : {}
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
function createGraphStoreSnapshot(runs, notices, version) {
|
|
745
|
+
const snapshot = {
|
|
746
|
+
runs: runs.map(compactRun),
|
|
747
|
+
notices: notices.map((notice) => ({ ...notice })),
|
|
748
|
+
version
|
|
749
|
+
};
|
|
750
|
+
deepFreezeGraphValue(snapshot);
|
|
751
|
+
return snapshot;
|
|
752
|
+
}
|
|
753
|
+
function deepFreezeGraphValue(value) {
|
|
754
|
+
if (value === null || typeof value !== "object" || Object.isFrozen(value))
|
|
755
|
+
return;
|
|
756
|
+
Object.freeze(value);
|
|
757
|
+
if (Array.isArray(value)) {
|
|
758
|
+
for (const item of value)
|
|
759
|
+
deepFreezeGraphValue(item);
|
|
760
|
+
return;
|
|
761
|
+
}
|
|
762
|
+
for (const key of Object.keys(value)) {
|
|
763
|
+
deepFreezeGraphValue(value[key]);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// dist/builtin/workflows/src/shared/store-internal.ts
|
|
768
|
+
var TERMINAL_STATUSES = new Set([
|
|
769
|
+
"completed",
|
|
770
|
+
"failed",
|
|
771
|
+
"killed",
|
|
772
|
+
"skipped",
|
|
773
|
+
"cancelled",
|
|
774
|
+
"blocked"
|
|
775
|
+
]);
|
|
776
|
+
function isTerminalStageStatus(status) {
|
|
777
|
+
return status === "completed" || status === "failed" || status === "skipped";
|
|
778
|
+
}
|
|
779
|
+
function cannotAwaitInput(status) {
|
|
780
|
+
return isTerminalStageStatus(status) || status === "paused" || status === "blocked";
|
|
781
|
+
}
|
|
782
|
+
function cannotBlock(status) {
|
|
783
|
+
return isTerminalStageStatus(status) || status === "paused";
|
|
784
|
+
}
|
|
785
|
+
function cannotPause(status) {
|
|
786
|
+
return isTerminalStageStatus(status) || status === "paused" || status === "blocked";
|
|
787
|
+
}
|
|
788
|
+
function clearRunFailureMetadata(run) {
|
|
789
|
+
delete run.error;
|
|
790
|
+
delete run.failureKind;
|
|
791
|
+
delete run.failureCode;
|
|
792
|
+
delete run.failureRecoverability;
|
|
793
|
+
delete run.failureDisposition;
|
|
794
|
+
delete run.failureMessage;
|
|
795
|
+
delete run.failedStageId;
|
|
796
|
+
delete run.failedToolNodeId;
|
|
797
|
+
delete run.resumable;
|
|
798
|
+
delete run.retryAfterMs;
|
|
799
|
+
delete run.blockedAt;
|
|
800
|
+
delete run.exited;
|
|
801
|
+
delete run.exitReason;
|
|
802
|
+
}
|
|
803
|
+
function clearStaleBlockedRunMetadata(run, metadata) {
|
|
804
|
+
if (metadata?.failureKind === undefined)
|
|
805
|
+
delete run.failureKind;
|
|
806
|
+
if (metadata?.failureCode === undefined)
|
|
807
|
+
delete run.failureCode;
|
|
808
|
+
if (metadata?.failureRecoverability === undefined)
|
|
809
|
+
delete run.failureRecoverability;
|
|
810
|
+
if (metadata?.failureDisposition === undefined)
|
|
811
|
+
delete run.failureDisposition;
|
|
812
|
+
if (metadata?.failureMessage === undefined)
|
|
813
|
+
delete run.failureMessage;
|
|
814
|
+
if (metadata?.failedStageId === undefined)
|
|
815
|
+
delete run.failedStageId;
|
|
816
|
+
if (metadata?.failedToolNodeId === undefined)
|
|
817
|
+
delete run.failedToolNodeId;
|
|
818
|
+
if (metadata?.resumable === undefined)
|
|
819
|
+
delete run.resumable;
|
|
820
|
+
if (metadata?.retryAfterMs === undefined)
|
|
821
|
+
delete run.retryAfterMs;
|
|
822
|
+
if (metadata?.exited === undefined)
|
|
823
|
+
delete run.exited;
|
|
824
|
+
if (metadata?.exitReason === undefined)
|
|
825
|
+
delete run.exitReason;
|
|
826
|
+
}
|
|
827
|
+
function applyRunEndMetadata(run, metadata) {
|
|
828
|
+
if (metadata.failureKind !== undefined)
|
|
829
|
+
run.failureKind = metadata.failureKind;
|
|
830
|
+
if (metadata.failureCode !== undefined)
|
|
831
|
+
run.failureCode = metadata.failureCode;
|
|
832
|
+
if (metadata.failureRecoverability !== undefined)
|
|
833
|
+
run.failureRecoverability = metadata.failureRecoverability;
|
|
834
|
+
if (metadata.failureDisposition !== undefined)
|
|
835
|
+
run.failureDisposition = metadata.failureDisposition;
|
|
836
|
+
if (metadata.retryAfterMs !== undefined)
|
|
837
|
+
run.retryAfterMs = metadata.retryAfterMs;
|
|
838
|
+
if (metadata.failureMessage !== undefined)
|
|
839
|
+
run.failureMessage = metadata.failureMessage;
|
|
840
|
+
if (metadata.failedStageId !== undefined)
|
|
841
|
+
run.failedStageId = metadata.failedStageId;
|
|
842
|
+
if (metadata.failedToolNodeId !== undefined)
|
|
843
|
+
run.failedToolNodeId = metadata.failedToolNodeId;
|
|
844
|
+
if (metadata.resumable !== undefined)
|
|
845
|
+
run.resumable = metadata.resumable;
|
|
846
|
+
if (metadata.exited !== undefined)
|
|
847
|
+
run.exited = metadata.exited;
|
|
848
|
+
if (metadata.exitReason !== undefined)
|
|
849
|
+
run.exitReason = metadata.exitReason;
|
|
850
|
+
}
|
|
851
|
+
function createStoreState() {
|
|
852
|
+
return {
|
|
853
|
+
runs: [],
|
|
854
|
+
notices: [],
|
|
855
|
+
listeners: new Set,
|
|
856
|
+
invalidationListeners: new Set,
|
|
857
|
+
resolvers: new Map,
|
|
858
|
+
stagePromptAnswers: new Map,
|
|
859
|
+
stagePromptDrafts: new Map,
|
|
860
|
+
version: 0
|
|
861
|
+
};
|
|
862
|
+
}
|
|
863
|
+
function createStoreContext(state = createStoreState()) {
|
|
864
|
+
let cachedGraphVersion = -1;
|
|
865
|
+
let cachedGraphSnapshot;
|
|
866
|
+
function snapshot() {
|
|
867
|
+
return JSON.parse(JSON.stringify({ runs: state.runs, notices: state.notices, version: state.version }));
|
|
868
|
+
}
|
|
869
|
+
function graphSnapshot() {
|
|
870
|
+
if (cachedGraphSnapshot === undefined || cachedGraphVersion !== state.version) {
|
|
871
|
+
cachedGraphSnapshot = createGraphStoreSnapshot(state.runs, state.notices, state.version);
|
|
872
|
+
cachedGraphVersion = state.version;
|
|
873
|
+
}
|
|
874
|
+
return cachedGraphSnapshot;
|
|
875
|
+
}
|
|
876
|
+
function notify() {
|
|
877
|
+
for (const fn of state.invalidationListeners) {
|
|
878
|
+
try {
|
|
879
|
+
fn();
|
|
880
|
+
} catch {}
|
|
881
|
+
}
|
|
882
|
+
if (state.listeners.size > 0) {
|
|
883
|
+
const snap = snapshot();
|
|
884
|
+
for (const fn of state.listeners) {
|
|
885
|
+
try {
|
|
886
|
+
fn(snap);
|
|
887
|
+
} catch {}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
function bumpAndNotify() {
|
|
892
|
+
state.version++;
|
|
893
|
+
notify();
|
|
894
|
+
}
|
|
895
|
+
function findRun(runId) {
|
|
896
|
+
return state.runs.find((r) => r.id === runId);
|
|
897
|
+
}
|
|
898
|
+
function findStage(run, stageId) {
|
|
899
|
+
return run.stages.find((s) => s.id === stageId);
|
|
900
|
+
}
|
|
901
|
+
function rejectPrompt(promptId, reason) {
|
|
902
|
+
const entry = state.resolvers.get(promptId);
|
|
903
|
+
if (!entry)
|
|
904
|
+
return;
|
|
905
|
+
state.resolvers.delete(promptId);
|
|
906
|
+
entry.reject(new Error(reason));
|
|
907
|
+
}
|
|
908
|
+
function stagePromptAnswerKey(runId, stageId) {
|
|
909
|
+
return JSON.stringify([runId, stageId]);
|
|
910
|
+
}
|
|
911
|
+
function stagePromptDraftKey(runId, stageId, promptId) {
|
|
912
|
+
return JSON.stringify([runId, stageId, promptId]);
|
|
913
|
+
}
|
|
914
|
+
function stageHasActiveTextPrompt(runId, stageId, promptId) {
|
|
915
|
+
const run = findRun(runId);
|
|
916
|
+
if (!run || TERMINAL_STATUSES.has(run.status))
|
|
917
|
+
return;
|
|
918
|
+
const stage = findStage(run, stageId);
|
|
919
|
+
if (!stage || isTerminalStageStatus(stage.status))
|
|
920
|
+
return;
|
|
921
|
+
const prompt = stage.pendingPrompt;
|
|
922
|
+
if (!prompt || prompt.id !== promptId)
|
|
923
|
+
return;
|
|
924
|
+
if (prompt.kind !== "input" && prompt.kind !== "editor")
|
|
925
|
+
return;
|
|
926
|
+
return { prompt };
|
|
927
|
+
}
|
|
928
|
+
function rejectStagePrompt(runId, stage, reason) {
|
|
929
|
+
const prompt = stage.pendingPrompt;
|
|
930
|
+
if (!prompt)
|
|
931
|
+
return;
|
|
932
|
+
stage.pendingPrompt = undefined;
|
|
933
|
+
state.stagePromptDrafts.delete(stagePromptDraftKey(runId, stage.id, prompt.id));
|
|
934
|
+
rejectPrompt(prompt.id, reason);
|
|
935
|
+
}
|
|
936
|
+
function rejectAllStagePrompts(runId, run, reason) {
|
|
937
|
+
for (const stage of run.stages) {
|
|
938
|
+
rejectStagePrompt(runId, stage, reason);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
state,
|
|
943
|
+
snapshot,
|
|
944
|
+
graphSnapshot,
|
|
945
|
+
notify,
|
|
946
|
+
bumpAndNotify,
|
|
947
|
+
findRun,
|
|
948
|
+
findStage,
|
|
949
|
+
rejectPrompt,
|
|
950
|
+
rejectStagePrompt,
|
|
951
|
+
rejectAllStagePrompts,
|
|
952
|
+
stagePromptAnswerKey,
|
|
953
|
+
stagePromptDraftKey,
|
|
954
|
+
stageHasActiveTextPrompt
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// dist/builtin/workflows/src/shared/store-pending-stage-delivery-methods.ts
|
|
959
|
+
function createPendingStageDeliveryStoreMethods(context) {
|
|
960
|
+
const transitions = new Map;
|
|
961
|
+
const serialize = async (runId, transition) => {
|
|
962
|
+
const previous = transitions.get(runId) ?? Promise.resolve();
|
|
963
|
+
const result = previous.catch(() => {
|
|
964
|
+
return;
|
|
965
|
+
}).then(transition);
|
|
966
|
+
const settled = result.then(() => {
|
|
967
|
+
return;
|
|
968
|
+
}, () => {
|
|
969
|
+
return;
|
|
970
|
+
});
|
|
971
|
+
transitions.set(runId, settled);
|
|
972
|
+
settled.finally(() => {
|
|
973
|
+
if (transitions.get(runId) === settled)
|
|
974
|
+
transitions.delete(runId);
|
|
975
|
+
});
|
|
976
|
+
return await result;
|
|
977
|
+
};
|
|
978
|
+
return {
|
|
979
|
+
async queueStageMessage(input, senderGroup, runGroup, backend) {
|
|
980
|
+
return await serialize(input.runId, async () => {
|
|
981
|
+
const run = context.findRun(input.runId);
|
|
982
|
+
if (run === undefined)
|
|
983
|
+
return;
|
|
984
|
+
const stageIdentity = resolvePendingStageIdentity(run, input.stageKey);
|
|
985
|
+
const result = queueStageMessage(run.pendingStageMessages ?? [], input, senderGroup, runGroup, stageIdentity);
|
|
986
|
+
if (result.ok && !result.deduplicated) {
|
|
987
|
+
await persistTransition(backend, input.runId, result.messages);
|
|
988
|
+
run.pendingStageMessages = [...result.messages];
|
|
989
|
+
context.bumpAndNotify();
|
|
990
|
+
}
|
|
991
|
+
return result;
|
|
992
|
+
});
|
|
993
|
+
},
|
|
994
|
+
async validateLiveStageMessage(input) {
|
|
995
|
+
return await serialize(input.runId, async () => {
|
|
996
|
+
const run = context.findRun(input.runId);
|
|
997
|
+
if (run === undefined)
|
|
998
|
+
return;
|
|
999
|
+
const result = queueStageMessage(run.pendingStageMessages ?? [], input, undefined, undefined, resolvePendingStageIdentity(run, input.stageKey));
|
|
1000
|
+
if (!result.ok) {
|
|
1001
|
+
return result.reason === "message_id_conflict" ? { outcome: "message_id_conflict", messageId: result.messageId } : { outcome: "forward" };
|
|
1002
|
+
}
|
|
1003
|
+
if (!result.deduplicated)
|
|
1004
|
+
return { outcome: "forward" };
|
|
1005
|
+
if (result.entry.status === "delivered")
|
|
1006
|
+
return { outcome: "delivered" };
|
|
1007
|
+
if (result.entry.status === "undeliverable") {
|
|
1008
|
+
return { outcome: "undeliverable", reason: result.entry.undeliverableReason };
|
|
1009
|
+
}
|
|
1010
|
+
if (result.position === undefined) {
|
|
1011
|
+
throw new Error(`atomic-workflows: queued message ${input.message.id} has no active position`);
|
|
1012
|
+
}
|
|
1013
|
+
return { outcome: "queued", position: result.position };
|
|
1014
|
+
});
|
|
1015
|
+
},
|
|
1016
|
+
pendingStageMessagesFor(runId, stageKey) {
|
|
1017
|
+
const run = context.findRun(runId);
|
|
1018
|
+
return pendingStageMessagesFor(run?.pendingStageMessages ?? [], runId, stageKey, run === undefined ? undefined : resolvePendingStageIdentity(run, stageKey));
|
|
1019
|
+
},
|
|
1020
|
+
async markPendingStageMessageDelivered(runId, stageKey, messageId, deliveredAt, backend) {
|
|
1021
|
+
return await serialize(runId, async () => {
|
|
1022
|
+
const run = context.findRun(runId);
|
|
1023
|
+
if (run === undefined)
|
|
1024
|
+
return false;
|
|
1025
|
+
const current = run.pendingStageMessages ?? [];
|
|
1026
|
+
const next = markPendingStageMessageDelivered(current, runId, stageKey, messageId, deliveredAt, resolvePendingStageIdentity(run, stageKey));
|
|
1027
|
+
if (next === current)
|
|
1028
|
+
return false;
|
|
1029
|
+
await persistTransition(backend, runId, next);
|
|
1030
|
+
run.pendingStageMessages = [...next];
|
|
1031
|
+
context.bumpAndNotify();
|
|
1032
|
+
return true;
|
|
1033
|
+
});
|
|
1034
|
+
},
|
|
1035
|
+
async markPendingStageMessageUndeliverable(runId, stageKey, messageId, reason, backend) {
|
|
1036
|
+
return await serialize(runId, async () => {
|
|
1037
|
+
const run = context.findRun(runId);
|
|
1038
|
+
if (run === undefined)
|
|
1039
|
+
return false;
|
|
1040
|
+
const current = run.pendingStageMessages ?? [];
|
|
1041
|
+
const next = markPendingStageMessageUndeliverable(current, runId, stageKey, messageId, reason, resolvePendingStageIdentity(run, stageKey));
|
|
1042
|
+
if (next === current)
|
|
1043
|
+
return false;
|
|
1044
|
+
await persistTransition(backend, runId, next);
|
|
1045
|
+
run.pendingStageMessages = [...next];
|
|
1046
|
+
context.bumpAndNotify();
|
|
1047
|
+
return true;
|
|
1048
|
+
});
|
|
1049
|
+
},
|
|
1050
|
+
async markPendingStageMessageUndeliverableNotified(runId, stageKey, messageId, notificationId, notifiedAt, backend) {
|
|
1051
|
+
return await serialize(runId, async () => {
|
|
1052
|
+
const run = context.findRun(runId);
|
|
1053
|
+
if (run === undefined)
|
|
1054
|
+
return false;
|
|
1055
|
+
const current = run.pendingStageMessages ?? [];
|
|
1056
|
+
const next = markPendingStageMessageUndeliverableNotified(current, runId, stageKey, messageId, notificationId, notifiedAt);
|
|
1057
|
+
if (next === current)
|
|
1058
|
+
return false;
|
|
1059
|
+
await persistTransition(backend, runId, next);
|
|
1060
|
+
run.pendingStageMessages = [...next];
|
|
1061
|
+
context.bumpAndNotify();
|
|
1062
|
+
return true;
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
function resolvePendingStageIdentity(run, stageKey) {
|
|
1068
|
+
const exactIds = run.stages.filter((stage2) => stage2.id === stageKey);
|
|
1069
|
+
const candidates = exactIds.length > 0 ? exactIds : run.stages.filter((stage2) => stage2.name === stageKey);
|
|
1070
|
+
if (candidates.length !== 1)
|
|
1071
|
+
return;
|
|
1072
|
+
const stage = candidates[0];
|
|
1073
|
+
return {
|
|
1074
|
+
id: stage.id,
|
|
1075
|
+
...stage.replayKey !== undefined ? { replayKey: stage.replayKey } : {},
|
|
1076
|
+
aliases: stage.id === stage.name ? [stage.id] : [stage.id, stage.name]
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
async function persistTransition(backend, runId, messages) {
|
|
1080
|
+
if (!await backend.persistPendingStageMessages(runId, messages)) {
|
|
1081
|
+
throw new Error(`atomic-workflows: durable workflow ${runId} is unavailable for pending-stage persistence`);
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
// dist/builtin/workflows/src/shared/store-prompt-methods.ts
|
|
1086
|
+
function createPromptStoreMethods(context) {
|
|
1087
|
+
const { state } = context;
|
|
1088
|
+
return {
|
|
1089
|
+
recordPendingPrompt(runId, prompt) {
|
|
1090
|
+
const run = context.findRun(runId);
|
|
1091
|
+
if (!run)
|
|
1092
|
+
return false;
|
|
1093
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1094
|
+
return false;
|
|
1095
|
+
if (run.pendingPrompt !== undefined)
|
|
1096
|
+
return false;
|
|
1097
|
+
run.pendingPrompt = { ...prompt };
|
|
1098
|
+
context.bumpAndNotify();
|
|
1099
|
+
return true;
|
|
1100
|
+
},
|
|
1101
|
+
resolvePendingPrompt(runId, promptId, response) {
|
|
1102
|
+
const run = context.findRun(runId);
|
|
1103
|
+
if (!run)
|
|
1104
|
+
return false;
|
|
1105
|
+
const pending = run.pendingPrompt;
|
|
1106
|
+
if (!pending || pending.id !== promptId)
|
|
1107
|
+
return false;
|
|
1108
|
+
run.pendingPrompt = undefined;
|
|
1109
|
+
context.bumpAndNotify();
|
|
1110
|
+
const entry = state.resolvers.get(promptId);
|
|
1111
|
+
if (entry) {
|
|
1112
|
+
state.resolvers.delete(promptId);
|
|
1113
|
+
entry.resolve(response);
|
|
1114
|
+
}
|
|
1115
|
+
return true;
|
|
1116
|
+
},
|
|
1117
|
+
awaitPendingPrompt(runId, promptId) {
|
|
1118
|
+
return new Promise((resolve, reject) => {
|
|
1119
|
+
const run = context.findRun(runId);
|
|
1120
|
+
if (!run) {
|
|
1121
|
+
reject(new Error(`atomic-workflows: run "${runId}" not found`));
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
const pending = run.pendingPrompt;
|
|
1125
|
+
if (!pending || pending.id !== promptId) {
|
|
1126
|
+
reject(new Error(`atomic-workflows: pending prompt "${promptId}" not registered on run "${runId}"`));
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
state.resolvers.set(promptId, { promptId, resolve, reject });
|
|
1130
|
+
});
|
|
1131
|
+
},
|
|
1132
|
+
recordStagePendingPrompt(runId, stageId, prompt) {
|
|
1133
|
+
const run = context.findRun(runId);
|
|
1134
|
+
if (!run)
|
|
1135
|
+
return false;
|
|
1136
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1137
|
+
return false;
|
|
1138
|
+
const stage = context.findStage(run, stageId);
|
|
1139
|
+
if (!stage)
|
|
1140
|
+
return false;
|
|
1141
|
+
if (isTerminalStageStatus(stage.status))
|
|
1142
|
+
return false;
|
|
1143
|
+
if (stage.pendingPrompt !== undefined)
|
|
1144
|
+
return false;
|
|
1145
|
+
stage.pendingPrompt = { ...prompt };
|
|
1146
|
+
stage.promptFootprint = { ...prompt };
|
|
1147
|
+
stage.status = "awaiting_input";
|
|
1148
|
+
stage.awaitingInputSince = prompt.createdAt;
|
|
1149
|
+
context.bumpAndNotify();
|
|
1150
|
+
return true;
|
|
1151
|
+
},
|
|
1152
|
+
resolveStagePendingPrompt(runId, stageId, promptId, response, options = {}) {
|
|
1153
|
+
const run = context.findRun(runId);
|
|
1154
|
+
if (!run)
|
|
1155
|
+
return false;
|
|
1156
|
+
const stage = context.findStage(run, stageId);
|
|
1157
|
+
if (!stage)
|
|
1158
|
+
return false;
|
|
1159
|
+
const pending = stage.pendingPrompt;
|
|
1160
|
+
if (!pending || pending.id !== promptId)
|
|
1161
|
+
return false;
|
|
1162
|
+
state.stagePromptDrafts.delete(context.stagePromptDraftKey(runId, stageId, promptId));
|
|
1163
|
+
if (options.recordAnswer !== false) {
|
|
1164
|
+
state.stagePromptAnswers.set(context.stagePromptAnswerKey(runId, stageId), {
|
|
1165
|
+
runId,
|
|
1166
|
+
stageId,
|
|
1167
|
+
promptId,
|
|
1168
|
+
kind: pending.kind,
|
|
1169
|
+
value: response,
|
|
1170
|
+
answeredAt: Date.now(),
|
|
1171
|
+
...options.answerSource !== undefined ? { answerSource: options.answerSource } : {}
|
|
1172
|
+
});
|
|
1173
|
+
stage.promptAnswerState = "available";
|
|
1174
|
+
} else {
|
|
1175
|
+
state.stagePromptAnswers.delete(context.stagePromptAnswerKey(runId, stageId));
|
|
1176
|
+
delete stage.promptAnswerState;
|
|
1177
|
+
}
|
|
1178
|
+
stage.pendingPrompt = undefined;
|
|
1179
|
+
if (stage.status === "awaiting_input") {
|
|
1180
|
+
stage.status = "running";
|
|
1181
|
+
delete stage.awaitingInputSince;
|
|
1182
|
+
}
|
|
1183
|
+
context.bumpAndNotify();
|
|
1184
|
+
const entry = state.resolvers.get(promptId);
|
|
1185
|
+
if (entry) {
|
|
1186
|
+
state.resolvers.delete(promptId);
|
|
1187
|
+
entry.resolve(response);
|
|
1188
|
+
}
|
|
1189
|
+
return true;
|
|
1190
|
+
},
|
|
1191
|
+
awaitStagePendingPrompt(runId, stageId, promptId) {
|
|
1192
|
+
return new Promise((resolve, reject) => {
|
|
1193
|
+
const run = context.findRun(runId);
|
|
1194
|
+
if (!run) {
|
|
1195
|
+
reject(new Error(`atomic-workflows: run "${runId}" not found`));
|
|
1196
|
+
return;
|
|
1197
|
+
}
|
|
1198
|
+
const stage = context.findStage(run, stageId);
|
|
1199
|
+
if (!stage) {
|
|
1200
|
+
reject(new Error(`atomic-workflows: stage "${stageId}" not found on run "${runId}"`));
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
const pending = stage.pendingPrompt;
|
|
1204
|
+
if (!pending || pending.id !== promptId) {
|
|
1205
|
+
reject(new Error(`atomic-workflows: pending prompt "${promptId}" not registered on stage "${stageId}" in run "${runId}"`));
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
state.resolvers.set(promptId, { promptId, resolve, reject });
|
|
1209
|
+
});
|
|
1210
|
+
},
|
|
1211
|
+
recordStagePromptAnswer(runId, stageId, prompt, response, options = {}) {
|
|
1212
|
+
const run = context.findRun(runId);
|
|
1213
|
+
if (!run)
|
|
1214
|
+
return false;
|
|
1215
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1216
|
+
return false;
|
|
1217
|
+
const stage = context.findStage(run, stageId);
|
|
1218
|
+
if (!stage)
|
|
1219
|
+
return false;
|
|
1220
|
+
if (isTerminalStageStatus(stage.status))
|
|
1221
|
+
return false;
|
|
1222
|
+
state.stagePromptAnswers.set(context.stagePromptAnswerKey(runId, stageId), {
|
|
1223
|
+
runId,
|
|
1224
|
+
stageId,
|
|
1225
|
+
promptId: prompt.id,
|
|
1226
|
+
kind: prompt.kind,
|
|
1227
|
+
value: response,
|
|
1228
|
+
answeredAt: Date.now(),
|
|
1229
|
+
...options.answerSource !== undefined ? { answerSource: options.answerSource } : {}
|
|
1230
|
+
});
|
|
1231
|
+
if (stage.promptFootprint === undefined)
|
|
1232
|
+
stage.promptFootprint = { ...prompt };
|
|
1233
|
+
stage.promptAnswerState = "available";
|
|
1234
|
+
if (stage.status === "awaiting_input") {
|
|
1235
|
+
stage.status = "running";
|
|
1236
|
+
delete stage.awaitingInputSince;
|
|
1237
|
+
}
|
|
1238
|
+
context.bumpAndNotify();
|
|
1239
|
+
return true;
|
|
1240
|
+
},
|
|
1241
|
+
recordStagePromptDraft(runId, stageId, promptId, text) {
|
|
1242
|
+
if (context.stageHasActiveTextPrompt(runId, stageId, promptId) === undefined)
|
|
1243
|
+
return false;
|
|
1244
|
+
state.stagePromptDrafts.set(context.stagePromptDraftKey(runId, stageId, promptId), text);
|
|
1245
|
+
return true;
|
|
1246
|
+
},
|
|
1247
|
+
getStagePromptDraft(runId, stageId, promptId) {
|
|
1248
|
+
if (context.stageHasActiveTextPrompt(runId, stageId, promptId) === undefined)
|
|
1249
|
+
return;
|
|
1250
|
+
return state.stagePromptDrafts.get(context.stagePromptDraftKey(runId, stageId, promptId));
|
|
1251
|
+
},
|
|
1252
|
+
clearStagePromptDraft(runId, stageId, promptId) {
|
|
1253
|
+
return state.stagePromptDrafts.delete(context.stagePromptDraftKey(runId, stageId, promptId));
|
|
1254
|
+
},
|
|
1255
|
+
getStagePromptAnswer(runId, stageId) {
|
|
1256
|
+
return state.stagePromptAnswers.get(context.stagePromptAnswerKey(runId, stageId));
|
|
1257
|
+
},
|
|
1258
|
+
clearStagePromptAnswer(runId, stageId) {
|
|
1259
|
+
const removed = state.stagePromptAnswers.delete(context.stagePromptAnswerKey(runId, stageId));
|
|
1260
|
+
const run = context.findRun(runId);
|
|
1261
|
+
const stage = run ? context.findStage(run, stageId) : undefined;
|
|
1262
|
+
const clearAvailabilityMarker = stage?.promptAnswerState === "available";
|
|
1263
|
+
if (clearAvailabilityMarker) {
|
|
1264
|
+
delete stage.promptAnswerState;
|
|
1265
|
+
}
|
|
1266
|
+
if (removed || clearAvailabilityMarker) {
|
|
1267
|
+
context.bumpAndNotify();
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
};
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// dist/builtin/workflows/src/shared/run-visibility.ts
|
|
1274
|
+
function isTopLevelWorkflowRun(run) {
|
|
1275
|
+
return run.parentRunId === undefined;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// dist/builtin/workflows/src/shared/timing.ts
|
|
1279
|
+
function nonNegative(ms) {
|
|
1280
|
+
return Math.max(0, ms);
|
|
1281
|
+
}
|
|
1282
|
+
function nextControlTimestamp(requestedAt, previousAt) {
|
|
1283
|
+
const candidate = requestedAt ?? Date.now();
|
|
1284
|
+
return previousAt === undefined || candidate > previousAt ? candidate : previousAt + 1;
|
|
1285
|
+
}
|
|
1286
|
+
function elapsedFromStart(startedAt, now, pausedDurationMs, pausedAt) {
|
|
1287
|
+
const completedPausedSegment = pausedDurationMs ?? 0;
|
|
1288
|
+
const activePausedSegment = pausedAt === undefined ? 0 : nonNegative(now - pausedAt);
|
|
1289
|
+
return nonNegative(now - startedAt - completedPausedSegment - activePausedSegment);
|
|
1290
|
+
}
|
|
1291
|
+
function accumulatePausedDurationMs(pausedDurationMs, pausedAt, resumedAt) {
|
|
1292
|
+
if (pausedAt === undefined)
|
|
1293
|
+
return pausedDurationMs ?? 0;
|
|
1294
|
+
return (pausedDurationMs ?? 0) + nonNegative(resumedAt - pausedAt);
|
|
1295
|
+
}
|
|
1296
|
+
function elapsedRunMs(run, now = Date.now()) {
|
|
1297
|
+
if (run.durationMs !== undefined)
|
|
1298
|
+
return nonNegative(run.durationMs);
|
|
1299
|
+
const effectiveNow = run.endedAt ?? now;
|
|
1300
|
+
return nonNegative(run.accumulatedDurationMs ?? 0) + elapsedFromStart(run.startedAt, effectiveNow, run.pausedDurationMs, run.pausedAt);
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// dist/builtin/workflows/src/shared/store-run-methods.ts
|
|
1304
|
+
function createRunStoreMethods(context) {
|
|
1305
|
+
const { state } = context;
|
|
1306
|
+
return {
|
|
1307
|
+
runs() {
|
|
1308
|
+
return state.runs;
|
|
1309
|
+
},
|
|
1310
|
+
notices() {
|
|
1311
|
+
return state.notices;
|
|
1312
|
+
},
|
|
1313
|
+
activeRunId() {
|
|
1314
|
+
for (let i = state.runs.length - 1;i >= 0; i--) {
|
|
1315
|
+
const run = state.runs[i];
|
|
1316
|
+
if (run && isTopLevelWorkflowRun(run) && run.endedAt === undefined) {
|
|
1317
|
+
return run.id;
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
for (let i = state.runs.length - 1;i >= 0; i--) {
|
|
1321
|
+
const run = state.runs[i];
|
|
1322
|
+
if (run && run.endedAt === undefined) {
|
|
1323
|
+
return run.id;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
return null;
|
|
1327
|
+
},
|
|
1328
|
+
recordRunStart(run) {
|
|
1329
|
+
state.runs.push(run);
|
|
1330
|
+
context.bumpAndNotify();
|
|
1331
|
+
},
|
|
1332
|
+
reconcileRunParentStage(runId, expectedParentStageId, parentStageId) {
|
|
1333
|
+
const run = context.findRun(runId);
|
|
1334
|
+
if (run?.parentStageId !== expectedParentStageId || parentStageId === expectedParentStageId)
|
|
1335
|
+
return false;
|
|
1336
|
+
run.parentStageId = parentStageId;
|
|
1337
|
+
context.bumpAndNotify();
|
|
1338
|
+
return true;
|
|
1339
|
+
},
|
|
1340
|
+
recordRunEnd(runId, status, result, error, metadata) {
|
|
1341
|
+
const run = context.findRun(runId);
|
|
1342
|
+
if (!run)
|
|
1343
|
+
return false;
|
|
1344
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1345
|
+
return false;
|
|
1346
|
+
run.status = status;
|
|
1347
|
+
run.endedAt = Date.now();
|
|
1348
|
+
if (run.pausedAt !== undefined) {
|
|
1349
|
+
run.pausedDurationMs = accumulatePausedDurationMs(run.pausedDurationMs, run.pausedAt, run.endedAt);
|
|
1350
|
+
run.pausedAt = undefined;
|
|
1351
|
+
}
|
|
1352
|
+
run.durationMs = elapsedRunMs(run, run.endedAt);
|
|
1353
|
+
if (result !== undefined && shouldStoreRunResult(status))
|
|
1354
|
+
run.result = result;
|
|
1355
|
+
const wasBlocked = run.blockedAt !== undefined || run.failureDisposition === "active_blocked";
|
|
1356
|
+
delete run.blockedAt;
|
|
1357
|
+
if (status === "completed" || status === "skipped" || status === "cancelled" || status === "blocked") {
|
|
1358
|
+
clearRunFailureMetadata(run);
|
|
1359
|
+
if (status === "blocked" && error !== undefined)
|
|
1360
|
+
run.error = error;
|
|
1361
|
+
if (metadata !== undefined)
|
|
1362
|
+
applyRunEndMetadata(run, metadata);
|
|
1363
|
+
} else {
|
|
1364
|
+
if (wasBlocked && error === undefined)
|
|
1365
|
+
delete run.error;
|
|
1366
|
+
if ((status === "failed" || status === "killed") && error !== undefined) {
|
|
1367
|
+
run.error = error;
|
|
1368
|
+
}
|
|
1369
|
+
if (wasBlocked)
|
|
1370
|
+
clearStaleBlockedRunMetadata(run, metadata);
|
|
1371
|
+
if (metadata !== undefined)
|
|
1372
|
+
applyRunEndMetadata(run, metadata);
|
|
1373
|
+
if (run.failureDisposition === "active_blocked")
|
|
1374
|
+
delete run.failureDisposition;
|
|
1375
|
+
if (status === "killed") {
|
|
1376
|
+
run.failureRecoverability = "non_recoverable";
|
|
1377
|
+
run.failureDisposition = "terminal_killed";
|
|
1378
|
+
run.resumable = false;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
const pending = run.pendingPrompt;
|
|
1382
|
+
if (pending) {
|
|
1383
|
+
run.pendingPrompt = undefined;
|
|
1384
|
+
context.rejectPrompt(pending.id, `atomic-workflows: run ${runId} ended before prompt resolved`);
|
|
1385
|
+
}
|
|
1386
|
+
context.rejectAllStagePrompts(runId, run, `atomic-workflows: run ${runId} ended before prompt resolved`);
|
|
1387
|
+
context.bumpAndNotify();
|
|
1388
|
+
return true;
|
|
1389
|
+
},
|
|
1390
|
+
recordRunBlocked(runId, error, metadata) {
|
|
1391
|
+
const run = context.findRun(runId);
|
|
1392
|
+
if (!run)
|
|
1393
|
+
return false;
|
|
1394
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1395
|
+
return false;
|
|
1396
|
+
run.status = "running";
|
|
1397
|
+
run.error = error;
|
|
1398
|
+
run.failureKind = metadata.failureKind;
|
|
1399
|
+
run.failureCode = metadata.failureCode;
|
|
1400
|
+
run.failureRecoverability = metadata.failureRecoverability;
|
|
1401
|
+
run.failureDisposition = metadata.failureDisposition;
|
|
1402
|
+
run.failureMessage = metadata.failureMessage;
|
|
1403
|
+
if (metadata.failedStageId === undefined)
|
|
1404
|
+
delete run.failedStageId;
|
|
1405
|
+
else
|
|
1406
|
+
run.failedStageId = metadata.failedStageId;
|
|
1407
|
+
run.resumable = metadata.resumable;
|
|
1408
|
+
run.blockedAt = metadata.blockedAt ?? Date.now();
|
|
1409
|
+
if (metadata.endedAt !== undefined) {
|
|
1410
|
+
run.endedAt = metadata.endedAt;
|
|
1411
|
+
run.durationMs = elapsedRunMs(run, metadata.endedAt);
|
|
1412
|
+
}
|
|
1413
|
+
if (metadata.retryAfterMs !== undefined)
|
|
1414
|
+
run.retryAfterMs = metadata.retryAfterMs;
|
|
1415
|
+
if (metadata.result !== undefined)
|
|
1416
|
+
run.result = metadata.result;
|
|
1417
|
+
if (metadata.budgetState !== undefined)
|
|
1418
|
+
run.budgetState = metadata.budgetState;
|
|
1419
|
+
context.bumpAndNotify();
|
|
1420
|
+
return true;
|
|
1421
|
+
},
|
|
1422
|
+
restoreActiveBlockedRun(source, error, metadata) {
|
|
1423
|
+
const restored = {
|
|
1424
|
+
...source,
|
|
1425
|
+
status: "running",
|
|
1426
|
+
error,
|
|
1427
|
+
resumable: metadata.resumable,
|
|
1428
|
+
failureRecoverability: metadata.failureRecoverability,
|
|
1429
|
+
failureDisposition: metadata.failureDisposition,
|
|
1430
|
+
blockedAt: metadata.blockedAt ?? Date.now(),
|
|
1431
|
+
stages: source.stages.map((stage) => ({ ...stage })),
|
|
1432
|
+
toolNodes: source.toolNodes?.map((node) => ({ ...node }))
|
|
1433
|
+
};
|
|
1434
|
+
delete restored.endedAt;
|
|
1435
|
+
delete restored.durationMs;
|
|
1436
|
+
restored.failureKind = metadata.failureKind;
|
|
1437
|
+
restored.failureCode = metadata.failureCode;
|
|
1438
|
+
restored.failureMessage = metadata.failureMessage;
|
|
1439
|
+
if (metadata.failedStageId === undefined)
|
|
1440
|
+
delete restored.failedStageId;
|
|
1441
|
+
else
|
|
1442
|
+
restored.failedStageId = metadata.failedStageId;
|
|
1443
|
+
if (metadata.retryAfterMs !== undefined)
|
|
1444
|
+
restored.retryAfterMs = metadata.retryAfterMs;
|
|
1445
|
+
if (metadata.result !== undefined)
|
|
1446
|
+
restored.result = metadata.result;
|
|
1447
|
+
if (metadata.budgetState !== undefined)
|
|
1448
|
+
restored.budgetState = metadata.budgetState;
|
|
1449
|
+
const index = state.runs.findIndex((candidate) => candidate.id === source.id);
|
|
1450
|
+
if (index < 0)
|
|
1451
|
+
state.runs.push(restored);
|
|
1452
|
+
else
|
|
1453
|
+
state.runs[index] = restored;
|
|
1454
|
+
context.bumpAndNotify();
|
|
1455
|
+
return true;
|
|
1456
|
+
},
|
|
1457
|
+
removeRun(runId) {
|
|
1458
|
+
const index = state.runs.findIndex((r) => r.id === runId);
|
|
1459
|
+
if (index < 0)
|
|
1460
|
+
return false;
|
|
1461
|
+
const run = state.runs[index];
|
|
1462
|
+
const pending = run.pendingPrompt;
|
|
1463
|
+
if (pending) {
|
|
1464
|
+
context.rejectPrompt(pending.id, `atomic-workflows: run ${runId} was removed before prompt resolved`);
|
|
1465
|
+
}
|
|
1466
|
+
context.rejectAllStagePrompts(runId, run, `atomic-workflows: run ${runId} was removed before prompt resolved`);
|
|
1467
|
+
for (const stage of run.stages) {
|
|
1468
|
+
state.stagePromptAnswers.delete(context.stagePromptAnswerKey(runId, stage.id));
|
|
1469
|
+
}
|
|
1470
|
+
state.runs.splice(index, 1);
|
|
1471
|
+
for (let i = state.notices.length - 1;i >= 0; i--) {
|
|
1472
|
+
if (state.notices[i]?.runId === runId)
|
|
1473
|
+
state.notices.splice(i, 1);
|
|
1474
|
+
}
|
|
1475
|
+
context.bumpAndNotify();
|
|
1476
|
+
return true;
|
|
1477
|
+
},
|
|
1478
|
+
recordNotice(notice) {
|
|
1479
|
+
state.notices.push(notice);
|
|
1480
|
+
context.bumpAndNotify();
|
|
1481
|
+
},
|
|
1482
|
+
ackNotice(id) {
|
|
1483
|
+
const notice = state.notices.find((n) => n.id === id);
|
|
1484
|
+
if (!notice || notice.ackedAt !== undefined)
|
|
1485
|
+
return false;
|
|
1486
|
+
notice.ackedAt = Date.now();
|
|
1487
|
+
context.bumpAndNotify();
|
|
1488
|
+
return true;
|
|
1489
|
+
},
|
|
1490
|
+
recordRunPaused(runId, pausedAt, metadata) {
|
|
1491
|
+
const run = context.findRun(runId);
|
|
1492
|
+
if (!run)
|
|
1493
|
+
return false;
|
|
1494
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1495
|
+
return false;
|
|
1496
|
+
const wasPaused = run.status === "paused";
|
|
1497
|
+
if (!wasPaused) {
|
|
1498
|
+
run.status = "paused";
|
|
1499
|
+
run.pausedAt = nextControlTimestamp(pausedAt, run.resumedAt);
|
|
1500
|
+
run.resumedAt = undefined;
|
|
1501
|
+
delete run.pauseActor;
|
|
1502
|
+
delete run.resumeActor;
|
|
1503
|
+
delete run.resumeSource;
|
|
1504
|
+
}
|
|
1505
|
+
if (metadata?.resumable !== undefined)
|
|
1506
|
+
run.resumable = metadata.resumable;
|
|
1507
|
+
if (metadata?.exitReason !== undefined)
|
|
1508
|
+
run.exitReason = metadata.exitReason;
|
|
1509
|
+
if (metadata?.exitReason === "quit" && run.quitAt === undefined)
|
|
1510
|
+
run.quitAt = nextControlTimestamp(undefined, run.pausedAt);
|
|
1511
|
+
if (metadata?.actor !== undefined)
|
|
1512
|
+
run.pauseActor = metadata.actor;
|
|
1513
|
+
if (wasPaused && metadata === undefined)
|
|
1514
|
+
return false;
|
|
1515
|
+
context.bumpAndNotify();
|
|
1516
|
+
return true;
|
|
1517
|
+
},
|
|
1518
|
+
recordRunResumed(runId, resumedAt, metadata) {
|
|
1519
|
+
const run = context.findRun(runId);
|
|
1520
|
+
if (!run)
|
|
1521
|
+
return false;
|
|
1522
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1523
|
+
return false;
|
|
1524
|
+
const claimsRunControl = metadata?.source === "run_control";
|
|
1525
|
+
if (run.status !== "paused") {
|
|
1526
|
+
if (!claimsRunControl || run.status !== "running" || run.resumedAt === undefined)
|
|
1527
|
+
return false;
|
|
1528
|
+
if (run.resumeSource === "run_control" && run.resumeActor === metadata?.actor)
|
|
1529
|
+
return false;
|
|
1530
|
+
run.resumeSource = "run_control";
|
|
1531
|
+
if (metadata?.actor === undefined)
|
|
1532
|
+
delete run.resumeActor;
|
|
1533
|
+
else
|
|
1534
|
+
run.resumeActor = metadata.actor;
|
|
1535
|
+
context.bumpAndNotify();
|
|
1536
|
+
return false;
|
|
1537
|
+
}
|
|
1538
|
+
const resumedTs = nextControlTimestamp(resumedAt, run.pausedAt);
|
|
1539
|
+
run.status = "running";
|
|
1540
|
+
run.pausedDurationMs = accumulatePausedDurationMs(run.pausedDurationMs, run.pausedAt, resumedTs);
|
|
1541
|
+
run.resumedAt = resumedTs;
|
|
1542
|
+
run.pausedAt = undefined;
|
|
1543
|
+
delete run.quitAt;
|
|
1544
|
+
delete run.exitReason;
|
|
1545
|
+
delete run.pauseActor;
|
|
1546
|
+
if (metadata === undefined) {
|
|
1547
|
+
delete run.resumeActor;
|
|
1548
|
+
delete run.resumeSource;
|
|
1549
|
+
} else {
|
|
1550
|
+
run.resumeSource = metadata.source;
|
|
1551
|
+
if (metadata.actor === undefined)
|
|
1552
|
+
delete run.resumeActor;
|
|
1553
|
+
else
|
|
1554
|
+
run.resumeActor = metadata.actor;
|
|
1555
|
+
}
|
|
1556
|
+
context.bumpAndNotify();
|
|
1557
|
+
return true;
|
|
1558
|
+
},
|
|
1559
|
+
clear() {
|
|
1560
|
+
if (state.runs.length === 0 && state.notices.length === 0 && state.resolvers.size === 0 && state.stagePromptAnswers.size === 0 && state.stagePromptDrafts.size === 0)
|
|
1561
|
+
return;
|
|
1562
|
+
state.runs.length = 0;
|
|
1563
|
+
state.notices.length = 0;
|
|
1564
|
+
for (const entry of state.resolvers.values()) {
|
|
1565
|
+
entry.reject(new Error("atomic-workflows: store cleared"));
|
|
1566
|
+
}
|
|
1567
|
+
state.resolvers.clear();
|
|
1568
|
+
state.stagePromptAnswers.clear();
|
|
1569
|
+
state.stagePromptDrafts.clear();
|
|
1570
|
+
context.bumpAndNotify();
|
|
1571
|
+
},
|
|
1572
|
+
snapshot() {
|
|
1573
|
+
return context.snapshot();
|
|
1574
|
+
},
|
|
1575
|
+
graphSnapshot() {
|
|
1576
|
+
return context.graphSnapshot();
|
|
1577
|
+
},
|
|
1578
|
+
subscribe(fn) {
|
|
1579
|
+
state.listeners.add(fn);
|
|
1580
|
+
return () => {
|
|
1581
|
+
state.listeners.delete(fn);
|
|
1582
|
+
};
|
|
1583
|
+
},
|
|
1584
|
+
subscribeInvalidation(fn) {
|
|
1585
|
+
state.invalidationListeners.add(fn);
|
|
1586
|
+
return () => state.invalidationListeners.delete(fn);
|
|
1587
|
+
}
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
function shouldStoreRunResult(status) {
|
|
1591
|
+
return status === "completed" || status === "skipped" || status === "cancelled" || status === "blocked" || status === "failed";
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
// dist/builtin/workflows/src/shared/store-tool-node-methods.ts
|
|
1595
|
+
function nextExecutionOrder(run) {
|
|
1596
|
+
const stageOrders = run.stages.map((stage) => stage.executionOrder ?? 0);
|
|
1597
|
+
const toolOrders = (run.toolNodes ?? []).map((node) => node.executionOrder ?? 0);
|
|
1598
|
+
return Math.max(0, ...stageOrders, ...toolOrders) + 1;
|
|
1599
|
+
}
|
|
1600
|
+
function createToolNodeStoreMethods(context) {
|
|
1601
|
+
return {
|
|
1602
|
+
recordToolNodeStart(runId, node) {
|
|
1603
|
+
const run = context.findRun(runId);
|
|
1604
|
+
if (run === undefined || TERMINAL_STATUSES.has(run.status))
|
|
1605
|
+
return false;
|
|
1606
|
+
const mutableRun = run;
|
|
1607
|
+
if (mutableRun.toolNodes === undefined)
|
|
1608
|
+
mutableRun.toolNodes = [];
|
|
1609
|
+
const nodes = mutableRun.toolNodes;
|
|
1610
|
+
if (nodes.some((candidate) => candidate.id === node.id))
|
|
1611
|
+
return false;
|
|
1612
|
+
if (node.executionOrder === undefined)
|
|
1613
|
+
node.executionOrder = nextExecutionOrder(run);
|
|
1614
|
+
nodes.push(node);
|
|
1615
|
+
context.bumpAndNotify();
|
|
1616
|
+
return true;
|
|
1617
|
+
},
|
|
1618
|
+
recordToolNodeRunning(runId, nodeId, startedAt) {
|
|
1619
|
+
const node = context.findRun(runId)?.toolNodes?.find((candidate) => candidate.id === nodeId);
|
|
1620
|
+
if (node === undefined || node.status !== "pending")
|
|
1621
|
+
return false;
|
|
1622
|
+
node.status = "running";
|
|
1623
|
+
node.startedAt = startedAt;
|
|
1624
|
+
context.bumpAndNotify();
|
|
1625
|
+
return true;
|
|
1626
|
+
},
|
|
1627
|
+
recordToolNodeEnd(runId, nodeId, update) {
|
|
1628
|
+
const node = context.findRun(runId)?.toolNodes?.find((candidate) => candidate.id === nodeId);
|
|
1629
|
+
if (node === undefined || node.status === "completed" || node.status === "failed" || node.status === "cached" || node.status === "cancelled")
|
|
1630
|
+
return false;
|
|
1631
|
+
node.status = update.status;
|
|
1632
|
+
if (update.endedAt !== undefined)
|
|
1633
|
+
node.endedAt = update.endedAt;
|
|
1634
|
+
if (update.durationMs !== undefined)
|
|
1635
|
+
node.durationMs = update.durationMs;
|
|
1636
|
+
if (update.result !== undefined)
|
|
1637
|
+
node.result = boundedToolPayload(update.result);
|
|
1638
|
+
if (update.resultSummary !== undefined)
|
|
1639
|
+
node.resultSummary = update.resultSummary;
|
|
1640
|
+
if (update.error !== undefined)
|
|
1641
|
+
node.error = update.error;
|
|
1642
|
+
context.bumpAndNotify();
|
|
1643
|
+
return true;
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// dist/builtin/workflows/src/shared/store-stage-methods.ts
|
|
1649
|
+
function createStageStoreMethods(context) {
|
|
1650
|
+
return {
|
|
1651
|
+
recordStageStart(runId, stage) {
|
|
1652
|
+
const run = context.findRun(runId);
|
|
1653
|
+
if (!run)
|
|
1654
|
+
return;
|
|
1655
|
+
if (stage.executionOrder === undefined)
|
|
1656
|
+
stage.executionOrder = nextExecutionOrder(run);
|
|
1657
|
+
if (!run.stages.some((s) => s.id === stage.id)) {
|
|
1658
|
+
run.stages.push(stage);
|
|
1659
|
+
}
|
|
1660
|
+
context.bumpAndNotify();
|
|
1661
|
+
},
|
|
1662
|
+
recordStageWorkflowChildRun(runId, stageId, ref) {
|
|
1663
|
+
const run = context.findRun(runId);
|
|
1664
|
+
if (!run)
|
|
1665
|
+
return false;
|
|
1666
|
+
const stage = context.findStage(run, stageId);
|
|
1667
|
+
if (!stage)
|
|
1668
|
+
return false;
|
|
1669
|
+
if (stage.workflowChildRun?.runId === ref.runId && stage.workflowChildRun.alias === ref.alias && stage.workflowChildRun.workflow === ref.workflow)
|
|
1670
|
+
return false;
|
|
1671
|
+
stage.workflowChildRun = { ...ref };
|
|
1672
|
+
context.bumpAndNotify();
|
|
1673
|
+
return true;
|
|
1674
|
+
},
|
|
1675
|
+
recordToolStart(runId, stageId, evt) {
|
|
1676
|
+
const run = context.findRun(runId);
|
|
1677
|
+
if (!run)
|
|
1678
|
+
return;
|
|
1679
|
+
const stage = context.findStage(run, stageId);
|
|
1680
|
+
if (!stage)
|
|
1681
|
+
return;
|
|
1682
|
+
const exists = stage.toolEvents.some((e) => e.name === evt.name && e.startedAt === evt.startedAt);
|
|
1683
|
+
if (!exists) {
|
|
1684
|
+
stage.toolEvents.push(evt);
|
|
1685
|
+
}
|
|
1686
|
+
context.bumpAndNotify();
|
|
1687
|
+
},
|
|
1688
|
+
recordToolEnd(runId, stageId, evt) {
|
|
1689
|
+
const run = context.findRun(runId);
|
|
1690
|
+
if (!run)
|
|
1691
|
+
return;
|
|
1692
|
+
const stage = context.findStage(run, stageId);
|
|
1693
|
+
if (!stage)
|
|
1694
|
+
return;
|
|
1695
|
+
const existing = stage.toolEvents.find((e) => e.name === evt.name && e.startedAt === evt.startedAt);
|
|
1696
|
+
if (existing) {
|
|
1697
|
+
existing.endedAt = evt.endedAt;
|
|
1698
|
+
existing.output = evt.output;
|
|
1699
|
+
}
|
|
1700
|
+
context.bumpAndNotify();
|
|
1701
|
+
},
|
|
1702
|
+
recordStageEnd(runId, stage) {
|
|
1703
|
+
const run = context.findRun(runId);
|
|
1704
|
+
if (!run)
|
|
1705
|
+
return;
|
|
1706
|
+
const existing = context.findStage(run, stage.id);
|
|
1707
|
+
if (!existing)
|
|
1708
|
+
return;
|
|
1709
|
+
existing.status = stage.status;
|
|
1710
|
+
existing.endedAt = stage.endedAt;
|
|
1711
|
+
if (existing.endedAt !== undefined && existing.pausedAt !== undefined) {
|
|
1712
|
+
existing.pausedDurationMs = accumulatePausedDurationMs(existing.pausedDurationMs, existing.pausedAt, existing.endedAt);
|
|
1713
|
+
existing.pausedAt = undefined;
|
|
1714
|
+
}
|
|
1715
|
+
existing.durationMs = stage.durationMs;
|
|
1716
|
+
existing.result = stage.result;
|
|
1717
|
+
existing.error = stage.error;
|
|
1718
|
+
if (stage.sessionId !== undefined)
|
|
1719
|
+
existing.sessionId = stage.sessionId;
|
|
1720
|
+
if (stage.sessionFile !== undefined)
|
|
1721
|
+
existing.sessionFile = stage.sessionFile;
|
|
1722
|
+
if (stage.modelAttempts !== undefined)
|
|
1723
|
+
existing.modelAttempts = stage.modelAttempts;
|
|
1724
|
+
existing.failureKind = stage.failureKind;
|
|
1725
|
+
existing.failureCode = stage.failureCode;
|
|
1726
|
+
existing.failureRecoverability = stage.failureRecoverability;
|
|
1727
|
+
existing.failureDisposition = stage.failureDisposition;
|
|
1728
|
+
existing.retryAfterMs = stage.retryAfterMs;
|
|
1729
|
+
existing.failureMessage = stage.failureMessage;
|
|
1730
|
+
existing.skippedReason = stage.skippedReason;
|
|
1731
|
+
if (stage.replayKey !== undefined)
|
|
1732
|
+
existing.replayKey = stage.replayKey;
|
|
1733
|
+
if (stage.promptAnswerState !== undefined)
|
|
1734
|
+
existing.promptAnswerState = stage.promptAnswerState;
|
|
1735
|
+
if (stage.replayedFromStageId !== undefined)
|
|
1736
|
+
existing.replayedFromStageId = stage.replayedFromStageId;
|
|
1737
|
+
if (stage.replayed !== undefined)
|
|
1738
|
+
existing.replayed = stage.replayed;
|
|
1739
|
+
if (stage.status === "completed") {
|
|
1740
|
+
if (stage.workflowChildRun !== undefined)
|
|
1741
|
+
existing.workflowChildRun = { ...stage.workflowChildRun };
|
|
1742
|
+
if (stage.workflowChild !== undefined)
|
|
1743
|
+
existing.workflowChild = structuredClone(stage.workflowChild);
|
|
1744
|
+
} else {
|
|
1745
|
+
delete existing.workflowChildRun;
|
|
1746
|
+
delete existing.workflowChild;
|
|
1747
|
+
}
|
|
1748
|
+
delete existing.awaitingInputSince;
|
|
1749
|
+
delete existing.inputRequest;
|
|
1750
|
+
context.rejectStagePrompt(runId, existing, `atomic-workflows: stage ${stage.id} ended before prompt resolved`);
|
|
1751
|
+
context.bumpAndNotify();
|
|
1752
|
+
},
|
|
1753
|
+
recordStageSession(runId, stageId, session) {
|
|
1754
|
+
const run = context.findRun(runId);
|
|
1755
|
+
if (!run)
|
|
1756
|
+
return false;
|
|
1757
|
+
const stage = context.findStage(run, stageId);
|
|
1758
|
+
if (!stage)
|
|
1759
|
+
return false;
|
|
1760
|
+
let changed = false;
|
|
1761
|
+
if (session.sessionId !== undefined && stage.sessionId !== session.sessionId) {
|
|
1762
|
+
stage.sessionId = session.sessionId;
|
|
1763
|
+
changed = true;
|
|
1764
|
+
}
|
|
1765
|
+
if (session.sessionFile !== undefined && stage.sessionFile !== session.sessionFile) {
|
|
1766
|
+
stage.sessionFile = session.sessionFile;
|
|
1767
|
+
changed = true;
|
|
1768
|
+
}
|
|
1769
|
+
if (!changed)
|
|
1770
|
+
return false;
|
|
1771
|
+
context.bumpAndNotify();
|
|
1772
|
+
return true;
|
|
1773
|
+
},
|
|
1774
|
+
recordStageAttachable(runId, stageId, attachable) {
|
|
1775
|
+
const run = context.findRun(runId);
|
|
1776
|
+
if (!run)
|
|
1777
|
+
return false;
|
|
1778
|
+
const stage = context.findStage(run, stageId);
|
|
1779
|
+
if (!stage)
|
|
1780
|
+
return false;
|
|
1781
|
+
const next = attachable === true ? true : undefined;
|
|
1782
|
+
if (stage.attachable === next)
|
|
1783
|
+
return false;
|
|
1784
|
+
if (next === undefined) {
|
|
1785
|
+
delete stage.attachable;
|
|
1786
|
+
} else {
|
|
1787
|
+
stage.attachable = next;
|
|
1788
|
+
}
|
|
1789
|
+
context.bumpAndNotify();
|
|
1790
|
+
return true;
|
|
1791
|
+
},
|
|
1792
|
+
recordStageAttached(runId, stageId, attached) {
|
|
1793
|
+
const run = context.findRun(runId);
|
|
1794
|
+
if (!run)
|
|
1795
|
+
return false;
|
|
1796
|
+
const stage = context.findStage(run, stageId);
|
|
1797
|
+
if (!stage)
|
|
1798
|
+
return false;
|
|
1799
|
+
const next = attached === true ? true : undefined;
|
|
1800
|
+
if (stage.attached === next)
|
|
1801
|
+
return false;
|
|
1802
|
+
if (next === undefined) {
|
|
1803
|
+
delete stage.attached;
|
|
1804
|
+
} else {
|
|
1805
|
+
stage.attached = next;
|
|
1806
|
+
}
|
|
1807
|
+
context.bumpAndNotify();
|
|
1808
|
+
return true;
|
|
1809
|
+
},
|
|
1810
|
+
recordStageAwaitingInput(runId, stageId, awaiting, ts) {
|
|
1811
|
+
const run = context.findRun(runId);
|
|
1812
|
+
if (!run)
|
|
1813
|
+
return false;
|
|
1814
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1815
|
+
return false;
|
|
1816
|
+
const stage = context.findStage(run, stageId);
|
|
1817
|
+
if (!stage)
|
|
1818
|
+
return false;
|
|
1819
|
+
if (cannotAwaitInput(stage.status))
|
|
1820
|
+
return false;
|
|
1821
|
+
if (awaiting) {
|
|
1822
|
+
if (stage.status === "awaiting_input")
|
|
1823
|
+
return false;
|
|
1824
|
+
stage.status = "awaiting_input";
|
|
1825
|
+
stage.awaitingInputSince = ts ?? Date.now();
|
|
1826
|
+
} else {
|
|
1827
|
+
if (stage.pendingPrompt !== undefined)
|
|
1828
|
+
return false;
|
|
1829
|
+
if (stage.status !== "awaiting_input")
|
|
1830
|
+
return false;
|
|
1831
|
+
stage.status = "running";
|
|
1832
|
+
delete stage.awaitingInputSince;
|
|
1833
|
+
}
|
|
1834
|
+
context.bumpAndNotify();
|
|
1835
|
+
return true;
|
|
1836
|
+
},
|
|
1837
|
+
recordStageInputRequest(runId, stageId, request) {
|
|
1838
|
+
const run = context.findRun(runId);
|
|
1839
|
+
if (!run)
|
|
1840
|
+
return false;
|
|
1841
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1842
|
+
return false;
|
|
1843
|
+
const stage = context.findStage(run, stageId);
|
|
1844
|
+
if (!stage)
|
|
1845
|
+
return false;
|
|
1846
|
+
if (isTerminalStageStatus(stage.status))
|
|
1847
|
+
return false;
|
|
1848
|
+
if (stage.inputRequest?.id === request.id)
|
|
1849
|
+
return false;
|
|
1850
|
+
stage.inputRequest = { ...request };
|
|
1851
|
+
context.bumpAndNotify();
|
|
1852
|
+
return true;
|
|
1853
|
+
},
|
|
1854
|
+
clearStageInputRequest(runId, stageId) {
|
|
1855
|
+
const run = context.findRun(runId);
|
|
1856
|
+
if (!run)
|
|
1857
|
+
return false;
|
|
1858
|
+
const stage = context.findStage(run, stageId);
|
|
1859
|
+
if (!stage || stage.inputRequest === undefined)
|
|
1860
|
+
return false;
|
|
1861
|
+
delete stage.inputRequest;
|
|
1862
|
+
context.bumpAndNotify();
|
|
1863
|
+
return true;
|
|
1864
|
+
},
|
|
1865
|
+
recordStageBlocked(runId, stageId, blockedBy) {
|
|
1866
|
+
const run = context.findRun(runId);
|
|
1867
|
+
if (!run)
|
|
1868
|
+
return false;
|
|
1869
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1870
|
+
return false;
|
|
1871
|
+
const stage = context.findStage(run, stageId);
|
|
1872
|
+
if (!stage)
|
|
1873
|
+
return false;
|
|
1874
|
+
if (cannotBlock(stage.status))
|
|
1875
|
+
return false;
|
|
1876
|
+
if (stage.status === "blocked") {
|
|
1877
|
+
if (stage.blockedByStageId === blockedBy)
|
|
1878
|
+
return false;
|
|
1879
|
+
stage.blockedByStageId = blockedBy;
|
|
1880
|
+
} else {
|
|
1881
|
+
stage.status = "blocked";
|
|
1882
|
+
stage.blockedByStageId = blockedBy;
|
|
1883
|
+
delete stage.awaitingInputSince;
|
|
1884
|
+
}
|
|
1885
|
+
context.bumpAndNotify();
|
|
1886
|
+
return true;
|
|
1887
|
+
},
|
|
1888
|
+
recordStageUnblocked(runId, stageId) {
|
|
1889
|
+
const run = context.findRun(runId);
|
|
1890
|
+
if (!run)
|
|
1891
|
+
return false;
|
|
1892
|
+
const stage = context.findStage(run, stageId);
|
|
1893
|
+
if (stage?.status !== "blocked")
|
|
1894
|
+
return false;
|
|
1895
|
+
stage.status = "pending";
|
|
1896
|
+
delete stage.blockedByStageId;
|
|
1897
|
+
delete stage.awaitingInputSince;
|
|
1898
|
+
context.bumpAndNotify();
|
|
1899
|
+
return true;
|
|
1900
|
+
},
|
|
1901
|
+
recordStageNotice(runId, stageId, notice) {
|
|
1902
|
+
const run = context.findRun(runId);
|
|
1903
|
+
if (!run)
|
|
1904
|
+
return false;
|
|
1905
|
+
const stage = context.findStage(run, stageId);
|
|
1906
|
+
if (!stage)
|
|
1907
|
+
return false;
|
|
1908
|
+
if (!stage.notices)
|
|
1909
|
+
stage.notices = [];
|
|
1910
|
+
stage.notices.push(notice);
|
|
1911
|
+
context.bumpAndNotify();
|
|
1912
|
+
return true;
|
|
1913
|
+
},
|
|
1914
|
+
recordStagePaused(runId, stageId, pausedAt, metadata) {
|
|
1915
|
+
const run = context.findRun(runId);
|
|
1916
|
+
if (!run)
|
|
1917
|
+
return false;
|
|
1918
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1919
|
+
return false;
|
|
1920
|
+
const stage = context.findStage(run, stageId);
|
|
1921
|
+
if (!stage)
|
|
1922
|
+
return false;
|
|
1923
|
+
if (cannotPause(stage.status)) {
|
|
1924
|
+
if (stage.status !== "paused" || metadata?.actor === undefined)
|
|
1925
|
+
return false;
|
|
1926
|
+
if (stage.pauseActor === metadata.actor)
|
|
1927
|
+
return false;
|
|
1928
|
+
stage.pauseActor = metadata.actor;
|
|
1929
|
+
context.bumpAndNotify();
|
|
1930
|
+
return false;
|
|
1931
|
+
}
|
|
1932
|
+
stage.status = "paused";
|
|
1933
|
+
stage.pausedAt = nextControlTimestamp(pausedAt, stage.resumedAt);
|
|
1934
|
+
stage.resumedAt = undefined;
|
|
1935
|
+
delete stage.awaitingInputSince;
|
|
1936
|
+
delete stage.resumeActor;
|
|
1937
|
+
if (metadata?.actor === undefined)
|
|
1938
|
+
delete stage.pauseActor;
|
|
1939
|
+
else
|
|
1940
|
+
stage.pauseActor = metadata.actor;
|
|
1941
|
+
context.bumpAndNotify();
|
|
1942
|
+
return true;
|
|
1943
|
+
},
|
|
1944
|
+
recordStageResumed(runId, stageId, resumedAt, metadata) {
|
|
1945
|
+
const run = context.findRun(runId);
|
|
1946
|
+
if (!run)
|
|
1947
|
+
return false;
|
|
1948
|
+
if (TERMINAL_STATUSES.has(run.status))
|
|
1949
|
+
return false;
|
|
1950
|
+
const stage = context.findStage(run, stageId);
|
|
1951
|
+
if (!stage)
|
|
1952
|
+
return false;
|
|
1953
|
+
if (stage.status !== "paused" && stage.status !== "blocked") {
|
|
1954
|
+
if (stage.status !== "running" || stage.resumedAt === undefined || metadata?.actor === undefined) {
|
|
1955
|
+
return false;
|
|
1956
|
+
}
|
|
1957
|
+
if (stage.resumeActor === metadata.actor)
|
|
1958
|
+
return false;
|
|
1959
|
+
stage.resumeActor = metadata.actor;
|
|
1960
|
+
context.bumpAndNotify();
|
|
1961
|
+
return false;
|
|
1962
|
+
}
|
|
1963
|
+
const resumedTs = nextControlTimestamp(resumedAt, stage.pausedAt);
|
|
1964
|
+
stage.status = "running";
|
|
1965
|
+
if (stage.startedAt !== undefined) {
|
|
1966
|
+
stage.pausedDurationMs = accumulatePausedDurationMs(stage.pausedDurationMs, stage.pausedAt, resumedTs);
|
|
1967
|
+
}
|
|
1968
|
+
stage.resumedAt = resumedTs;
|
|
1969
|
+
stage.pausedAt = undefined;
|
|
1970
|
+
delete stage.blockedByStageId;
|
|
1971
|
+
delete stage.awaitingInputSince;
|
|
1972
|
+
delete stage.pauseActor;
|
|
1973
|
+
if (metadata?.actor === undefined)
|
|
1974
|
+
delete stage.resumeActor;
|
|
1975
|
+
else
|
|
1976
|
+
stage.resumeActor = metadata.actor;
|
|
1977
|
+
context.bumpAndNotify();
|
|
1978
|
+
return true;
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// dist/builtin/workflows/src/shared/store-factory.ts
|
|
1984
|
+
function createStore() {
|
|
1985
|
+
const context = createStoreContext();
|
|
1986
|
+
return {
|
|
1987
|
+
...createRunStoreMethods(context),
|
|
1988
|
+
...createPendingStageDeliveryStoreMethods(context),
|
|
1989
|
+
...createStageStoreMethods(context),
|
|
1990
|
+
...createToolNodeStoreMethods(context),
|
|
1991
|
+
...createPromptStoreMethods(context)
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
var SESSION_KEY = "workflows:store:v1";
|
|
1995
|
+
var singleton = createSessionScopedSingleton(SESSION_KEY, createStore);
|
|
1996
|
+
var store = singleton.facade;
|
|
1997
|
+
// dist/builtin/workflows/src/shared/workflow-artifact-env.ts
|
|
1998
|
+
var WORKFLOW_ARTIFACT_RETENTION_MS = 30 * 24 * 60 * 60 * 1000;
|
|
1999
|
+
var ENV_WORKFLOW_ARTIFACT_DIR = "ATOMIC_WORKFLOW_ARTIFACT_DIR";
|
|
2000
|
+
|
|
2001
|
+
// dist/builtin/workflows/src/shared/workflow-artifacts.ts
|
|
2002
|
+
var ARTIFACT_PRUNE_RECHECK_MS = 60 * 60 * 1000;
|
|
2003
|
+
var lastArtifactPruneAt = new Map;
|
|
2004
|
+
var pendingArtifactPrunes = new Map;
|
|
2005
|
+
function workflowArtifactRoot() {
|
|
2006
|
+
const override = getEnvValue(ENV_WORKFLOW_ARTIFACT_DIR);
|
|
2007
|
+
if (override !== undefined && override.length > 0)
|
|
2008
|
+
return override;
|
|
2009
|
+
return join(dirname(getAgentDir()), "workflows");
|
|
2010
|
+
}
|
|
2011
|
+
function workflowArtifactRunsRoot() {
|
|
2012
|
+
return join(workflowArtifactRoot(), "runs");
|
|
2013
|
+
}
|
|
2014
|
+
function safeRunId(runId) {
|
|
2015
|
+
const safe = runId.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
2016
|
+
return safe.length > 0 ? safe : "run";
|
|
2017
|
+
}
|
|
2018
|
+
function workflowArtifactRunPath(runId) {
|
|
2019
|
+
return join(workflowArtifactRunsRoot(), safeRunId(runId));
|
|
2020
|
+
}
|
|
2021
|
+
function storeRunState(run) {
|
|
2022
|
+
const hasPendingInput = run.pendingPrompt !== undefined || run.stages.some((stage) => stage.status === "awaiting_input" || stage.status === "paused" || stage.status === "blocked");
|
|
2023
|
+
if (hasPendingInput || run.status === "pending" || run.status === "running" || run.status === "paused" || run.status === "blocked" || run.exitReason === "quit") {
|
|
2024
|
+
return "protected";
|
|
2025
|
+
}
|
|
2026
|
+
return "terminal";
|
|
2027
|
+
}
|
|
2028
|
+
function durableRunState(backend, runId) {
|
|
2029
|
+
const handle = backend.getLoadableWorkflow(runId);
|
|
2030
|
+
if (handle === undefined)
|
|
2031
|
+
return;
|
|
2032
|
+
if (handle.status === "running" || handle.status === "paused" || handle.status === "blocked" || handle.pendingPrompts > 0) {
|
|
2033
|
+
return "protected";
|
|
2034
|
+
}
|
|
2035
|
+
return "terminal";
|
|
2036
|
+
}
|
|
2037
|
+
function createWorkflowArtifactRunStateResolver() {
|
|
2038
|
+
const localRuns = new Map(store.runs().map((run) => [run.id, run]));
|
|
2039
|
+
const findLocalRun = (runId) => localRuns.get(runId) ?? [...localRuns.values()].find((run) => safeRunId(run.id) === runId);
|
|
2040
|
+
const protectedOwners = new Set;
|
|
2041
|
+
for (const run of localRuns.values()) {
|
|
2042
|
+
if (storeRunState(run) !== "protected")
|
|
2043
|
+
continue;
|
|
2044
|
+
let cursor = run;
|
|
2045
|
+
const visited = new Set;
|
|
2046
|
+
while (cursor !== undefined && !visited.has(cursor.id)) {
|
|
2047
|
+
visited.add(cursor.id);
|
|
2048
|
+
protectedOwners.add(safeRunId(cursor.id));
|
|
2049
|
+
const sourceId = cursor.resumedFromRunId;
|
|
2050
|
+
if (sourceId === undefined)
|
|
2051
|
+
break;
|
|
2052
|
+
protectedOwners.add(safeRunId(sourceId));
|
|
2053
|
+
cursor = findLocalRun(sourceId);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
let backend;
|
|
2057
|
+
let backendReady = true;
|
|
2058
|
+
try {
|
|
2059
|
+
backend = getDurableBackend();
|
|
2060
|
+
} catch {
|
|
2061
|
+
backendReady = false;
|
|
2062
|
+
}
|
|
2063
|
+
return (runId) => {
|
|
2064
|
+
if (protectedOwners.has(runId))
|
|
2065
|
+
return "protected";
|
|
2066
|
+
const local = findLocalRun(runId);
|
|
2067
|
+
const localState = local === undefined ? undefined : storeRunState(local);
|
|
2068
|
+
if (!backendReady) {
|
|
2069
|
+
return localState === "protected" ? "protected" : undefined;
|
|
2070
|
+
}
|
|
2071
|
+
let durable;
|
|
2072
|
+
if (backend !== undefined) {
|
|
2073
|
+
try {
|
|
2074
|
+
durable = durableRunState(backend, runId);
|
|
2075
|
+
} catch {
|
|
2076
|
+
backendReady = false;
|
|
2077
|
+
return localState === "protected" ? "protected" : undefined;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
if (durable === "protected" || localState === "protected")
|
|
2081
|
+
return "protected";
|
|
2082
|
+
if (durable === "terminal" || localState === "terminal")
|
|
2083
|
+
return "terminal";
|
|
2084
|
+
return "orphan";
|
|
2085
|
+
};
|
|
2086
|
+
}
|
|
2087
|
+
async function deleteTerminalDurableEntry(runId) {
|
|
2088
|
+
let backend;
|
|
2089
|
+
try {
|
|
2090
|
+
backend = getDurableBackend();
|
|
2091
|
+
} catch {
|
|
2092
|
+
return false;
|
|
2093
|
+
}
|
|
2094
|
+
try {
|
|
2095
|
+
const result = await backend.deleteWorkflowIfInactive(runId);
|
|
2096
|
+
return result.ok || result.reason === "not_found";
|
|
2097
|
+
} catch {
|
|
2098
|
+
return false;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
async function pruneWorkflowArtifactRuns(root = workflowArtifactRunsRoot(), now = Date.now(), stateResolver) {
|
|
2102
|
+
try {
|
|
2103
|
+
const entries = await readdir(root, { withFileTypes: true, encoding: "utf8" });
|
|
2104
|
+
for (const entry of entries) {
|
|
2105
|
+
if (!entry.isDirectory())
|
|
2106
|
+
continue;
|
|
2107
|
+
const entryPath = join(root, entry.name);
|
|
2108
|
+
let metadata;
|
|
2109
|
+
try {
|
|
2110
|
+
metadata = await stat(entryPath);
|
|
2111
|
+
} catch (error) {
|
|
2112
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
2113
|
+
continue;
|
|
2114
|
+
throw error;
|
|
2115
|
+
}
|
|
2116
|
+
if (now - metadata.mtimeMs <= WORKFLOW_ARTIFACT_RETENTION_MS)
|
|
2117
|
+
continue;
|
|
2118
|
+
if (stateResolver === undefined)
|
|
2119
|
+
continue;
|
|
2120
|
+
const state = stateResolver(entry.name);
|
|
2121
|
+
if (state !== "terminal" && state !== "orphan")
|
|
2122
|
+
continue;
|
|
2123
|
+
if (state === "terminal" && !await deleteTerminalDurableEntry(entry.name))
|
|
2124
|
+
continue;
|
|
2125
|
+
await rm(entryPath, { recursive: true, force: true });
|
|
2126
|
+
}
|
|
2127
|
+
} catch (error) {
|
|
2128
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
2129
|
+
return;
|
|
2130
|
+
throw error;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
async function pruneArtifactRootIfDue(root, now) {
|
|
2134
|
+
const pending = pendingArtifactPrunes.get(root);
|
|
2135
|
+
if (pending !== undefined) {
|
|
2136
|
+
try {
|
|
2137
|
+
await pending;
|
|
2138
|
+
} catch {}
|
|
2139
|
+
return;
|
|
2140
|
+
}
|
|
2141
|
+
const previous = lastArtifactPruneAt.get(root);
|
|
2142
|
+
if (previous !== undefined && now - previous < ARTIFACT_PRUNE_RECHECK_MS)
|
|
2143
|
+
return;
|
|
2144
|
+
const operation = pruneWorkflowArtifactRuns(root, now, createWorkflowArtifactRunStateResolver());
|
|
2145
|
+
pendingArtifactPrunes.set(root, operation);
|
|
2146
|
+
try {
|
|
2147
|
+
await operation;
|
|
2148
|
+
} catch {} finally {
|
|
2149
|
+
lastArtifactPruneAt.set(root, now);
|
|
2150
|
+
pendingArtifactPrunes.delete(root);
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
function workflowArtifactDirectoryPath(runId) {
|
|
2154
|
+
const effectiveRunId = runId ?? randomUUID();
|
|
2155
|
+
return join(workflowArtifactRunPath(effectiveRunId), `artifact-${randomUUID()}`);
|
|
2156
|
+
}
|
|
2157
|
+
async function ensureWorkflowArtifactDirectory(directory) {
|
|
2158
|
+
await pruneArtifactRootIfDue(workflowArtifactRunsRoot(), Date.now());
|
|
2159
|
+
await mkdir(directory, { recursive: true });
|
|
2160
|
+
return directory;
|
|
2161
|
+
}
|
|
2162
|
+
async function createWorkflowArtifactDirectory(runId) {
|
|
2163
|
+
return ensureWorkflowArtifactDirectory(workflowArtifactDirectoryPath(runId));
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
// dist/builtin/workflows/builtin/goal-convergence.ts
|
|
2167
|
+
var FRACTION_TREND_RISE_DELTA = DEFAULT_RISE_DELTA / (VERIFICATION_SCALE.max - VERIFICATION_SCALE.min);
|
|
2168
|
+
var FRACTION_TREND_FALL_DELTA = DEFAULT_FALL_DELTA / (VERIFICATION_SCALE.max - VERIFICATION_SCALE.min);
|
|
2169
|
+
function record_convergence(round) {
|
|
2170
|
+
return {
|
|
2171
|
+
unresolvedBlockingCount: round.unresolvedBlockingCount,
|
|
2172
|
+
meanFindingConfidence: round.meanFindingConfidence,
|
|
2173
|
+
fractionProven: round.fractionProven,
|
|
2174
|
+
demotions: round.demotions,
|
|
2175
|
+
usage: round.usage
|
|
2176
|
+
};
|
|
2177
|
+
}
|
|
2178
|
+
function classify_convergence(entries) {
|
|
2179
|
+
return {
|
|
2180
|
+
blocking: classify_trend(entries.map((entry) => entry.unresolvedBlockingCount)),
|
|
2181
|
+
proven: classify_trend(entries.map((entry) => entry.fractionProven), {
|
|
2182
|
+
riseDelta: FRACTION_TREND_RISE_DELTA,
|
|
2183
|
+
fallDelta: FRACTION_TREND_FALL_DELTA
|
|
2184
|
+
})
|
|
2185
|
+
};
|
|
2186
|
+
}
|
|
2187
|
+
function convergence_escalation_evidence(entries) {
|
|
2188
|
+
if (entries.length === 0)
|
|
2189
|
+
return [];
|
|
2190
|
+
const { blocking, proven } = classify_convergence(entries);
|
|
2191
|
+
if (blocking.trend === "regressing" || proven.trend === "rising" && blocking.trend !== "rising")
|
|
2192
|
+
return [];
|
|
2193
|
+
const latest = entries[entries.length - 1]?.meanFindingConfidence;
|
|
2194
|
+
return [
|
|
2195
|
+
`${entries.length} round${entries.length === 1 ? "" : "s"} recorded; no observed convergence: the blocking-count trend is ${blocking.trend}.`,
|
|
2196
|
+
`Blocking-count trend: ${blocking.trend}; raw series: ${JSON.stringify(blocking.evidence.series)}.`,
|
|
2197
|
+
`Fraction-proven trend: ${proven.trend}; raw series: ${JSON.stringify(proven.evidence.series)}.`,
|
|
2198
|
+
latest === null ? "Latest mean finding confidence: no findings were filed." : `Latest mean finding confidence: ${latest}.`,
|
|
2199
|
+
"This is escalation EVIDENCE only; it never approves or terminates anything."
|
|
2200
|
+
];
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
// dist/builtin/workflows/builtin/review-convergence.ts
|
|
2204
|
+
var FINAL_ACTION_PATTERN = /\b(?:pr|pull[- ]request|merge[- ]request|review request|github pr|create pr)\b/iu;
|
|
2205
|
+
function isFinalActionTraceability(entry) {
|
|
2206
|
+
return FINAL_ACTION_PATTERN.test(`${entry.requirement}
|
|
2207
|
+
${entry.evidence}`);
|
|
2208
|
+
}
|
|
2209
|
+
function finalActionRemaining(traceability) {
|
|
2210
|
+
return traceability.some((entry) => entry.status !== "proven" && isFinalActionTraceability(entry));
|
|
2211
|
+
}
|
|
2212
|
+
var MAX_BLOCKING_PRIORITY = 2;
|
|
2213
|
+
function findingBlocksClosure(finding) {
|
|
2214
|
+
const alignment = finding.objective_alignment;
|
|
2215
|
+
if (alignment === "beyond_objective" || alignment === "contradicts_objective") {
|
|
2216
|
+
return false;
|
|
2217
|
+
}
|
|
2218
|
+
if (alignment === "required_by_objective")
|
|
2219
|
+
return true;
|
|
2220
|
+
if (alignment !== "consistent_with_objective")
|
|
2221
|
+
return true;
|
|
2222
|
+
const priority = finding.priority;
|
|
2223
|
+
if (priority === undefined || priority === null)
|
|
2224
|
+
return true;
|
|
2225
|
+
return priority <= MAX_BLOCKING_PRIORITY;
|
|
2226
|
+
}
|
|
2227
|
+
function findingConsolidationKey(finding) {
|
|
2228
|
+
const normalizedTitle = finding.title.replace(/^\s*\[P[0-3]\]\s*/iu, "").toLowerCase().replace(/\s+/gu, " ").trim();
|
|
2229
|
+
return `${finding.code_location?.absolute_file_path ?? ""}::${normalizedTitle}`;
|
|
2230
|
+
}
|
|
2231
|
+
function consolidateFindingsBatch(reviews) {
|
|
2232
|
+
const byKey = new Map;
|
|
2233
|
+
for (const review of reviews) {
|
|
2234
|
+
for (const finding of review.findings) {
|
|
2235
|
+
const key = findingConsolidationKey(finding);
|
|
2236
|
+
const existing = byKey.get(key);
|
|
2237
|
+
if (existing === undefined) {
|
|
2238
|
+
byKey.set(key, {
|
|
2239
|
+
finding,
|
|
2240
|
+
reviewers: [review.reviewer],
|
|
2241
|
+
blocking: findingBlocksClosure(finding)
|
|
2242
|
+
});
|
|
2243
|
+
continue;
|
|
2244
|
+
}
|
|
2245
|
+
if (!existing.reviewers.includes(review.reviewer)) {
|
|
2246
|
+
existing.reviewers.push(review.reviewer);
|
|
2247
|
+
}
|
|
2248
|
+
existing.blocking = existing.blocking || findingBlocksClosure(finding);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
return [...byKey.values()].sort((a, b) => Number(b.blocking) - Number(a.blocking));
|
|
2252
|
+
}
|
|
2253
|
+
var PREVIEW_LIMIT = 500;
|
|
2254
|
+
function rawTextPreview(rawText) {
|
|
2255
|
+
const trimmed = rawText.trim();
|
|
2256
|
+
if (trimmed.length === 0)
|
|
2257
|
+
return;
|
|
2258
|
+
return trimmed.slice(0, PREVIEW_LIMIT);
|
|
2259
|
+
}
|
|
2260
|
+
function parseFailureDiagnostics(reviewer, rawText) {
|
|
2261
|
+
const preview = rawTextPreview(rawText);
|
|
2262
|
+
const base = `Structured reviewer decision parse failed for ${reviewer}: no schema-valid JSON decision was returned.`;
|
|
2263
|
+
return preview === undefined ? [base] : [base, `Raw reviewer output preview: ${preview}`];
|
|
2264
|
+
}
|
|
2265
|
+
function errorMessage2(error) {
|
|
2266
|
+
return error instanceof Error ? error.message : String(error);
|
|
2267
|
+
}
|
|
2268
|
+
function reviewerFailureText(error) {
|
|
2269
|
+
const messages = [errorMessage2(error)];
|
|
2270
|
+
if (error instanceof AggregateError) {
|
|
2271
|
+
for (const nested of error.errors) {
|
|
2272
|
+
messages.push(errorMessage2(nested));
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
return [...new Set(messages.map((message) => message.trim()).filter(Boolean))].join(`
|
|
2276
|
+
`);
|
|
2277
|
+
}
|
|
2278
|
+
function summarizeReviewConvergence(args) {
|
|
2279
|
+
return {
|
|
2280
|
+
parsed: args.parsed,
|
|
2281
|
+
approved: args.approved,
|
|
2282
|
+
stopReviewLoop: args.stopReviewLoop,
|
|
2283
|
+
nextAction: args.nextAction,
|
|
2284
|
+
finalActionRemaining: args.finalActionRemaining ?? args.nextAction === "pull-request",
|
|
2285
|
+
diagnostics: args.diagnostics
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
// dist/builtin/workflows/builtin/goal-reverify.ts
|
|
2290
|
+
import { Type } from "typebox";
|
|
2291
|
+
var DEFAULT_REVERIFY_THRESHOLD = 0.7;
|
|
2292
|
+
var STANDARD_CONFIRM_THRESHOLD = 10;
|
|
2293
|
+
var REQUIRED_CONFIRM_THRESHOLD = 6;
|
|
2294
|
+
var DEFAULT_REPEATS = 3;
|
|
2295
|
+
var REVERIFY_QUESTION = "Assess this specific finding against the code it cites: is it a real, objective-relevant, currently-unresolved blocker?";
|
|
2296
|
+
var reverifySchema = Type.Object({
|
|
2297
|
+
score: VERIFICATION_SCALE.schema,
|
|
2298
|
+
evidence: Type.Array(Type.String())
|
|
2299
|
+
}, { additionalProperties: false });
|
|
2300
|
+
function isRecord(value) {
|
|
2301
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2302
|
+
}
|
|
2303
|
+
function isStringArray(value) {
|
|
2304
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
2305
|
+
}
|
|
2306
|
+
function parseReport(result) {
|
|
2307
|
+
if (!isRecord(result.structured))
|
|
2308
|
+
return;
|
|
2309
|
+
const score = result.structured.score;
|
|
2310
|
+
if (typeof score !== "number" || !Number.isInteger(score) || score < VERIFICATION_SCALE.min || score > VERIFICATION_SCALE.max) {
|
|
2311
|
+
return;
|
|
2312
|
+
}
|
|
2313
|
+
const evidence = result.structured.evidence;
|
|
2314
|
+
return {
|
|
2315
|
+
score,
|
|
2316
|
+
evidence: isStringArray(evidence) ? evidence : []
|
|
2317
|
+
};
|
|
2318
|
+
}
|
|
2319
|
+
function requiredByObjective(finding) {
|
|
2320
|
+
return finding.finding.objective_alignment === "required_by_objective";
|
|
2321
|
+
}
|
|
2322
|
+
function is_reverifiable(finding, threshold = DEFAULT_REVERIFY_THRESHOLD) {
|
|
2323
|
+
const confidence = finding.finding.confidence_score;
|
|
2324
|
+
return finding.blocking && finding.reviewers.length === 1 && typeof confidence === "number" && Number.isFinite(confidence) && confidence < threshold && finding.finding.objective_alignment !== "beyond_objective" && finding.finding.objective_alignment !== "contradicts_objective";
|
|
2325
|
+
}
|
|
2326
|
+
function readPaths(finding, candidateRefs) {
|
|
2327
|
+
const codePath = finding.finding.code_location?.absolute_file_path;
|
|
2328
|
+
return [
|
|
2329
|
+
...codePath === undefined ? [] : [codePath],
|
|
2330
|
+
...candidateRefs
|
|
2331
|
+
];
|
|
2332
|
+
}
|
|
2333
|
+
function promptFor(finding, context) {
|
|
2334
|
+
const codePath = finding.finding.code_location?.absolute_file_path;
|
|
2335
|
+
const candidate = {
|
|
2336
|
+
...codePath === undefined ? {} : { path: codePath },
|
|
2337
|
+
body: [
|
|
2338
|
+
`Title: ${finding.finding.title}`,
|
|
2339
|
+
`Body: ${finding.finding.body ?? ""}`,
|
|
2340
|
+
`Code location: ${codePath ?? "not supplied"}`
|
|
2341
|
+
].join(`
|
|
2342
|
+
`)
|
|
2343
|
+
};
|
|
2344
|
+
const head = {
|
|
2345
|
+
task: `${REVERIFY_QUESTION}
|
|
2346
|
+
|
|
2347
|
+
Objective:
|
|
2348
|
+
${context.objective}`,
|
|
2349
|
+
groundTruthNote: `The objective is the contract. Verify the finding against observed code, not reviewer narration.`,
|
|
2350
|
+
candidates: [candidate],
|
|
2351
|
+
outputFormat: "Call structured_output with score (an integer from 1 to 20) and evidence (an array of observed, concise reasons)."
|
|
2352
|
+
};
|
|
2353
|
+
const prompt = build_scoring_prompt(head, {
|
|
2354
|
+
id: "finding_reverification",
|
|
2355
|
+
name: "Finding re-verification",
|
|
2356
|
+
description: REVERIFY_QUESTION
|
|
2357
|
+
});
|
|
2358
|
+
return {
|
|
2359
|
+
prompt,
|
|
2360
|
+
reads: [
|
|
2361
|
+
...readPaths(finding, context.candidateRefs),
|
|
2362
|
+
...scoring_prompt_reads(head)
|
|
2363
|
+
]
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
async function runRepeat(ctx, finding, context, stageName) {
|
|
2367
|
+
try {
|
|
2368
|
+
const rendered = promptFor(finding, context);
|
|
2369
|
+
const options = {
|
|
2370
|
+
prompt: rendered.prompt,
|
|
2371
|
+
context: "fresh",
|
|
2372
|
+
reads: rendered.reads,
|
|
2373
|
+
schema: reverifySchema
|
|
2374
|
+
};
|
|
2375
|
+
return parseReport(await ctx.task(stageName, options));
|
|
2376
|
+
} catch {
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
async function reverify_finding(ctx, input) {
|
|
2381
|
+
if (!is_reverifiable(input.finding, input.threshold)) {
|
|
2382
|
+
throw new Error("Cannot re-verify an ineligible finding.");
|
|
2383
|
+
}
|
|
2384
|
+
const repeatCount = Number.isFinite(input.repeats) && input.repeats !== undefined ? Math.max(0, Math.floor(input.repeats)) : DEFAULT_REPEATS;
|
|
2385
|
+
const perRepeat = [];
|
|
2386
|
+
const evidence = [];
|
|
2387
|
+
const validScores = [];
|
|
2388
|
+
for (let repeat = 1;repeat <= repeatCount; repeat += 1) {
|
|
2389
|
+
let report = await runRepeat(ctx, input.finding, input.context, `reverify-${repeat}`);
|
|
2390
|
+
if (report === undefined) {
|
|
2391
|
+
report = await runRepeat(ctx, input.finding, input.context, `reverify-${repeat}-reask`);
|
|
2392
|
+
}
|
|
2393
|
+
if (report === undefined) {
|
|
2394
|
+
perRepeat.push(null);
|
|
2395
|
+
evidence.push(`Re-verification repeat ${repeat} was invalid after one re-ask; doubt defaults to confirmed.`);
|
|
2396
|
+
continue;
|
|
2397
|
+
}
|
|
2398
|
+
perRepeat.push(report.score);
|
|
2399
|
+
validScores.push(report.score);
|
|
2400
|
+
if (report.evidence.length === 0) {
|
|
2401
|
+
evidence.push(`Re-verification repeat ${repeat} scored ${report.score}/20.`);
|
|
2402
|
+
} else {
|
|
2403
|
+
evidence.push(...report.evidence);
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
const meanScore = validScores.length === 0 ? 0 : validScores.reduce((total, score) => total + score, 0) / validScores.length;
|
|
2407
|
+
const validCount = validScores.length;
|
|
2408
|
+
const requiredQuorum = Math.ceil(repeatCount / 2);
|
|
2409
|
+
const demoted = requiredByObjective(input.finding) ? repeatCount > 0 && validCount === repeatCount && meanScore < REQUIRED_CONFIRM_THRESHOLD : validCount > 0 && validCount >= requiredQuorum && meanScore < STANDARD_CONFIRM_THRESHOLD;
|
|
2410
|
+
return {
|
|
2411
|
+
verdict: demoted ? "demoted" : "confirmed",
|
|
2412
|
+
meanScore,
|
|
2413
|
+
perRepeat,
|
|
2414
|
+
evidence
|
|
2415
|
+
};
|
|
2416
|
+
}
|
|
2417
|
+
function auditKey(finding) {
|
|
2418
|
+
return JSON.stringify([
|
|
2419
|
+
finding.finding.code_location?.absolute_file_path ?? "",
|
|
2420
|
+
finding.finding.title,
|
|
2421
|
+
finding.reviewers
|
|
2422
|
+
]);
|
|
2423
|
+
}
|
|
2424
|
+
function apply_reverify_results(batch, audits) {
|
|
2425
|
+
const demoted = new Set(audits.filter((audit) => audit.verdict === "demoted").map((audit) => auditKey(audit.finding)));
|
|
2426
|
+
return {
|
|
2427
|
+
batch: batch.map((entry) => demoted.has(auditKey(entry)) ? { ...entry, blocking: false } : entry),
|
|
2428
|
+
audits
|
|
2429
|
+
};
|
|
2430
|
+
}
|
|
2431
|
+
async function reverify_consolidated_batch(ctx, input) {
|
|
2432
|
+
const audits = [];
|
|
2433
|
+
for (const entry of input.batch) {
|
|
2434
|
+
if (!is_reverifiable(entry, input.threshold))
|
|
2435
|
+
continue;
|
|
2436
|
+
const result = await reverify_finding(ctx, {
|
|
2437
|
+
finding: entry,
|
|
2438
|
+
context: input.context,
|
|
2439
|
+
repeats: input.repeats,
|
|
2440
|
+
threshold: input.threshold
|
|
2441
|
+
});
|
|
2442
|
+
audits.push({ finding: entry, ...result });
|
|
2443
|
+
}
|
|
2444
|
+
return apply_reverify_results(input.batch, audits);
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
export { workflowArtifactDirectoryPath, ensureWorkflowArtifactDirectory, createWorkflowArtifactDirectory, record_convergence, convergence_escalation_evidence, finalActionRemaining, consolidateFindingsBatch, parseFailureDiagnostics, reviewerFailureText, summarizeReviewConvergence, reverify_consolidated_batch };
|