@namzu/sdk 59.0.0 → 60.0.0
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 +102 -0
- package/dist/compaction/context-window.d.ts +53 -0
- package/dist/compaction/context-window.d.ts.map +1 -1
- package/dist/compaction/context-window.js +141 -2
- package/dist/compaction/context-window.js.map +1 -1
- package/dist/execution/workflow/index.d.ts +3 -1
- package/dist/execution/workflow/index.d.ts.map +1 -1
- package/dist/execution/workflow/index.js +2 -1
- package/dist/execution/workflow/index.js.map +1 -1
- package/dist/execution/workflow/journal.d.ts +24 -4
- package/dist/execution/workflow/journal.d.ts.map +1 -1
- package/dist/execution/workflow/journal.js +131 -9
- package/dist/execution/workflow/journal.js.map +1 -1
- package/dist/execution/workflow/prelude.d.ts +2 -0
- package/dist/execution/workflow/prelude.d.ts.map +1 -1
- package/dist/execution/workflow/prelude.js +49 -8
- package/dist/execution/workflow/prelude.js.map +1 -1
- package/dist/execution/workflow/resume.d.ts +59 -0
- package/dist/execution/workflow/resume.d.ts.map +1 -0
- package/dist/execution/workflow/resume.js +273 -0
- package/dist/execution/workflow/resume.js.map +1 -0
- package/dist/execution/workflow/runtime.d.ts.map +1 -1
- package/dist/execution/workflow/runtime.js +112 -8
- package/dist/execution/workflow/runtime.js.map +1 -1
- package/dist/execution/workflow/types.d.ts +105 -1
- package/dist/execution/workflow/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin/compat.d.ts +24 -0
- package/dist/plugin/compat.d.ts.map +1 -0
- package/dist/plugin/compat.js +149 -0
- package/dist/plugin/compat.js.map +1 -0
- package/dist/plugin/loader.d.ts +2 -1
- package/dist/plugin/loader.d.ts.map +1 -1
- package/dist/plugin/loader.js +6 -0
- package/dist/plugin/loader.js.map +1 -1
- package/dist/pricing/index.d.ts.map +1 -1
- package/dist/pricing/index.js +2 -1
- package/dist/pricing/index.js.map +1 -1
- package/dist/process/kill-tree.d.ts +44 -0
- package/dist/process/kill-tree.d.ts.map +1 -1
- package/dist/process/kill-tree.js +102 -4
- package/dist/process/kill-tree.js.map +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
- package/dist/prompt/coding-agent-doctrine.js +9 -1
- package/dist/prompt/coding-agent-doctrine.js.map +1 -1
- package/dist/provider/model-window-suffix.d.ts +18 -0
- package/dist/provider/model-window-suffix.d.ts.map +1 -0
- package/dist/provider/model-window-suffix.js +77 -0
- package/dist/provider/model-window-suffix.js.map +1 -0
- package/dist/public-runtime.d.ts +5 -3
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +5 -4
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +1 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/registry/command/kernel-commands.d.ts +1 -4
- package/dist/registry/command/kernel-commands.d.ts.map +1 -1
- package/dist/registry/command/kernel-commands.js +0 -28
- package/dist/registry/command/kernel-commands.js.map +1 -1
- package/dist/runtime/jobs/awaited-jobs.d.ts +6 -0
- package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -1
- package/dist/runtime/jobs/awaited-jobs.js +11 -0
- package/dist/runtime/jobs/awaited-jobs.js.map +1 -1
- package/dist/runtime/jobs/host-exit-finalizer.d.ts +20 -0
- package/dist/runtime/jobs/host-exit-finalizer.d.ts.map +1 -0
- package/dist/runtime/jobs/host-exit-finalizer.js +57 -0
- package/dist/runtime/jobs/host-exit-finalizer.js.map +1 -0
- package/dist/runtime/jobs/liveness.d.ts +67 -0
- package/dist/runtime/jobs/liveness.d.ts.map +1 -0
- package/dist/runtime/jobs/liveness.js +94 -0
- package/dist/runtime/jobs/liveness.js.map +1 -0
- package/dist/runtime/jobs/registry.d.ts +21 -0
- package/dist/runtime/jobs/registry.d.ts.map +1 -1
- package/dist/runtime/jobs/registry.js +104 -2
- package/dist/runtime/jobs/registry.js.map +1 -1
- package/dist/runtime/jobs/wake-budget.d.ts +35 -0
- package/dist/runtime/jobs/wake-budget.d.ts.map +1 -0
- package/dist/runtime/jobs/wake-budget.js +48 -0
- package/dist/runtime/jobs/wake-budget.js.map +1 -0
- package/dist/runtime/query/detached-calls.d.ts +65 -0
- package/dist/runtime/query/detached-calls.d.ts.map +1 -0
- package/dist/runtime/query/detached-calls.js +116 -0
- package/dist/runtime/query/detached-calls.js.map +1 -0
- package/dist/runtime/query/executor.d.ts +4 -1
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +90 -6
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/index.d.ts +20 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +31 -5
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/outstanding-work.d.ts.map +1 -1
- package/dist/runtime/query/iteration/outstanding-work.js +11 -3
- package/dist/runtime/query/iteration/outstanding-work.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +7 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +63 -1
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/session-storage.d.ts.map +1 -1
- package/dist/runtime/query/session-storage.js +8 -3
- package/dist/runtime/query/session-storage.js.map +1 -1
- package/dist/runtime/query/steering.d.ts +29 -3
- package/dist/runtime/query/steering.d.ts.map +1 -1
- package/dist/runtime/query/steering.js +58 -3
- package/dist/runtime/query/steering.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +1 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +1 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/runtime/system-events.d.ts +5 -0
- package/dist/runtime/system-events.d.ts.map +1 -1
- package/dist/runtime/system-events.js +7 -1
- package/dist/runtime/system-events.js.map +1 -1
- package/dist/sandbox/denial.d.ts +11 -0
- package/dist/sandbox/denial.d.ts.map +1 -0
- package/dist/sandbox/denial.js +61 -0
- package/dist/sandbox/denial.js.map +1 -0
- package/dist/sandbox/file-walk-program.d.ts.map +1 -1
- package/dist/sandbox/file-walk-program.js +31 -13
- package/dist/sandbox/file-walk-program.js.map +1 -1
- package/dist/sandbox/file-walk.d.ts +2 -0
- package/dist/sandbox/file-walk.d.ts.map +1 -1
- package/dist/sandbox/file-walk.js +64 -13
- package/dist/sandbox/file-walk.js.map +1 -1
- package/dist/sandbox/ignore-matcher.d.ts +30 -0
- package/dist/sandbox/ignore-matcher.d.ts.map +1 -0
- package/dist/sandbox/ignore-matcher.js +11 -0
- package/dist/sandbox/ignore-matcher.js.map +1 -0
- package/dist/sandbox/ignore-source.d.ts +26 -0
- package/dist/sandbox/ignore-source.d.ts.map +1 -0
- package/dist/sandbox/ignore-source.js +221 -0
- package/dist/sandbox/ignore-source.js.map +1 -0
- package/dist/sandbox/provider/local.d.ts.map +1 -1
- package/dist/sandbox/provider/local.js +11 -1
- package/dist/sandbox/provider/local.js.map +1 -1
- package/dist/scheduler/completion-inbox.d.ts.map +1 -1
- package/dist/scheduler/completion-inbox.js +1 -0
- package/dist/scheduler/completion-inbox.js.map +1 -1
- package/dist/session/log-hash.d.ts.map +1 -1
- package/dist/session/log-hash.js +18 -1
- package/dist/session/log-hash.js.map +1 -1
- package/dist/store/session-index/sqlite.d.ts.map +1 -1
- package/dist/store/session-index/sqlite.js +169 -16
- package/dist/store/session-index/sqlite.js.map +1 -1
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +10 -4
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts +35 -0
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +512 -67
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/glob.d.ts +1 -0
- package/dist/tools/builtins/glob.d.ts.map +1 -1
- package/dist/tools/builtins/glob.js +65 -28
- package/dist/tools/builtins/glob.js.map +1 -1
- package/dist/tools/builtins/grep.d.ts +2 -0
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +94 -40
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/job.d.ts +1 -1
- package/dist/tools/builtins/job.d.ts.map +1 -1
- package/dist/tools/builtins/job.js +34 -7
- package/dist/tools/builtins/job.js.map +1 -1
- package/dist/tools/builtins/search-support.d.ts +44 -0
- package/dist/tools/builtins/search-support.d.ts.map +1 -0
- package/dist/tools/builtins/search-support.js +89 -0
- package/dist/tools/builtins/search-support.js.map +1 -0
- package/dist/tools/builtins/wait-for-job-bounds.d.ts +2 -0
- package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -1
- package/dist/tools/builtins/wait-for-job-bounds.js +3 -1
- package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -1
- package/dist/tools/builtins/wait-for-job.d.ts +1 -1
- package/dist/tools/builtins/wait-for-job.d.ts.map +1 -1
- package/dist/tools/builtins/wait-for-job.js +13 -2
- package/dist/tools/builtins/wait-for-job.js.map +1 -1
- package/dist/tools/command-shell.d.ts.map +1 -1
- package/dist/tools/command-shell.js +14 -5
- package/dist/tools/command-shell.js.map +1 -1
- package/dist/types/computer-use/index.d.ts +129 -13
- package/dist/types/computer-use/index.d.ts.map +1 -1
- package/dist/types/computer-use/index.js.map +1 -1
- package/dist/types/plugin/index.d.ts +24 -0
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js +4 -0
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/sandbox/index.d.ts +38 -1
- package/dist/types/sandbox/index.d.ts.map +1 -1
- package/dist/types/sandbox/index.js.map +1 -1
- package/dist/types/session/records.d.ts +264 -0
- package/dist/types/session/records.d.ts.map +1 -1
- package/dist/types/session/records.js +32 -1
- package/dist/types/session/records.js.map +1 -1
- package/dist/types/tool/index.d.ts +30 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/dist/types/tool/presentation.d.ts +8 -0
- package/dist/types/tool/presentation.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/compaction/context-window.ts +163 -2
- package/src/execution/workflow/index.ts +14 -1
- package/src/execution/workflow/journal.ts +161 -11
- package/src/execution/workflow/prelude.ts +51 -8
- package/src/execution/workflow/resume.ts +313 -0
- package/src/execution/workflow/runtime.ts +127 -9
- package/src/execution/workflow/types.ts +109 -1
- package/src/index.ts +17 -0
- package/src/plugin/compat.ts +173 -0
- package/src/plugin/loader.ts +7 -1
- package/src/pricing/index.ts +2 -1
- package/src/process/kill-tree.ts +106 -4
- package/src/prompt/coding-agent-doctrine.ts +9 -1
- package/src/provider/model-window-suffix.ts +84 -0
- package/src/public-runtime.ts +21 -2
- package/src/public-types.ts +1 -0
- package/src/registry/command/kernel-commands.ts +1 -32
- package/src/runtime/jobs/awaited-jobs.ts +11 -0
- package/src/runtime/jobs/host-exit-finalizer.ts +67 -0
- package/src/runtime/jobs/liveness.ts +144 -0
- package/src/runtime/jobs/registry.ts +114 -2
- package/src/runtime/jobs/wake-budget.ts +55 -0
- package/src/runtime/query/detached-calls.ts +135 -0
- package/src/runtime/query/executor.ts +92 -10
- package/src/runtime/query/index.ts +50 -7
- package/src/runtime/query/iteration/outstanding-work.ts +12 -3
- package/src/runtime/query/iteration/phases/context.ts +7 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +73 -8
- package/src/runtime/query/session-storage.ts +8 -3
- package/src/runtime/query/steering.ts +77 -6
- package/src/runtime/query/tooling.ts +2 -0
- package/src/runtime/system-events.ts +12 -1
- package/src/sandbox/denial.ts +79 -0
- package/src/sandbox/file-walk-program.ts +32 -13
- package/src/sandbox/file-walk.ts +75 -12
- package/src/sandbox/ignore-matcher.ts +46 -0
- package/src/sandbox/ignore-source.ts +220 -0
- package/src/sandbox/provider/local.ts +11 -1
- package/src/scheduler/completion-inbox.ts +1 -0
- package/src/session/log-hash.ts +21 -0
- package/src/store/session-index/sqlite.ts +171 -16
- package/src/tools/builtins/bash.ts +11 -4
- package/src/tools/builtins/computer-use.ts +593 -68
- package/src/tools/builtins/glob.ts +79 -32
- package/src/tools/builtins/grep.ts +107 -43
- package/src/tools/builtins/job.ts +42 -12
- package/src/tools/builtins/search-support.ts +107 -0
- package/src/tools/builtins/wait-for-job-bounds.ts +5 -1
- package/src/tools/builtins/wait-for-job.ts +14 -2
- package/src/tools/command-shell.ts +13 -5
- package/src/types/computer-use/index.ts +157 -15
- package/src/types/plugin/index.ts +8 -0
- package/src/types/sandbox/index.ts +40 -1
- package/src/types/session/records.ts +36 -2
- package/src/types/tool/index.ts +30 -0
- package/src/types/tool/presentation.ts +8 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { createHash, createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
/** The key version. A change to how keys are made bumps it, so old keys simply never match. */
|
|
3
|
+
const KEY_VERSION = 'k1';
|
|
4
|
+
function sha256Hex(text) {
|
|
5
|
+
return createHash('sha256').update(text).digest('hex');
|
|
6
|
+
}
|
|
7
|
+
/** JSON with every object's keys sorted and `__proto__` dropped, so equal values give equal text. */
|
|
8
|
+
function canonicalJson(value) {
|
|
9
|
+
if (Array.isArray(value))
|
|
10
|
+
return `[${value.map((item) => canonicalJson(item)).join(',')}]`;
|
|
11
|
+
if (typeof value === 'object' && value !== null) {
|
|
12
|
+
const record = value;
|
|
13
|
+
const keys = Object.keys(record)
|
|
14
|
+
.filter((key) => key !== '__proto__' && record[key] !== undefined)
|
|
15
|
+
.sort();
|
|
16
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(',')}}`;
|
|
17
|
+
}
|
|
18
|
+
return JSON.stringify(value) ?? 'null';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* The key a call is saved and looked up under: the prompt, the options that
|
|
22
|
+
* change what the agent does (schema, model, effort, agent type) and how many
|
|
23
|
+
* identical calls came before it in the same pass. Each part is length-prefixed
|
|
24
|
+
* so one cannot be read as part of another.
|
|
25
|
+
*/
|
|
26
|
+
export function workflowCallKey(prompt, call, ordinal) {
|
|
27
|
+
return `${KEY_VERSION}:${sha256Hex(`${workflowCallContent(prompt, call)}${ordinal}`)}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* What makes two calls the same call: the prompt and the options that change
|
|
31
|
+
* the agent, in a form where key order and `undefined` do not matter. The
|
|
32
|
+
* runtime counts repeats of this text to give identical calls distinct slots,
|
|
33
|
+
* and the key hashes the same text, so the two can never disagree.
|
|
34
|
+
*/
|
|
35
|
+
export function workflowCallContent(prompt, call) {
|
|
36
|
+
const options = canonicalJson({
|
|
37
|
+
schema: call.schema,
|
|
38
|
+
model: call.model,
|
|
39
|
+
effort: call.effort,
|
|
40
|
+
agentType: call.agentType,
|
|
41
|
+
});
|
|
42
|
+
return `${prompt.length}:${prompt}${options.length}:${options}`;
|
|
43
|
+
}
|
|
44
|
+
/** The hash the first line of a run's journal chains from. It binds the file to its run id. */
|
|
45
|
+
export function workflowJournalSeed(runId) {
|
|
46
|
+
return sha256Hex(`namzu-workflow-journal\0${runId}`);
|
|
47
|
+
}
|
|
48
|
+
/** The hash a line contributes to the next one: its exact bytes, newline included. */
|
|
49
|
+
export function workflowJournalLineHash(line) {
|
|
50
|
+
return sha256Hex(`${line}\n`);
|
|
51
|
+
}
|
|
52
|
+
/** The line `record` is written as. With a key, a `mac` over the rest of the line is added last. */
|
|
53
|
+
export function formatWorkflowJournalLine(record, seq, prev, key) {
|
|
54
|
+
const body = { seq, prev, ...record };
|
|
55
|
+
if (key === undefined)
|
|
56
|
+
return JSON.stringify(body);
|
|
57
|
+
const mac = createHmac('sha256', key).update(JSON.stringify(body)).digest('hex');
|
|
58
|
+
return JSON.stringify({ ...body, mac });
|
|
59
|
+
}
|
|
60
|
+
function macMatches(record, key) {
|
|
61
|
+
const { mac, ...rest } = record;
|
|
62
|
+
if (typeof mac !== 'string')
|
|
63
|
+
return false;
|
|
64
|
+
const expected = createHmac('sha256', key).update(JSON.stringify(rest)).digest();
|
|
65
|
+
const actual = Buffer.from(mac, 'hex');
|
|
66
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
67
|
+
}
|
|
68
|
+
function parseLine(line) {
|
|
69
|
+
try {
|
|
70
|
+
const value = JSON.parse(line);
|
|
71
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
72
|
+
? value
|
|
73
|
+
: undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Reads a journal's text and keeps only the records that can be trusted.
|
|
81
|
+
*
|
|
82
|
+
* Every line carries `seq` (counting trusted lines from 1) and `prev` (the hash
|
|
83
|
+
* of the line before; the first chains from a seed bound to the run id). A
|
|
84
|
+
* line that does not chain, a line that does not parse, and anything after
|
|
85
|
+
* one is dropped until a `run_started` of a resumed pass picks the chain up
|
|
86
|
+
* again at the last trusted line. A last line without its newline that is not
|
|
87
|
+
* whole JSON is a torn write and is ignored; one that is whole JSON is read
|
|
88
|
+
* like any other line. The file is never rewritten.
|
|
89
|
+
*
|
|
90
|
+
* The chain alone cannot notice an edit to the final line (nothing chains from
|
|
91
|
+
* it yet). With `key`, every line must also carry a `mac` made with that
|
|
92
|
+
* secret, which closes that gap against anyone who does not hold the key.
|
|
93
|
+
*/
|
|
94
|
+
export function readWorkflowJournalChecked(text, runId, options = {}) {
|
|
95
|
+
const endsWithNewline = text === '' || text.endsWith('\n');
|
|
96
|
+
const pieces = text.split('\n');
|
|
97
|
+
const fragment = endsWithNewline ? undefined : pieces.pop();
|
|
98
|
+
if (endsWithNewline)
|
|
99
|
+
pieces.pop();
|
|
100
|
+
// A last line without its newline that is whole JSON was only missing the newline: it is
|
|
101
|
+
// judged like any other line (the writer adds the newline before the next record, so the
|
|
102
|
+
// hash it contributes is the one of the line with its newline). Anything else is a torn write.
|
|
103
|
+
const wholeFragment = fragment !== undefined && fragment !== '' && parseLine(fragment) !== undefined;
|
|
104
|
+
if (wholeFragment)
|
|
105
|
+
pieces.push(fragment);
|
|
106
|
+
const tornTail = fragment !== undefined && fragment !== '' && !wholeFragment;
|
|
107
|
+
const parsed = pieces.map((line) => parseLine(line));
|
|
108
|
+
const firstRecord = parsed.find((record) => record !== undefined);
|
|
109
|
+
if (firstRecord !== undefined && typeof firstRecord.seq !== 'number') {
|
|
110
|
+
return {
|
|
111
|
+
records: [],
|
|
112
|
+
legacy: true,
|
|
113
|
+
tornTail,
|
|
114
|
+
lastSeq: 0,
|
|
115
|
+
lastHash: workflowJournalSeed(runId),
|
|
116
|
+
endsWithNewline,
|
|
117
|
+
untrusted: parsed.filter((record) => record !== undefined),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const records = [];
|
|
121
|
+
let lastSeq = 0;
|
|
122
|
+
let lastHash = workflowJournalSeed(runId);
|
|
123
|
+
let gapStart;
|
|
124
|
+
let gapLines = 0;
|
|
125
|
+
let gapParsed = false;
|
|
126
|
+
let brokenAt;
|
|
127
|
+
const closeGap = () => {
|
|
128
|
+
if (gapStart !== undefined && (gapLines > 1 || gapParsed))
|
|
129
|
+
brokenAt ??= gapStart;
|
|
130
|
+
gapStart = undefined;
|
|
131
|
+
gapLines = 0;
|
|
132
|
+
gapParsed = false;
|
|
133
|
+
};
|
|
134
|
+
for (let i = 0; i < pieces.length; i++) {
|
|
135
|
+
const line = pieces[i];
|
|
136
|
+
const record = parsed[i];
|
|
137
|
+
const chains = record !== undefined &&
|
|
138
|
+
record.seq === lastSeq + 1 &&
|
|
139
|
+
record.prev === lastHash &&
|
|
140
|
+
(options.key === undefined || macMatches(record, options.key));
|
|
141
|
+
const first = records.length === 0;
|
|
142
|
+
const acceptable = chains &&
|
|
143
|
+
(first
|
|
144
|
+
? record.type === 'run_started' && record.runId === runId
|
|
145
|
+
: gapStart === undefined || record.type === 'run_started');
|
|
146
|
+
if (acceptable) {
|
|
147
|
+
closeGap();
|
|
148
|
+
records.push(record);
|
|
149
|
+
lastSeq = record.seq;
|
|
150
|
+
lastHash = workflowJournalLineHash(line);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (gapStart === undefined)
|
|
154
|
+
gapStart = i + 1;
|
|
155
|
+
gapLines++;
|
|
156
|
+
if (record !== undefined)
|
|
157
|
+
gapParsed = true;
|
|
158
|
+
}
|
|
159
|
+
// A gap that runs to the end is a change, except a single line that does not parse
|
|
160
|
+
// (what a torn write leaves once the next pass closed it with a newline).
|
|
161
|
+
closeGap();
|
|
162
|
+
return {
|
|
163
|
+
records,
|
|
164
|
+
legacy: false,
|
|
165
|
+
tornTail,
|
|
166
|
+
...(brokenAt !== undefined ? { brokenAt } : {}),
|
|
167
|
+
lastSeq,
|
|
168
|
+
lastHash,
|
|
169
|
+
endsWithNewline,
|
|
170
|
+
untrusted: [],
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function hasResult(record) {
|
|
174
|
+
return Object.hasOwn(record, 'result') && record.result !== undefined && record.result !== null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Folds a checked journal into what a resumed pass needs.
|
|
178
|
+
*
|
|
179
|
+
* The last saved result for a key wins. An agent that was asked for again
|
|
180
|
+
* after a result was saved gives that result up until it finishes again. A
|
|
181
|
+
* failed or skipped outcome removes the result and marks the key failed; an
|
|
182
|
+
* outcome the run recorded as interrupted (stopped, not failed) leaves the key
|
|
183
|
+
* as seen but unfinished. Lines marked `cached` repeat an earlier result and
|
|
184
|
+
* are skipped, and so is any agent record from a pass older than the latest
|
|
185
|
+
* `run_started`, which a slow agent of an earlier pass can still write.
|
|
186
|
+
*/
|
|
187
|
+
export function loadWorkflowResume(checked) {
|
|
188
|
+
const results = new Map();
|
|
189
|
+
const seen = new Set();
|
|
190
|
+
const failed = new Set();
|
|
191
|
+
const demoted = new Set();
|
|
192
|
+
const problems = [];
|
|
193
|
+
const keysByIndex = new Map();
|
|
194
|
+
let currentPass = 0;
|
|
195
|
+
let scriptSha256;
|
|
196
|
+
let previousFinish = 'unfinished';
|
|
197
|
+
for (const record of checked.records) {
|
|
198
|
+
if (record.type === 'run_started') {
|
|
199
|
+
currentPass = record.resume?.pass ?? 1;
|
|
200
|
+
scriptSha256 = record.scriptSha256;
|
|
201
|
+
previousFinish = 'unfinished';
|
|
202
|
+
keysByIndex.clear();
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (record.type === 'run_finished') {
|
|
206
|
+
previousFinish = record.status;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (record.type !== 'agent_request' && record.type !== 'agent_outcome')
|
|
210
|
+
continue;
|
|
211
|
+
const pass = record.pass ?? 1;
|
|
212
|
+
if (pass < currentPass || record.cached === true)
|
|
213
|
+
continue;
|
|
214
|
+
if (record.type === 'agent_request') {
|
|
215
|
+
if (record.key === undefined)
|
|
216
|
+
continue;
|
|
217
|
+
keysByIndex.set(`${pass}:${record.index}`, record.key);
|
|
218
|
+
seen.add(record.key);
|
|
219
|
+
if (results.delete(record.key))
|
|
220
|
+
demoted.add(record.key);
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const key = record.key ?? keysByIndex.get(`${pass}:${record.index}`);
|
|
224
|
+
if (key === undefined)
|
|
225
|
+
continue;
|
|
226
|
+
seen.add(key);
|
|
227
|
+
if (record.state === 'done' && hasResult(record)) {
|
|
228
|
+
results.set(key, {
|
|
229
|
+
value: record.result,
|
|
230
|
+
pass,
|
|
231
|
+
index: record.index,
|
|
232
|
+
...(record.childSessionId !== undefined ? { childSessionId: record.childSessionId } : {}),
|
|
233
|
+
});
|
|
234
|
+
failed.delete(key);
|
|
235
|
+
demoted.delete(key);
|
|
236
|
+
}
|
|
237
|
+
else if (record.state === 'done' && record.unsaved === true) {
|
|
238
|
+
results.delete(key);
|
|
239
|
+
demoted.add(key);
|
|
240
|
+
}
|
|
241
|
+
else if (record.interrupted === true) {
|
|
242
|
+
// Stopped, not failed: the agent runs again and the cache stays open.
|
|
243
|
+
results.delete(key);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
results.delete(key);
|
|
247
|
+
demoted.delete(key);
|
|
248
|
+
failed.add(key);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
if (checked.legacy) {
|
|
252
|
+
problems.push('This run was saved before resuming was possible, so its agents cannot be reused.');
|
|
253
|
+
}
|
|
254
|
+
if (checked.brokenAt !== undefined) {
|
|
255
|
+
problems.push(`The journal was changed or cut short at line ${checked.brokenAt}. Results after that point are not trusted and those agents will run again.`);
|
|
256
|
+
}
|
|
257
|
+
const started = checked.records.some((record) => record.type === 'run_started');
|
|
258
|
+
if (!checked.legacy && !started)
|
|
259
|
+
problems.push('The journal has no usable record of the run.');
|
|
260
|
+
return {
|
|
261
|
+
pass: currentPass + 1,
|
|
262
|
+
results,
|
|
263
|
+
seen,
|
|
264
|
+
failed,
|
|
265
|
+
demoted,
|
|
266
|
+
...(scriptSha256 !== undefined ? { scriptSha256 } : {}),
|
|
267
|
+
previousFinish,
|
|
268
|
+
problems,
|
|
269
|
+
resumable: !checked.legacy && started,
|
|
270
|
+
...(checked.brokenAt !== undefined ? { brokenAt: checked.brokenAt } : {}),
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//# sourceMappingURL=resume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resume.js","sourceRoot":"","sources":["../../../src/execution/workflow/resume.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAUrE,+FAA+F;AAC/F,MAAM,WAAW,GAAG,IAAI,CAAA;AAExB,SAAS,SAAS,CAAC,IAAY;IAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACvD,CAAC;AAED,qGAAqG;AACrG,SAAS,aAAa,CAAC,KAAc;IACpC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA;IAC1F,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACjD,MAAM,MAAM,GAAG,KAAgC,CAAA;QAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;aAC9B,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,KAAK,WAAW,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;aACjE,IAAI,EAAE,CAAA;QACR,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA;IAClG,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAA;AACvC,CAAC;AAUD;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC9B,MAAc,EACd,IAA0B,EAC1B,OAAe;IAEf,OAAO,GAAG,WAAW,IAAI,SAAS,CAAC,GAAG,mBAAmB,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,OAAO,EAAE,CAAC,EAAE,CAAA;AACvF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,IAA0B;IAC7E,MAAM,OAAO,GAAG,aAAa,CAAC;QAC7B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,SAAS,EAAE,IAAI,CAAC,SAAS;KACzB,CAAC,CAAA;IACF,OAAO,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,EAAE,CAAA;AAChE,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,mBAAmB,CAAC,KAAa;IAChD,OAAO,SAAS,CAAC,2BAA2B,KAAK,EAAE,CAAC,CAAA;AACrD,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,uBAAuB,CAAC,IAAY;IACnD,OAAO,SAAS,CAAC,GAAG,IAAI,IAAI,CAAC,CAAA;AAC9B,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,yBAAyB,CACxC,MAA6B,EAC7B,GAAW,EACX,IAAY,EACZ,GAAyB;IAEzB,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,MAAM,EAAE,CAAA;IACrC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IAClD,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAChF,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;AACxC,CAAC;AAED,SAAS,UAAU,CAAC,MAA+B,EAAE,GAAwB;IAC5E,MAAM,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAA;IAC/B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAA;IAChF,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;IACtC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;AAC9E,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC9B,IAAI,CAAC;QACJ,MAAM,KAAK,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACvC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;YAC1E,CAAC,CAAE,KAAiC;YACpC,CAAC,CAAC,SAAS,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAA;IACjB,CAAC;AACF,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,0BAA0B,CACzC,IAAY,EACZ,KAAa,EACb,UAAkD,EAAE;IAEpD,MAAM,eAAe,GAAG,IAAI,KAAK,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,EAAE,CAAA;IAC3D,IAAI,eAAe;QAAE,MAAM,CAAC,GAAG,EAAE,CAAA;IACjC,yFAAyF;IACzF,yFAAyF;IACzF,+FAA+F;IAC/F,MAAM,aAAa,GAClB,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,SAAS,CAAA;IAC/E,IAAI,aAAa;QAAE,MAAM,CAAC,IAAI,CAAC,QAAkB,CAAC,CAAA;IAClD,MAAM,QAAQ,GAAG,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,EAAE,IAAI,CAAC,aAAa,CAAA;IAE5E,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IACpD,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,SAAS,CAAC,CAAA;IACjE,IAAI,WAAW,KAAK,SAAS,IAAI,OAAO,WAAW,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACtE,OAAO;YACN,OAAO,EAAE,EAAE;YACX,MAAM,EAAE,IAAI;YACZ,QAAQ;YACR,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,mBAAmB,CAAC,KAAK,CAAC;YACpC,eAAe;YACf,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,SAAS,CAA4B;SACrF,CAAA;IACF,CAAC;IAED,MAAM,OAAO,GAAmC,EAAE,CAAA;IAClD,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,QAAQ,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACzC,IAAI,QAA4B,CAAA;IAChC,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,IAAI,SAAS,GAAG,KAAK,CAAA;IACrB,IAAI,QAA4B,CAAA;IAChC,MAAM,QAAQ,GAAG,GAAS,EAAE;QAC3B,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,SAAS,CAAC;YAAE,QAAQ,KAAK,QAAQ,CAAA;QAChF,QAAQ,GAAG,SAAS,CAAA;QACpB,QAAQ,GAAG,CAAC,CAAA;QACZ,SAAS,GAAG,KAAK,CAAA;IAClB,CAAC,CAAA;IAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAW,CAAA;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;QACxB,MAAM,MAAM,GACX,MAAM,KAAK,SAAS;YACpB,MAAM,CAAC,GAAG,KAAK,OAAO,GAAG,CAAC;YAC1B,MAAM,CAAC,IAAI,KAAK,QAAQ;YACxB,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,IAAI,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC,CAAA;QAClC,MAAM,UAAU,GACf,MAAM;YACN,CAAC,KAAK;gBACL,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK;gBACzD,CAAC,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,CAAC,CAAA;QAC5D,IAAI,UAAU,EAAE,CAAC;YAChB,QAAQ,EAAE,CAAA;YACV,OAAO,CAAC,IAAI,CAAC,MAAiD,CAAC,CAAA;YAC/D,OAAO,GAAG,MAAM,CAAC,GAAa,CAAA;YAC9B,QAAQ,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;YACxC,SAAQ;QACT,CAAC;QACD,IAAI,QAAQ,KAAK,SAAS;YAAE,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAA;QAC5C,QAAQ,EAAE,CAAA;QACV,IAAI,MAAM,KAAK,SAAS;YAAE,SAAS,GAAG,IAAI,CAAA;IAC3C,CAAC;IACD,mFAAmF;IACnF,0EAA0E;IAC1E,QAAQ,EAAE,CAAA;IAEV,OAAO;QACN,OAAO;QACP,MAAM,EAAE,KAAK;QACb,QAAQ;QACR,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/C,OAAO;QACP,QAAQ;QACR,eAAe;QACf,SAAS,EAAE,EAAE;KACb,CAAA;AACF,CAAC;AAED,SAAS,SAAS,CAAC,MAAqC;IACvD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI,CAAA;AAChG,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAA+B;IACjE,MAAM,OAAO,GAAG,IAAI,GAAG,EAGpB,CAAA;IACH,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAA;IAChC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAA;IACjC,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC7C,IAAI,WAAW,GAAG,CAAC,CAAA;IACnB,IAAI,YAAgC,CAAA;IACpC,IAAI,cAAc,GAAwC,YAAY,CAAA;IAEtE,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACtC,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YACnC,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,CAAA;YACtC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAA;YAClC,cAAc,GAAG,YAAY,CAAA;YAC7B,WAAW,CAAC,KAAK,EAAE,CAAA;YACnB,SAAQ;QACT,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YACpC,cAAc,GAAG,MAAM,CAAC,MAAM,CAAA;YAC9B,SAAQ;QACT,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe;YAAE,SAAQ;QAChF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,CAAA;QAC7B,IAAI,IAAI,GAAG,WAAW,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;YAAE,SAAQ;QAC1D,IAAI,MAAM,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACrC,IAAI,MAAM,CAAC,GAAG,KAAK,SAAS;gBAAE,SAAQ;YACtC,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAA;YACtD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACpB,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;gBAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACvD,SAAQ;QACT,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAA;QACpE,IAAI,GAAG,KAAK,SAAS;YAAE,SAAQ;QAC/B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACb,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;gBAChB,KAAK,EAAE,MAAM,CAAC,MAAM;gBACpB,IAAI;gBACJ,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,GAAG,CAAC,MAAM,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACzF,CAAC,CAAA;YACF,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAClB,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACpB,CAAC;aAAM,IAAI,MAAM,CAAC,KAAK,KAAK,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,IAAI,EAAE,CAAC;YAC/D,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACnB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;aAAM,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,EAAE,CAAC;YACxC,sEAAsE;YACtE,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACpB,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACnB,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACnB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAChB,CAAC;IACF,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,QAAQ,CAAC,IAAI,CACZ,kFAAkF,CAClF,CAAA;IACF,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACpC,QAAQ,CAAC,IAAI,CACZ,gDAAgD,OAAO,CAAC,QAAQ,6EAA6E,CAC7I,CAAA;IACF,CAAC;IACD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,aAAa,CAAC,CAAA;IAC/E,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO;QAAE,QAAQ,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAA;IAE9F,OAAO;QACN,IAAI,EAAE,WAAW,GAAG,CAAC;QACrB,OAAO;QACP,IAAI;QACJ,MAAM;QACN,OAAO;QACP,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,cAAc;QACd,QAAQ;QACR,SAAS,EAAE,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO;QACrC,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzE,CAAA;AACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/execution/workflow/runtime.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,WAAW,EAAkB,MAAM,0BAA0B,CAAA;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/execution/workflow/runtime.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAa,WAAW,EAAkB,MAAM,0BAA0B,CAAA;AAStF,OAAO,KAAK,EAQX,cAAc,EACd,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EAEjB,MAAM,YAAY,CAAA;AAEnB,uCAAuC;AACvC,eAAO,MAAM,kBAAkB,UAAU,CAAA;AAoBzC,sHAAsH;AACtH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGvE;AASD,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,cAAmB,GAAG,sBAAsB,CAqCzF;AAuHD,MAAM,WAAW,sBAAsB;IACtC,4FAA4F;IAC5F,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAA;IAClC,oCAAoC;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;IAC3B,qGAAqG;IACrG,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAC/B;AAkCD;;;;;;;;;;GAUG;AACH,qBAAa,eAAe;IAGf,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;gBAEL,OAAO,GAAE,sBAA2B;IAI3D,GAAG,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC;CAwnBlE"}
|
|
@@ -7,6 +7,7 @@ import { preview, sha256 } from './journal.js';
|
|
|
7
7
|
import { splitWorkflowScript } from './meta.js';
|
|
8
8
|
import { PhaseRegistry, summarizeWorkflowPhases } from './phases.js';
|
|
9
9
|
import { buildPrelude, preludeLineCount } from './prelude.js';
|
|
10
|
+
import { workflowCallContent, workflowCallKey } from './resume.js';
|
|
10
11
|
import { parseJsonText, validateAgainstSchema } from './schema.js';
|
|
11
12
|
/** The one capability a script has. */
|
|
12
13
|
export const WORKFLOW_HOST_CALL = 'agent';
|
|
@@ -47,7 +48,9 @@ export function resolveWorkflowLimits(limits = {}) {
|
|
|
47
48
|
memoryLimitBytes: integer('memoryLimitBytes', limits.memoryLimitBytes ?? 64 * 1024 * 1024, 16 * 1024 * 1024, 256 * 1024 * 1024),
|
|
48
49
|
maxValueBytes: integer('maxValueBytes', limits.maxValueBytes ?? 1024 * 1024, 1, 16 * 1024 * 1024),
|
|
49
50
|
...(limits.tokenBudget !== undefined
|
|
50
|
-
? {
|
|
51
|
+
? {
|
|
52
|
+
tokenBudget: integer('tokenBudget', limits.tokenBudget, 1, Number.MAX_SAFE_INTEGER),
|
|
53
|
+
}
|
|
51
54
|
: {}),
|
|
52
55
|
maxDurationMs: integer('maxDurationMs', limits.maxDurationMs ?? 6 * 3_600_000, 1, 2_147_483_647),
|
|
53
56
|
cpuSliceMs: integer('cpuSliceMs', limits.cpuSliceMs ?? 2_000, 1, 2_147_483_647),
|
|
@@ -176,6 +179,10 @@ export class WorkflowRuntime {
|
|
|
176
179
|
const now = this.now;
|
|
177
180
|
const runId = options.runId ?? `w${[...randomBytes(8)].map((b) => (b % 36).toString(36)).join('')}`;
|
|
178
181
|
const startedAt = now();
|
|
182
|
+
const pass = options.resume?.pass ?? 1;
|
|
183
|
+
const resume = options.resume;
|
|
184
|
+
let latch = false;
|
|
185
|
+
const seenContent = new Map();
|
|
179
186
|
const phases = new PhaseRegistry();
|
|
180
187
|
const agents = new Map();
|
|
181
188
|
const inFlight = new Set();
|
|
@@ -232,7 +239,13 @@ export class WorkflowRuntime {
|
|
|
232
239
|
declared,
|
|
233
240
|
at,
|
|
234
241
|
});
|
|
235
|
-
journal({
|
|
242
|
+
journal({
|
|
243
|
+
type: 'phase',
|
|
244
|
+
at,
|
|
245
|
+
index: phase.index,
|
|
246
|
+
title: phase.title,
|
|
247
|
+
declared,
|
|
248
|
+
});
|
|
236
249
|
}
|
|
237
250
|
return phase;
|
|
238
251
|
};
|
|
@@ -258,6 +271,7 @@ export class WorkflowRuntime {
|
|
|
258
271
|
...(agent.resultPreview !== undefined ? { resultPreview: agent.resultPreview } : {}),
|
|
259
272
|
...(agent.error !== undefined ? { error: agent.error } : {}),
|
|
260
273
|
...(agent.skipped ? { skipped: true } : {}),
|
|
274
|
+
...(agent.cached !== undefined ? { cached: true } : {}),
|
|
261
275
|
});
|
|
262
276
|
// FIFO admission: an agent starts when fewer than maxConcurrency run.
|
|
263
277
|
const acquire = (agent) => {
|
|
@@ -333,11 +347,26 @@ export class WorkflowRuntime {
|
|
|
333
347
|
value = null;
|
|
334
348
|
}
|
|
335
349
|
emit(agentEvent(agent));
|
|
350
|
+
const finalState = agent.state === 'error' ? 'error' : agent.skipped ? 'skipped' : 'done';
|
|
351
|
+
let saved;
|
|
352
|
+
if (finalState === 'done' && value !== null && agent.cached === undefined) {
|
|
353
|
+
try {
|
|
354
|
+
saved = { result: JSON.parse(JSON.stringify(value)) };
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
saved = { unsaved: true };
|
|
358
|
+
journal({
|
|
359
|
+
type: 'log',
|
|
360
|
+
at,
|
|
361
|
+
message: "An agent's result could not be saved, so a resume will run it again.",
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
336
365
|
journal({
|
|
337
366
|
type: 'agent_outcome',
|
|
338
367
|
at,
|
|
339
368
|
index: agent.index,
|
|
340
|
-
state:
|
|
369
|
+
state: finalState,
|
|
341
370
|
tokens: agent.tokens,
|
|
342
371
|
toolCalls: agent.toolCalls,
|
|
343
372
|
queuedAt: agent.queuedAt,
|
|
@@ -345,12 +374,30 @@ export class WorkflowRuntime {
|
|
|
345
374
|
finishedAt: at,
|
|
346
375
|
...(agent.resultPreview !== undefined ? { resultPreview: agent.resultPreview } : {}),
|
|
347
376
|
...(agent.error !== undefined ? { error: agent.error } : {}),
|
|
377
|
+
...(agent.key !== undefined ? { key: agent.key } : {}),
|
|
378
|
+
pass,
|
|
379
|
+
...(agent.cached !== undefined
|
|
380
|
+
? {
|
|
381
|
+
cached: true,
|
|
382
|
+
resultFrom: {
|
|
383
|
+
pass: agent.cached.pass,
|
|
384
|
+
index: agent.cached.index,
|
|
385
|
+
},
|
|
386
|
+
}
|
|
387
|
+
: {}),
|
|
388
|
+
...(saved ?? {}),
|
|
389
|
+
...(outcome.interrupted === true && finalState === 'error'
|
|
390
|
+
? { interrupted: true }
|
|
391
|
+
: {}),
|
|
392
|
+
...(agent.childSessionId !== undefined ? { childSessionId: agent.childSessionId } : {}),
|
|
348
393
|
});
|
|
349
394
|
return { ok: true, value: { v: value, t: totalTokens() } };
|
|
350
395
|
};
|
|
351
396
|
const interpret = (agent, call, outcome) => {
|
|
352
397
|
agent.tokens = count(outcome.tokens);
|
|
353
398
|
agent.toolCalls = count(outcome.toolCalls);
|
|
399
|
+
if (outcome.sessionId !== undefined)
|
|
400
|
+
agent.childSessionId = outcome.sessionId;
|
|
354
401
|
if (agent.userSkipped || outcome.state === 'skipped') {
|
|
355
402
|
return settle(agent, { state: 'done', skipped: true });
|
|
356
403
|
}
|
|
@@ -358,10 +405,14 @@ export class WorkflowRuntime {
|
|
|
358
405
|
return settle(agent, {
|
|
359
406
|
state: 'error',
|
|
360
407
|
error: 'The workflow was stopped before this agent finished.',
|
|
408
|
+
interrupted: true,
|
|
361
409
|
});
|
|
362
410
|
}
|
|
363
411
|
if (outcome.state === 'error') {
|
|
364
|
-
return settle(agent, {
|
|
412
|
+
return settle(agent, {
|
|
413
|
+
state: 'error',
|
|
414
|
+
error: outcome.error ?? 'The agent failed.',
|
|
415
|
+
});
|
|
365
416
|
}
|
|
366
417
|
if (call.schema === undefined) {
|
|
367
418
|
return settle(agent, { state: 'done', value: outcome.text ?? '' });
|
|
@@ -396,6 +447,16 @@ export class WorkflowRuntime {
|
|
|
396
447
|
return { ok: false, error: reason };
|
|
397
448
|
}
|
|
398
449
|
const index = ++requested;
|
|
450
|
+
const contentId = workflowCallContent(call.prompt, call);
|
|
451
|
+
const ordinal = seenContent.get(contentId) ?? 0;
|
|
452
|
+
seenContent.set(contentId, ordinal + 1);
|
|
453
|
+
const key = workflowCallKey(call.prompt, call, ordinal);
|
|
454
|
+
const hit = latch ? undefined : resume?.results.get(key);
|
|
455
|
+
if (resume !== undefined &&
|
|
456
|
+
hit === undefined &&
|
|
457
|
+
!(resume.seen.has(key) && !resume.failed.has(key) && !resume.demoted.has(key))) {
|
|
458
|
+
latch = true;
|
|
459
|
+
}
|
|
399
460
|
const phaseTitle = call.phase ?? call.cursor;
|
|
400
461
|
const phase = phaseTitle?.trim() ? announce(phaseTitle, false) : undefined;
|
|
401
462
|
const queuedAt = now();
|
|
@@ -414,13 +475,27 @@ export class WorkflowRuntime {
|
|
|
414
475
|
toolCalls: 0,
|
|
415
476
|
skipped: false,
|
|
416
477
|
userSkipped: false,
|
|
478
|
+
key,
|
|
417
479
|
};
|
|
418
480
|
agents.set(index, agent);
|
|
481
|
+
if (hit !== undefined) {
|
|
482
|
+
agent.cached = {
|
|
483
|
+
pass: hit.pass,
|
|
484
|
+
index: hit.index,
|
|
485
|
+
...(hit.childSessionId !== undefined ? { childSessionId: hit.childSessionId } : {}),
|
|
486
|
+
};
|
|
487
|
+
if (hit.childSessionId !== undefined)
|
|
488
|
+
agent.childSessionId = hit.childSessionId;
|
|
489
|
+
agent.startedAt = queuedAt;
|
|
490
|
+
}
|
|
419
491
|
emit(agentEvent(agent));
|
|
420
492
|
journal({
|
|
421
493
|
type: 'agent_request',
|
|
422
494
|
at: queuedAt,
|
|
423
495
|
index,
|
|
496
|
+
key,
|
|
497
|
+
pass,
|
|
498
|
+
...(hit !== undefined ? { cached: true } : {}),
|
|
424
499
|
label: agent.label,
|
|
425
500
|
...(phase ? { phaseIndex: phase.index, phaseTitle: phase.title } : {}),
|
|
426
501
|
promptPreview: preview(call.prompt),
|
|
@@ -432,6 +507,12 @@ export class WorkflowRuntime {
|
|
|
432
507
|
schema: call.schema !== undefined,
|
|
433
508
|
},
|
|
434
509
|
});
|
|
510
|
+
if (hit !== undefined) {
|
|
511
|
+
return settle(agent, {
|
|
512
|
+
state: 'done',
|
|
513
|
+
value: structuredClone(hit.value),
|
|
514
|
+
});
|
|
515
|
+
}
|
|
435
516
|
const admitted = await acquire(agent);
|
|
436
517
|
if (!admitted) {
|
|
437
518
|
return agent.userSkipped
|
|
@@ -439,6 +520,7 @@ export class WorkflowRuntime {
|
|
|
439
520
|
: settle(agent, {
|
|
440
521
|
state: 'error',
|
|
441
522
|
error: 'The workflow was stopped before this agent started.',
|
|
523
|
+
interrupted: true,
|
|
442
524
|
});
|
|
443
525
|
}
|
|
444
526
|
try {
|
|
@@ -446,6 +528,7 @@ export class WorkflowRuntime {
|
|
|
446
528
|
return settle(agent, {
|
|
447
529
|
state: 'error',
|
|
448
530
|
error: `Not started: the token budget for this workflow (${limits.tokenBudget} tokens) is spent.`,
|
|
531
|
+
interrupted: true,
|
|
449
532
|
});
|
|
450
533
|
}
|
|
451
534
|
if (controller.signal.aborted || agent.userSkipped) {
|
|
@@ -454,6 +537,7 @@ export class WorkflowRuntime {
|
|
|
454
537
|
: settle(agent, {
|
|
455
538
|
state: 'error',
|
|
456
539
|
error: 'The workflow was stopped before this agent started.',
|
|
540
|
+
interrupted: true,
|
|
457
541
|
});
|
|
458
542
|
}
|
|
459
543
|
agent.startedAt = now();
|
|
@@ -526,7 +610,7 @@ export class WorkflowRuntime {
|
|
|
526
610
|
// --- start ---
|
|
527
611
|
if (options.journal?.writeScript) {
|
|
528
612
|
try {
|
|
529
|
-
await options.journal.writeScript(options.script, sha256(options.script));
|
|
613
|
+
await options.journal.writeScript(options.script, sha256(options.script), pass);
|
|
530
614
|
}
|
|
531
615
|
catch (error) {
|
|
532
616
|
journalError = error instanceof Error ? error.message : String(error);
|
|
@@ -541,6 +625,16 @@ export class WorkflowRuntime {
|
|
|
541
625
|
meta,
|
|
542
626
|
args,
|
|
543
627
|
limits,
|
|
628
|
+
...(resume !== undefined
|
|
629
|
+
? {
|
|
630
|
+
resume: {
|
|
631
|
+
pass,
|
|
632
|
+
previousFinish: resume.previousFinish,
|
|
633
|
+
scriptSha256Changed: resume.scriptSha256 !== undefined && resume.scriptSha256 !== sha256(options.script),
|
|
634
|
+
},
|
|
635
|
+
}
|
|
636
|
+
: {}),
|
|
637
|
+
...(options.scriptPath !== undefined ? { scriptPath: options.scriptPath } : {}),
|
|
544
638
|
});
|
|
545
639
|
emit({
|
|
546
640
|
type: 'workflow_started',
|
|
@@ -560,7 +654,11 @@ export class WorkflowRuntime {
|
|
|
560
654
|
maxHostCalls: limits.maxAgents + 100,
|
|
561
655
|
maxPendingHostCalls: limits.maxAgents + 100,
|
|
562
656
|
});
|
|
563
|
-
const preludeConfig = {
|
|
657
|
+
const preludeConfig = {
|
|
658
|
+
args,
|
|
659
|
+
tokenLimit: limits.tokenBudget ?? null,
|
|
660
|
+
deterministic: options.deterministic === true,
|
|
661
|
+
};
|
|
564
662
|
const runResult = await codeRuntime.run({
|
|
565
663
|
source: `${buildPrelude(preludeConfig)}\n${body}`,
|
|
566
664
|
allowedCalls: [WORKFLOW_HOST_CALL],
|
|
@@ -571,7 +669,10 @@ export class WorkflowRuntime {
|
|
|
571
669
|
onOutput,
|
|
572
670
|
onHostCall: (request) => {
|
|
573
671
|
if (request.name !== WORKFLOW_HOST_CALL) {
|
|
574
|
-
return Promise.resolve({
|
|
672
|
+
return Promise.resolve({
|
|
673
|
+
ok: false,
|
|
674
|
+
error: `Unknown host call "${request.name}".`,
|
|
675
|
+
});
|
|
575
676
|
}
|
|
576
677
|
let call;
|
|
577
678
|
try {
|
|
@@ -634,7 +735,7 @@ export class WorkflowRuntime {
|
|
|
634
735
|
const failedAgents = begun.filter((a) => a.state === 'error').length;
|
|
635
736
|
const progress = begun.length === 0
|
|
636
737
|
? 'No agent had started.'
|
|
637
|
-
: `Before it failed: ${begun.length} agent${begun.length === 1 ? '' : 's'} started, ${finished} finished, ${failedAgents} failed. A rerun starts the whole script again, so finished agents run again
|
|
738
|
+
: `Before it failed: ${begun.length} agent${begun.length === 1 ? '' : 's'} started, ${finished} finished, ${failedAgents} failed. ${options.canResume === true ? 'Resume the run to continue: agents whose prompt and options are unchanged return their saved results.' : 'A rerun starts the whole script again, so finished agents run again.'}`;
|
|
638
739
|
error = `${describeScriptFailure(outcome, body, preludeLineCount(preludeConfig))}\n${progress}${scriptPhase !== undefined ? ` Last phase: "${scriptPhase}".` : ''}`;
|
|
639
740
|
}
|
|
640
741
|
const all = [...agents.values()];
|
|
@@ -646,6 +747,9 @@ export class WorkflowRuntime {
|
|
|
646
747
|
tokens: all.reduce((sum, a) => sum + a.tokens, 0),
|
|
647
748
|
toolCalls: all.reduce((sum, a) => sum + a.toolCalls, 0),
|
|
648
749
|
elapsedMs: Math.max(0, now() - startedAt),
|
|
750
|
+
...(all.some((a) => a.cached !== undefined)
|
|
751
|
+
? { cachedAgents: all.filter((a) => a.cached !== undefined).length }
|
|
752
|
+
: {}),
|
|
649
753
|
};
|
|
650
754
|
const at = now();
|
|
651
755
|
emit({
|