@bastani/atomic 0.9.16-alpha.7 → 0.9.16-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/package.json +1 -1
- 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 +15 -0
- package/dist/builtin/workflows/README.md +40 -37
- package/dist/builtin/workflows/builtin/adversarial-verification.js +13 -0
- package/dist/builtin/workflows/builtin/{shared-prompts.ts → chunk-0x6e303p.js} +133 -154
- package/dist/builtin/workflows/builtin/chunk-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 +1228 -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 +2 -2
- package/docs/rpc.md +21 -4
- package/docs/settings.md +6 -4
- package/docs/subagents.md +1 -1
- package/docs/usage.md +1 -1
- package/docs/workflows.md +108 -239
- package/npm-shrinkwrap.json +32 -32
- package/package.json +9 -13
- package/dist/builtin/workflows/ambient.d.ts +0 -61
- package/dist/builtin/workflows/builtin/adversarial-verification-prompts.ts +0 -26
- package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +0 -391
- package/dist/builtin/workflows/builtin/adversarial-verification.ts +0 -34
- package/dist/builtin/workflows/builtin/classify-and-act-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/classify-and-act-runner.ts +0 -108
- package/dist/builtin/workflows/builtin/classify-and-act.ts +0 -40
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-prompts.ts +0 -14
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize-runner.ts +0 -96
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +0 -37
- package/dist/builtin/workflows/builtin/generate-and-filter-prompts.ts +0 -41
- package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +0 -90
- package/dist/builtin/workflows/builtin/generate-and-filter.ts +0 -31
- package/dist/builtin/workflows/builtin/goal-artifacts.ts +0 -64
- package/dist/builtin/workflows/builtin/goal-convergence.ts +0 -87
- package/dist/builtin/workflows/builtin/goal-ledger.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-models.ts +0 -72
- package/dist/builtin/workflows/builtin/goal-orchestrator-prompts.ts +0 -94
- package/dist/builtin/workflows/builtin/goal-prompts.ts +0 -217
- package/dist/builtin/workflows/builtin/goal-reducer.ts +0 -176
- package/dist/builtin/workflows/builtin/goal-reports.ts +0 -76
- package/dist/builtin/workflows/builtin/goal-reverify.ts +0 -305
- package/dist/builtin/workflows/builtin/goal-review.ts +0 -139
- package/dist/builtin/workflows/builtin/goal-runner.ts +0 -504
- package/dist/builtin/workflows/builtin/goal-schemas.ts +0 -89
- package/dist/builtin/workflows/builtin/goal-types.ts +0 -164
- package/dist/builtin/workflows/builtin/goal.ts +0 -78
- package/dist/builtin/workflows/builtin/index.ts +0 -16
- package/dist/builtin/workflows/builtin/loop-until-done-prompts.ts +0 -87
- package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +0 -282
- package/dist/builtin/workflows/builtin/loop-until-done.ts +0 -51
- package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +0 -305
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +0 -337
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +0 -347
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +0 -313
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -311
- package/dist/builtin/workflows/builtin/open-claude-design.ts +0 -57
- package/dist/builtin/workflows/builtin/pattern-artifact-root.ts +0 -28
- package/dist/builtin/workflows/builtin/progress-scoring.ts +0 -230
- package/dist/builtin/workflows/builtin/ralph-core.ts +0 -449
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +0 -100
- package/dist/builtin/workflows/builtin/ralph-models.ts +0 -183
- package/dist/builtin/workflows/builtin/ralph-review-gate.ts +0 -103
- package/dist/builtin/workflows/builtin/ralph-reviewer-prompt.ts +0 -104
- package/dist/builtin/workflows/builtin/ralph-runner.ts +0 -459
- package/dist/builtin/workflows/builtin/ralph.ts +0 -82
- package/dist/builtin/workflows/builtin/review-convergence.ts +0 -229
- package/dist/builtin/workflows/builtin/selection-math.ts +0 -156
- package/dist/builtin/workflows/builtin/steering-context.ts +0 -51
- package/dist/builtin/workflows/builtin/tournament-prompts.ts +0 -70
- package/dist/builtin/workflows/builtin/tournament-runner.ts +0 -400
- package/dist/builtin/workflows/builtin/tournament.ts +0 -73
- package/dist/builtin/workflows/builtin/verification-criteria.ts +0 -330
- package/dist/builtin/workflows/builtin/verification-prompts.ts +0 -206
- package/dist/builtin/workflows/builtin/verification-usage.ts +0 -44
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERIFICATION_SCALE
|
|
3
|
+
} from "./chunk-cg9tmks0.js";
|
|
4
|
+
|
|
5
|
+
// dist/builtin/workflows/builtin/progress-scoring.ts
|
|
6
|
+
import { Type } from "typebox";
|
|
7
|
+
var DEFAULT_TREND_WINDOW = 3;
|
|
8
|
+
var DEFAULT_RISE_DELTA = 1.5;
|
|
9
|
+
var DEFAULT_FALL_DELTA = -1.5;
|
|
10
|
+
var DEFAULT_REPEATS = 1;
|
|
11
|
+
var CALIBRATION_RULES = [
|
|
12
|
+
"Trust observed output, not the agent's narration.",
|
|
13
|
+
"Effort and step count are NOT progress.",
|
|
14
|
+
'Agent declarations of success ("done!", "all tests pass") are ZERO evidence.',
|
|
15
|
+
"Scores may plateau or fall; wrong approaches plateau, and regressions decrease."
|
|
16
|
+
];
|
|
17
|
+
var PROGRESS_SCALE_ORIENTATION = `${VERIFICATION_SCALE.min} = certainly would not satisfy the acceptance criteria … ${VERIFICATION_SCALE.max} = verified satisfaction with observed output`;
|
|
18
|
+
var progressSchema = Type.Object({
|
|
19
|
+
scores: Type.Array(Type.Object({
|
|
20
|
+
checkpoint: Type.Integer({ minimum: 1 }),
|
|
21
|
+
score: VERIFICATION_SCALE.schema
|
|
22
|
+
}, { additionalProperties: false }))
|
|
23
|
+
}, { additionalProperties: false });
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
function isProgressStructuredOutput(value) {
|
|
28
|
+
if (!isRecord(value) || Object.keys(value).length !== 1 || !Object.hasOwn(value, "scores"))
|
|
29
|
+
return false;
|
|
30
|
+
return Array.isArray(value.scores);
|
|
31
|
+
}
|
|
32
|
+
function nullScores(checkpointCount) {
|
|
33
|
+
return Array.from({ length: checkpointCount }, () => null);
|
|
34
|
+
}
|
|
35
|
+
function defaultCheckpoints(stepCount) {
|
|
36
|
+
const result = [];
|
|
37
|
+
for (let checkpoint = 2;checkpoint <= stepCount - 1; checkpoint += 1)
|
|
38
|
+
result.push(checkpoint);
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
function validateCheckpoints(checkpoints, stepCount) {
|
|
42
|
+
for (const checkpoint of checkpoints) {
|
|
43
|
+
if (!Number.isInteger(checkpoint) || checkpoint < 1 || checkpoint > stepCount) {
|
|
44
|
+
throw new RangeError(`Progress checkpoint ${checkpoint} is outside the step range 1..${stepCount}.`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function scoresFromStructured(value, checkpoints) {
|
|
49
|
+
if (!isProgressStructuredOutput(value))
|
|
50
|
+
return nullScores(checkpoints.length);
|
|
51
|
+
const requested = new Set(checkpoints);
|
|
52
|
+
const seen = new Set;
|
|
53
|
+
const scoresByCheckpoint = new Map;
|
|
54
|
+
for (const candidate of value.scores) {
|
|
55
|
+
if (!isRecord(candidate) || Object.keys(candidate).length !== 2 || !Object.hasOwn(candidate, "checkpoint") || !Object.hasOwn(candidate, "score"))
|
|
56
|
+
continue;
|
|
57
|
+
const checkpoint = candidate.checkpoint;
|
|
58
|
+
const score = candidate.score;
|
|
59
|
+
if (typeof checkpoint !== "number" || !Number.isInteger(checkpoint) || seen.has(checkpoint))
|
|
60
|
+
continue;
|
|
61
|
+
if (!requested.has(checkpoint) || typeof score !== "number" || !Number.isInteger(score) || score < VERIFICATION_SCALE.min || score > VERIFICATION_SCALE.max)
|
|
62
|
+
continue;
|
|
63
|
+
seen.add(checkpoint);
|
|
64
|
+
scoresByCheckpoint.set(checkpoint, score);
|
|
65
|
+
}
|
|
66
|
+
return checkpoints.map((checkpoint) => scoresByCheckpoint.get(checkpoint) ?? null);
|
|
67
|
+
}
|
|
68
|
+
async function scoreRepeat(ctx, input, checkpoints, repeat) {
|
|
69
|
+
try {
|
|
70
|
+
const result = await ctx.task(`progress-score-${repeat + 1}`, {
|
|
71
|
+
prompt: build_progress_prompt({ ...input, checkpoints }),
|
|
72
|
+
context: "fresh",
|
|
73
|
+
schema: progressSchema
|
|
74
|
+
});
|
|
75
|
+
return scoresFromStructured(result.structured, checkpoints);
|
|
76
|
+
} catch {
|
|
77
|
+
return nullScores(checkpoints.length);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function score_progress(ctx, input) {
|
|
81
|
+
if (input.steps.length === 0)
|
|
82
|
+
throw new RangeError("Progress scoring requires a non-empty step prefix.");
|
|
83
|
+
const checkpoints = Array.from(input.checkpoints ?? defaultCheckpoints(input.steps.length));
|
|
84
|
+
validateCheckpoints(checkpoints, input.steps.length);
|
|
85
|
+
const repeats = input.repeats ?? DEFAULT_REPEATS;
|
|
86
|
+
const perRepeat = [];
|
|
87
|
+
for (let repeat = 0;repeat < repeats; repeat += 1) {
|
|
88
|
+
perRepeat.push(await scoreRepeat(ctx, input, checkpoints, repeat));
|
|
89
|
+
}
|
|
90
|
+
const scores = checkpoints.map((_, checkpointIndex) => {
|
|
91
|
+
const valid = perRepeat.map((repeat) => repeat[checkpointIndex]).filter((score) => score !== null);
|
|
92
|
+
if (valid.length === 0)
|
|
93
|
+
return null;
|
|
94
|
+
return valid.reduce((total, score) => total + score, 0) / valid.length;
|
|
95
|
+
});
|
|
96
|
+
return { checkpoints, scores, perRepeat };
|
|
97
|
+
}
|
|
98
|
+
function build_progress_prompt(input) {
|
|
99
|
+
const numberedSteps = input.steps.map((step, index) => `${index + 1}. ${step}`);
|
|
100
|
+
const sharedHead = [
|
|
101
|
+
"<progress_head>",
|
|
102
|
+
"<problem>",
|
|
103
|
+
input.problem,
|
|
104
|
+
"</problem>",
|
|
105
|
+
"<steps>",
|
|
106
|
+
...numberedSteps,
|
|
107
|
+
"</steps>",
|
|
108
|
+
"<calibration>",
|
|
109
|
+
...CALIBRATION_RULES,
|
|
110
|
+
"</calibration>",
|
|
111
|
+
"<scale>",
|
|
112
|
+
`Use VERIFICATION_SCALE ${VERIFICATION_SCALE.min}..${VERIFICATION_SCALE.max} to answer: would the CURRENT state satisfy the acceptance criteria?`,
|
|
113
|
+
PROGRESS_SCALE_ORIENTATION,
|
|
114
|
+
"Score only the supplied current state from observed output.",
|
|
115
|
+
"</scale>",
|
|
116
|
+
"</progress_head>"
|
|
117
|
+
].join(`
|
|
118
|
+
`);
|
|
119
|
+
const checkpointTail = [
|
|
120
|
+
"<checkpoints>",
|
|
121
|
+
"Score each listed 1-indexed checkpoint.",
|
|
122
|
+
...input.checkpoints.map((checkpoint) => `- ${checkpoint}`),
|
|
123
|
+
"</checkpoints>",
|
|
124
|
+
"<output_format>",
|
|
125
|
+
`Return structured_output with scores: [{ checkpoint, score }], using integer scores from ${VERIFICATION_SCALE.min} through ${VERIFICATION_SCALE.max}.`,
|
|
126
|
+
"</output_format>"
|
|
127
|
+
].join(`
|
|
128
|
+
`);
|
|
129
|
+
return `${sharedHead}
|
|
130
|
+
|
|
131
|
+
${checkpointTail}`;
|
|
132
|
+
}
|
|
133
|
+
function mean(values) {
|
|
134
|
+
if (values.length === 0)
|
|
135
|
+
return 0;
|
|
136
|
+
return values.reduce((total, value) => total + value, 0) / values.length;
|
|
137
|
+
}
|
|
138
|
+
function classify_trend(series, config = {}) {
|
|
139
|
+
const window = config.window ?? DEFAULT_TREND_WINDOW;
|
|
140
|
+
const riseDelta = config.riseDelta ?? DEFAULT_RISE_DELTA;
|
|
141
|
+
const fallDelta = config.fallDelta ?? DEFAULT_FALL_DELTA;
|
|
142
|
+
if (series.length < window + 1) {
|
|
143
|
+
return { trend: "flat", evidence: { series, window, delta: 0 } };
|
|
144
|
+
}
|
|
145
|
+
const sample = series.slice(-2 * window);
|
|
146
|
+
const usableLength = sample.length % 2 === 1 ? sample.length - 1 : sample.length;
|
|
147
|
+
const halfLength = usableLength / 2;
|
|
148
|
+
const leading = sample.slice(0, halfLength);
|
|
149
|
+
const trailing = sample.slice(sample.length - halfLength);
|
|
150
|
+
const delta = halfLength === 0 ? 0 : mean(trailing) - mean(leading);
|
|
151
|
+
const trend = delta >= riseDelta ? "rising" : delta <= fallDelta ? "regressing" : "flat";
|
|
152
|
+
return { trend, evidence: { series, window, delta } };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export { DEFAULT_RISE_DELTA, DEFAULT_FALL_DELTA, score_progress, classify_trend };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import {
|
|
2
|
+
VERIFICATION_SCALE
|
|
3
|
+
} from "./chunk-cg9tmks0.js";
|
|
4
|
+
|
|
5
|
+
// dist/builtin/workflows/builtin/verification-prompts.ts
|
|
6
|
+
var MAX_INLINE_CANDIDATE_BYTES = 32 * 1024;
|
|
7
|
+
var DEFAULT_WARM_CONCURRENCY = 4;
|
|
8
|
+
var DEFAULT_OUTPUT_FORMAT = "Call structured_output with criterion_id, score (1–20), evidence, and findings containing finding and severity.";
|
|
9
|
+
function inlineCandidates(head) {
|
|
10
|
+
return head.candidates.every((candidate) => Buffer.byteLength(candidate.body, "utf8") <= MAX_INLINE_CANDIDATE_BYTES);
|
|
11
|
+
}
|
|
12
|
+
function fallbackReadPaths(head) {
|
|
13
|
+
if (inlineCandidates(head))
|
|
14
|
+
return;
|
|
15
|
+
const paths = [];
|
|
16
|
+
for (const [index, candidate] of head.candidates.entries()) {
|
|
17
|
+
if (candidate.path === undefined) {
|
|
18
|
+
throw new TypeError(`Oversized candidate family requires a caller-bound path for every candidate; candidate ${index + 1} has no path.`);
|
|
19
|
+
}
|
|
20
|
+
paths.push(candidate.path);
|
|
21
|
+
}
|
|
22
|
+
return paths;
|
|
23
|
+
}
|
|
24
|
+
function candidateSection(head, readPaths) {
|
|
25
|
+
return head.candidates.map((candidate, index) => {
|
|
26
|
+
if (readPaths === undefined) {
|
|
27
|
+
return `<candidate index="${index + 1}">
|
|
28
|
+
${candidate.body}
|
|
29
|
+
</candidate>`;
|
|
30
|
+
}
|
|
31
|
+
return `<candidate index="${index + 1}" source="read">
|
|
32
|
+
Read candidate from ${readPaths[index]}.
|
|
33
|
+
</candidate>`;
|
|
34
|
+
}).join(`
|
|
35
|
+
`);
|
|
36
|
+
}
|
|
37
|
+
function scoring_prompt_reads(head) {
|
|
38
|
+
return fallbackReadPaths(head) ?? [];
|
|
39
|
+
}
|
|
40
|
+
function build_scoring_prompt(head, criterion) {
|
|
41
|
+
const readPaths = fallbackReadPaths(head);
|
|
42
|
+
const sharedHead = [
|
|
43
|
+
"<scoring_head>",
|
|
44
|
+
"<task_statement>",
|
|
45
|
+
head.task,
|
|
46
|
+
"</task_statement>",
|
|
47
|
+
"<ground_truth_note>",
|
|
48
|
+
head.groundTruthNote,
|
|
49
|
+
"</ground_truth_note>",
|
|
50
|
+
"<candidates>",
|
|
51
|
+
candidateSection(head, readPaths),
|
|
52
|
+
"</candidates>",
|
|
53
|
+
"<scale_anchors>",
|
|
54
|
+
head.scaleAnchors ?? VERIFICATION_SCALE.anchors,
|
|
55
|
+
"</scale_anchors>"
|
|
56
|
+
].join(`
|
|
57
|
+
`);
|
|
58
|
+
const varyingTail = [
|
|
59
|
+
"<criterion>",
|
|
60
|
+
`<name>${criterion.name}</name>`,
|
|
61
|
+
`<description>${criterion.description}</description>`,
|
|
62
|
+
"</criterion>",
|
|
63
|
+
"<output_format>",
|
|
64
|
+
head.outputFormat ?? DEFAULT_OUTPUT_FORMAT,
|
|
65
|
+
"</output_format>"
|
|
66
|
+
].join(`
|
|
67
|
+
`);
|
|
68
|
+
return `${sharedHead}
|
|
69
|
+
|
|
70
|
+
${varyingTail}`;
|
|
71
|
+
}
|
|
72
|
+
function boundedConcurrency(stepCount, phaseCap, inheritedCap) {
|
|
73
|
+
return Math.min(stepCount, phaseCap ?? stepCount, inheritedCap ?? stepCount);
|
|
74
|
+
}
|
|
75
|
+
async function warm_first_fan_out(ctx, steps, prefixKeyOf, options = {}) {
|
|
76
|
+
const warmIndices = [];
|
|
77
|
+
const restIndices = [];
|
|
78
|
+
const seen = new Set;
|
|
79
|
+
for (const [index, step] of steps.entries()) {
|
|
80
|
+
const prefixKey = prefixKeyOf(step, index);
|
|
81
|
+
if (seen.has(prefixKey))
|
|
82
|
+
restIndices.push(index);
|
|
83
|
+
else {
|
|
84
|
+
seen.add(prefixKey);
|
|
85
|
+
warmIndices.push(index);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const { warmConcurrency, ...parallelOptions } = options;
|
|
89
|
+
const inheritedConcurrency = parallelOptions.concurrency;
|
|
90
|
+
const resultsByIndex = new Map;
|
|
91
|
+
let warmFailure;
|
|
92
|
+
if (warmIndices.length > 0) {
|
|
93
|
+
const warmSteps = warmIndices.map((index) => steps[index]);
|
|
94
|
+
try {
|
|
95
|
+
const warmResults = await ctx.parallel(warmSteps, {
|
|
96
|
+
...parallelOptions,
|
|
97
|
+
concurrency: boundedConcurrency(warmSteps.length, warmConcurrency ?? DEFAULT_WARM_CONCURRENCY, inheritedConcurrency),
|
|
98
|
+
failFast: false
|
|
99
|
+
});
|
|
100
|
+
for (const [resultIndex, result] of warmResults.entries()) {
|
|
101
|
+
const originalIndex = warmIndices[resultIndex];
|
|
102
|
+
if (originalIndex !== undefined)
|
|
103
|
+
resultsByIndex.set(originalIndex, result);
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
warmFailure = error instanceof Error ? error : new Error(String(error));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (restIndices.length > 0) {
|
|
110
|
+
const restSteps = restIndices.map((index) => steps[index]);
|
|
111
|
+
const restResults = await ctx.parallel(restSteps, {
|
|
112
|
+
...parallelOptions,
|
|
113
|
+
concurrency: boundedConcurrency(restSteps.length, undefined, inheritedConcurrency)
|
|
114
|
+
});
|
|
115
|
+
for (const [resultIndex, result] of restResults.entries()) {
|
|
116
|
+
const originalIndex = restIndices[resultIndex];
|
|
117
|
+
if (originalIndex !== undefined)
|
|
118
|
+
resultsByIndex.set(originalIndex, result);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (warmFailure !== undefined)
|
|
122
|
+
throw warmFailure;
|
|
123
|
+
return steps.map((_, index) => resultsByIndex.get(index)).filter((result) => result !== undefined);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export { scoring_prompt_reads, build_scoring_prompt, warm_first_fan_out };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// dist/builtin/workflows/builtin/verification-usage.ts
|
|
2
|
+
function fold_usage(results) {
|
|
3
|
+
const totals = {
|
|
4
|
+
calls: 0,
|
|
5
|
+
input: 0,
|
|
6
|
+
output: 0,
|
|
7
|
+
cacheRead: 0,
|
|
8
|
+
cacheWrite: 0,
|
|
9
|
+
cost: 0,
|
|
10
|
+
turns: 0
|
|
11
|
+
};
|
|
12
|
+
for (const result of results) {
|
|
13
|
+
for (const attempt of result.modelAttempts ?? []) {
|
|
14
|
+
totals.calls += 1;
|
|
15
|
+
const usage = attempt.usage;
|
|
16
|
+
if (usage === undefined)
|
|
17
|
+
continue;
|
|
18
|
+
totals.input += usage.input ?? 0;
|
|
19
|
+
totals.output += usage.output ?? 0;
|
|
20
|
+
totals.cacheRead += usage.cacheRead ?? 0;
|
|
21
|
+
totals.cacheWrite += usage.cacheWrite ?? 0;
|
|
22
|
+
totals.cost += usage.cost ?? 0;
|
|
23
|
+
totals.turns += usage.turns ?? 0;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const cacheDenominator = totals.input + totals.cacheRead;
|
|
27
|
+
return {
|
|
28
|
+
...totals,
|
|
29
|
+
cacheHitRate: cacheDenominator === 0 ? 0 : totals.cacheRead / cacheDenominator
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { fold_usage };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import {
|
|
2
|
+
stableArtifactRoot
|
|
3
|
+
} from "./chunk-wpckd35c.js";
|
|
4
|
+
import {
|
|
5
|
+
workflow
|
|
6
|
+
} from "./chunk-bfkmzv9h.js";
|
|
7
|
+
import {
|
|
8
|
+
withSteeringPropagationContext
|
|
9
|
+
} from "./chunk-0x6e303p.js";
|
|
10
|
+
|
|
11
|
+
// dist/builtin/workflows/builtin/classify-and-act.ts
|
|
12
|
+
import { Type as Type2 } from "typebox";
|
|
13
|
+
|
|
14
|
+
// dist/builtin/workflows/builtin/classify-and-act-runner.ts
|
|
15
|
+
import { writeFile } from "node:fs/promises";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { Type } from "typebox";
|
|
18
|
+
|
|
19
|
+
// dist/builtin/workflows/builtin/classify-and-act-prompts.ts
|
|
20
|
+
var GROUNDED_REPORTING = "Before reporting progress, audit each claim against a tool result from this session. Report only work you can point to evidence for; say so explicitly when something is unverified.";
|
|
21
|
+
var READABLE_REPORT = "Lead with the outcome. Keep facts, decisions, caveats, and next steps; drop background and repetition. Use complete, readable sentences rather than compressed fragments.";
|
|
22
|
+
function classifierPrompt(prompt, categories) {
|
|
23
|
+
return `<categories>
|
|
24
|
+
${categories.map((category) => `- ${category}`).join(`
|
|
25
|
+
`)}
|
|
26
|
+
</categories>
|
|
27
|
+
|
|
28
|
+
<role>
|
|
29
|
+
You route a task to exactly one declared action category.
|
|
30
|
+
</role>
|
|
31
|
+
|
|
32
|
+
<success_criteria>
|
|
33
|
+
The selected category is copied verbatim and supported by the task's concrete wording.
|
|
34
|
+
</success_criteria>
|
|
35
|
+
|
|
36
|
+
<decision_rules>
|
|
37
|
+
Choose exactly one listed category. Use low confidence when the task is ambiguous or spans categories. Stop after making that single classification.
|
|
38
|
+
</decision_rules>
|
|
39
|
+
|
|
40
|
+
<output_format>
|
|
41
|
+
Return only the structured result requested by the schema: category, confidence, and a concise evidence-based rationale in complete sentences.
|
|
42
|
+
</output_format>
|
|
43
|
+
|
|
44
|
+
<objective>
|
|
45
|
+
Classify this task: ${prompt}
|
|
46
|
+
</objective>`;
|
|
47
|
+
}
|
|
48
|
+
function actionPrompt(input) {
|
|
49
|
+
return `<evidence>
|
|
50
|
+
Read the classification artifact at ${input.classificationPath}. Use only relevant evidence available to this stage; do not assume access to classifier conversation context.
|
|
51
|
+
</evidence>
|
|
52
|
+
|
|
53
|
+
<role>
|
|
54
|
+
You are the isolated action agent for category "${input.category}".
|
|
55
|
+
</role>
|
|
56
|
+
|
|
57
|
+
<success_criteria>
|
|
58
|
+
Complete the requested action for this category, distinguish verified facts from assumptions, and report concrete evidence, validation, and remaining risks.
|
|
59
|
+
</success_criteria>
|
|
60
|
+
|
|
61
|
+
<stop_rules>
|
|
62
|
+
Stop when the category-specific action is complete or a remaining blocker is stated with its missing evidence.
|
|
63
|
+
</stop_rules>
|
|
64
|
+
|
|
65
|
+
<output_format>
|
|
66
|
+
Markdown with Outcome, Evidence, Validation, and Remaining risks headings. ${READABLE_REPORT}
|
|
67
|
+
${GROUNDED_REPORTING}
|
|
68
|
+
</output_format>
|
|
69
|
+
|
|
70
|
+
<objective>
|
|
71
|
+
${input.prompt}
|
|
72
|
+
</objective>`;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// dist/builtin/workflows/builtin/classify-and-act-runner.ts
|
|
76
|
+
var classificationSchema = Type.Object({
|
|
77
|
+
category: Type.String({ description: "One category copied verbatim from the supplied list." }),
|
|
78
|
+
confidence: Type.Number({ minimum: 0, maximum: 1 }),
|
|
79
|
+
rationale: Type.String()
|
|
80
|
+
}, { additionalProperties: false });
|
|
81
|
+
function safeName(value) {
|
|
82
|
+
const normalized = value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
83
|
+
return normalized || "fallback";
|
|
84
|
+
}
|
|
85
|
+
function actionTools(category) {
|
|
86
|
+
const normalized = category.toLowerCase();
|
|
87
|
+
if (normalized.includes("implement") || normalized.includes("fix") || normalized.includes("code")) {
|
|
88
|
+
return ["read", "edit", "write", "bash"];
|
|
89
|
+
}
|
|
90
|
+
if (normalized.includes("research"))
|
|
91
|
+
return ["read", "web_search", "fetch_content"];
|
|
92
|
+
return ["read"];
|
|
93
|
+
}
|
|
94
|
+
async function resolveFallbackCategory(ctx, exactCategory) {
|
|
95
|
+
try {
|
|
96
|
+
const category = await ctx.ui.select("Classification is uncertain. Choose the action category.", ctx.inputs.categories);
|
|
97
|
+
return { category, fallbackMode: "interactive_select" };
|
|
98
|
+
} catch {
|
|
99
|
+
return { category: exactCategory ?? ctx.inputs.categories[0], fallbackMode: "deterministic" };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function runClassifyAndAct(ctx) {
|
|
103
|
+
const artifactDir = await stableArtifactRoot(ctx, "classify-and-act");
|
|
104
|
+
const classified = await ctx.task("classifier", {
|
|
105
|
+
prompt: classifierPrompt(ctx.inputs.prompt, ctx.inputs.categories),
|
|
106
|
+
schema: classificationSchema,
|
|
107
|
+
context: "fresh",
|
|
108
|
+
tools: []
|
|
109
|
+
});
|
|
110
|
+
const value = classified.structured;
|
|
111
|
+
const proposedCategory = typeof value === "object" && value !== null && "category" in value ? String(value.category) : "";
|
|
112
|
+
const confidenceValue = typeof value === "object" && value !== null && "confidence" in value ? value.confidence : 0;
|
|
113
|
+
const confidence = typeof confidenceValue === "number" && Number.isFinite(confidenceValue) ? Math.max(0, Math.min(1, confidenceValue)) : 0;
|
|
114
|
+
const rationale = typeof value === "object" && value !== null && "rationale" in value ? String(value.rationale) : "Classifier did not provide a usable structured rationale.";
|
|
115
|
+
const exactCategory = ctx.inputs.categories.find((category2) => category2 === proposedCategory);
|
|
116
|
+
const needsFallback = exactCategory === undefined || confidence < ctx.inputs.confidence_threshold;
|
|
117
|
+
const fallback = needsFallback ? await resolveFallbackCategory(ctx, exactCategory) : undefined;
|
|
118
|
+
const category = fallback?.category ?? exactCategory;
|
|
119
|
+
const classificationPath = join(artifactDir, "classification.json");
|
|
120
|
+
await writeFile(classificationPath, JSON.stringify({
|
|
121
|
+
proposed_category: proposedCategory,
|
|
122
|
+
selected_category: category,
|
|
123
|
+
confidence,
|
|
124
|
+
threshold: ctx.inputs.confidence_threshold,
|
|
125
|
+
rationale,
|
|
126
|
+
fallback_used: needsFallback,
|
|
127
|
+
fallback_mode: fallback?.fallbackMode ?? "none"
|
|
128
|
+
}, null, 2));
|
|
129
|
+
const actionPath = join(artifactDir, `action-${safeName(category)}.md`);
|
|
130
|
+
const action = await ctx.task(`action-${safeName(category)}`, {
|
|
131
|
+
tools: actionTools(category),
|
|
132
|
+
prompt: actionPrompt({ prompt: ctx.inputs.prompt, category, classificationPath }),
|
|
133
|
+
context: "fresh",
|
|
134
|
+
reads: [classificationPath],
|
|
135
|
+
output: actionPath,
|
|
136
|
+
outputMode: "file-only"
|
|
137
|
+
});
|
|
138
|
+
const result = action.text;
|
|
139
|
+
return { result, category, confidence, action: action.stageName, classification_path: classificationPath, action_path: actionPath, artifact_dir: artifactDir };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// dist/builtin/workflows/builtin/classify-and-act.ts
|
|
143
|
+
var DEFAULT_ACTION_CATEGORIES = ["analysis", "implementation", "research"];
|
|
144
|
+
var classify_and_act_default = workflow({
|
|
145
|
+
name: "classify-and-act",
|
|
146
|
+
description: "Classify a task with structured confidence, route deterministically to an isolated category action, and ask for human selection when confidence is low.",
|
|
147
|
+
heartbeatIntervalMinutes: 15,
|
|
148
|
+
inputs: {
|
|
149
|
+
prompt: Type2.String({ description: "Task to classify and execute." }),
|
|
150
|
+
categories: Type2.Array(Type2.String({ minLength: 1 }), {
|
|
151
|
+
minItems: 1,
|
|
152
|
+
maxItems: 8,
|
|
153
|
+
default: [...DEFAULT_ACTION_CATEGORIES],
|
|
154
|
+
description: "Ordered action categories available to the classifier and fallback chooser."
|
|
155
|
+
}),
|
|
156
|
+
confidence_threshold: Type2.Number({
|
|
157
|
+
minimum: 0.5,
|
|
158
|
+
maximum: 0.99,
|
|
159
|
+
default: 0.75,
|
|
160
|
+
description: "Minimum structured confidence required to route without human selection."
|
|
161
|
+
})
|
|
162
|
+
},
|
|
163
|
+
outputs: {
|
|
164
|
+
result: Type2.String({ description: "Compact reference to the category-specific action report artifact; read `action_path` for the full report." }),
|
|
165
|
+
category: Type2.String({ description: "Selected category, including any human fallback selection." }),
|
|
166
|
+
confidence: Type2.Number({ minimum: 0, maximum: 1, description: "Classifier confidence before fallback." }),
|
|
167
|
+
action: Type2.String({ description: "Executed category-specific action stage name." }),
|
|
168
|
+
classification_path: Type2.String({ description: "Structured classification artifact path." }),
|
|
169
|
+
action_path: Type2.String({ description: "Category action report artifact path." }),
|
|
170
|
+
artifact_dir: Type2.String({ description: "Per-run artifact directory." })
|
|
171
|
+
},
|
|
172
|
+
run: async (ctx) => await runClassifyAndAct(withSteeringPropagationContext(ctx))
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
export { DEFAULT_ACTION_CATEGORIES, classify_and_act_default };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// dist/builtin/workflows/src/authoring/workflow.ts
|
|
2
|
+
import { basename } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
// dist/builtin/workflows/src/shared/budget.ts
|
|
6
|
+
function validateWorkflowBudget(value, label = "budget") {
|
|
7
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
8
|
+
return `"${label}" must be a JSON object, got ${JSON.stringify(typeof value)}`;
|
|
9
|
+
}
|
|
10
|
+
const budget = value;
|
|
11
|
+
for (const field of ["maxDurationMs", "maxTokens"]) {
|
|
12
|
+
const limit = budget[field];
|
|
13
|
+
if (field in budget && (typeof limit !== "number" || !Number.isFinite(limit) || !Number.isInteger(limit) || limit < 0)) {
|
|
14
|
+
return `"${label}.${field}" must be a non-negative finite integer, got ${JSON.stringify(limit)}`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
for (const field of ["maxCost", "warnAtPercent"]) {
|
|
18
|
+
const limit = budget[field];
|
|
19
|
+
if (field in budget && (typeof limit !== "number" || !Number.isFinite(limit) || limit < 0)) {
|
|
20
|
+
return `"${label}.${field}" must be a non-negative finite number, got ${JSON.stringify(limit)}`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function assertWorkflowBudget(value, label = "budget") {
|
|
26
|
+
if (value === undefined)
|
|
27
|
+
return;
|
|
28
|
+
const reason = validateWorkflowBudget(value, label);
|
|
29
|
+
if (reason !== null)
|
|
30
|
+
throw new TypeError(reason);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// dist/builtin/workflows/src/shared/workflow-heartbeat-contract.ts
|
|
34
|
+
var DEFAULT_WORKFLOW_HEARTBEAT_INTERVAL_MINUTES = 15;
|
|
35
|
+
|
|
36
|
+
// dist/builtin/workflows/src/workflows/identity.ts
|
|
37
|
+
function normalizeWorkflowName(name) {
|
|
38
|
+
if (!name || typeof name !== "string") {
|
|
39
|
+
throw new TypeError("normalizeWorkflowName: name must be a non-empty string");
|
|
40
|
+
}
|
|
41
|
+
return name.trim().toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-{2,}/g, "-").replace(/^-|-$/g, "");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// dist/builtin/workflows/src/authoring/workflow.ts
|
|
45
|
+
var BRANDED_WORKFLOW_DEFINITIONS = new WeakSet;
|
|
46
|
+
function stampWorkflowDefinition(definition) {
|
|
47
|
+
BRANDED_WORKFLOW_DEFINITIONS.add(definition);
|
|
48
|
+
return definition;
|
|
49
|
+
}
|
|
50
|
+
function requireNonEmptyString(value, label) {
|
|
51
|
+
if (value.trim().length === 0) {
|
|
52
|
+
throw new TypeError(`workflow: ${label} must be a non-empty string`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function freezeSchemaMap(schemas) {
|
|
56
|
+
return Object.freeze({ ...schemas });
|
|
57
|
+
}
|
|
58
|
+
function stackFilePath(line) {
|
|
59
|
+
const fileUrlMatch = line.match(/\(?((?:file:\/\/)[^\s)]+?\.[cm]?[jt]sx?):\d+:\d+\)?/);
|
|
60
|
+
const rawPath = fileUrlMatch?.[1] ?? line.match(/\(?((?:\/|[A-Za-z]:[\\/])[^():]+?\.[cm]?[jt]sx?):\d+:\d+\)?/)?.[1];
|
|
61
|
+
if (rawPath === undefined)
|
|
62
|
+
return;
|
|
63
|
+
if (!rawPath.startsWith("file://"))
|
|
64
|
+
return rawPath;
|
|
65
|
+
try {
|
|
66
|
+
return fileURLToPath(rawPath);
|
|
67
|
+
} catch {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isWorkflowAuthoringImplementationFrame(filePath) {
|
|
72
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
73
|
+
if (!/\/authoring\/workflow\.[cm]?[jt]sx?$/.test(normalized))
|
|
74
|
+
return false;
|
|
75
|
+
return normalized.includes("/packages/workflows/") || normalized.includes("/node_modules/@bastani/workflows/") || normalized.includes("/dist/builtin/workflows/") || normalized.includes("/.atomic/agent/extensions/workflows/") || normalized.includes("/.pi/agent/extensions/workflows/");
|
|
76
|
+
}
|
|
77
|
+
function workflowNameFromCaller() {
|
|
78
|
+
const stack = new Error().stack;
|
|
79
|
+
if (stack === undefined)
|
|
80
|
+
return;
|
|
81
|
+
for (const line of stack.split(`
|
|
82
|
+
`)) {
|
|
83
|
+
const filePath = stackFilePath(line);
|
|
84
|
+
if (filePath === undefined)
|
|
85
|
+
continue;
|
|
86
|
+
if (isWorkflowAuthoringImplementationFrame(filePath))
|
|
87
|
+
continue;
|
|
88
|
+
const base = basename(filePath.replace(/\\/g, "/")).replace(/\.[cm]?[jt]sx?$/, "");
|
|
89
|
+
if (base.length > 0)
|
|
90
|
+
return base;
|
|
91
|
+
}
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
function resolveWorkflowName(name) {
|
|
95
|
+
const resolved = name ?? workflowNameFromCaller();
|
|
96
|
+
if (resolved === undefined) {
|
|
97
|
+
throw new TypeError("workflow: name must be provided when caller filename cannot be inferred");
|
|
98
|
+
}
|
|
99
|
+
requireNonEmptyString(resolved, "name");
|
|
100
|
+
return resolved;
|
|
101
|
+
}
|
|
102
|
+
function freezeInputBindings(binding) {
|
|
103
|
+
if (binding === undefined)
|
|
104
|
+
return;
|
|
105
|
+
return Object.freeze({
|
|
106
|
+
worktree: Object.freeze({ ...binding })
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
function freezeBudget(budget) {
|
|
110
|
+
return budget === undefined ? undefined : Object.freeze({ ...budget });
|
|
111
|
+
}
|
|
112
|
+
function workflow(spec) {
|
|
113
|
+
const specRun = spec.run;
|
|
114
|
+
if (typeof spec.description !== "string") {
|
|
115
|
+
throw new TypeError("workflow: description must be a string");
|
|
116
|
+
}
|
|
117
|
+
if (typeof specRun !== "function") {
|
|
118
|
+
throw new TypeError("workflow: run must be a function");
|
|
119
|
+
}
|
|
120
|
+
if (spec.outputs === undefined || spec.outputs === null || typeof spec.outputs !== "object" || Array.isArray(spec.outputs)) {
|
|
121
|
+
throw new TypeError("workflow: outputs must be a schema map");
|
|
122
|
+
}
|
|
123
|
+
if (spec.inputs !== undefined && (spec.inputs === null || typeof spec.inputs !== "object" || Array.isArray(spec.inputs))) {
|
|
124
|
+
throw new TypeError("workflow: inputs must be a schema map");
|
|
125
|
+
}
|
|
126
|
+
const heartbeatIntervalMinutes = spec.heartbeatIntervalMinutes === undefined ? DEFAULT_WORKFLOW_HEARTBEAT_INTERVAL_MINUTES : spec.heartbeatIntervalMinutes;
|
|
127
|
+
if (!Number.isFinite(heartbeatIntervalMinutes) || heartbeatIntervalMinutes < 0) {
|
|
128
|
+
throw new TypeError("workflow: heartbeatIntervalMinutes must be a non-negative finite number");
|
|
129
|
+
}
|
|
130
|
+
assertWorkflowBudget(spec.budget, "workflow: budget");
|
|
131
|
+
const name = resolveWorkflowName(spec.name);
|
|
132
|
+
const normalizedName = normalizeWorkflowName(name);
|
|
133
|
+
requireNonEmptyString(normalizedName, "normalized name");
|
|
134
|
+
const frozenInputs = freezeSchemaMap(spec.inputs ?? {});
|
|
135
|
+
const frozenOutputs = freezeSchemaMap(spec.outputs);
|
|
136
|
+
const inputBindings = freezeInputBindings(spec.worktreeFromInputs);
|
|
137
|
+
const budget = freezeBudget(spec.budget);
|
|
138
|
+
const run = async (ctx) => specRun(ctx);
|
|
139
|
+
const definition = {
|
|
140
|
+
__piWorkflow: true,
|
|
141
|
+
name,
|
|
142
|
+
normalizedName,
|
|
143
|
+
description: spec.description,
|
|
144
|
+
...spec.autoAttach === true ? { autoAttach: true } : {},
|
|
145
|
+
heartbeatIntervalMinutes,
|
|
146
|
+
inputs: frozenInputs,
|
|
147
|
+
outputs: frozenOutputs,
|
|
148
|
+
...inputBindings !== undefined ? { inputBindings } : {},
|
|
149
|
+
...budget !== undefined ? { budget } : {},
|
|
150
|
+
run
|
|
151
|
+
};
|
|
152
|
+
const branded = stampWorkflowDefinition(definition);
|
|
153
|
+
return Object.freeze(branded);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export { workflow };
|