@burtson-labs/agent-core 1.6.40 → 1.6.42
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/dist/graph/envelopes.d.ts +48 -0
- package/dist/graph/envelopes.d.ts.map +1 -0
- package/dist/graph/envelopes.js +46 -0
- package/dist/graph/envelopes.js.map +1 -0
- package/dist/graph/index.d.ts +1 -0
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/index.js +1 -0
- package/dist/graph/index.js.map +1 -1
- package/dist/graph/loopNode.d.ts.map +1 -1
- package/dist/graph/loopNode.js +6 -0
- package/dist/graph/loopNode.js.map +1 -1
- package/dist/graph/scheduler.d.ts +15 -1
- package/dist/graph/scheduler.d.ts.map +1 -1
- package/dist/graph/scheduler.js +41 -2
- package/dist/graph/scheduler.js.map +1 -1
- package/dist/graph/types.d.ts +35 -0
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/graph/types.js +10 -0
- package/dist/graph/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 6 — per-node capability envelopes.
|
|
3
|
+
*
|
|
4
|
+
* An envelope narrows what a NODE may do, independent of what the host's
|
|
5
|
+
* global permission model allows. The two compose, and the layering is
|
|
6
|
+
* deliberate:
|
|
7
|
+
*
|
|
8
|
+
* - agent-core (here) provides the MECHANISM: a declarative, serializable
|
|
9
|
+
* envelope (tool-name allow/deny) evaluated as a beforeToolExecute-style
|
|
10
|
+
* gate, plus gate composition. No policy knowledge — this package doesn't
|
|
11
|
+
* know what "plan mode" or "risk tier" means.
|
|
12
|
+
* - hosts provide the POLICY: the CLI/extension inject their host-kit
|
|
13
|
+
* permission gate (mode + risk classification) per node via loop options;
|
|
14
|
+
* `composeGates` runs envelope first, host gate second, first deny wins.
|
|
15
|
+
*
|
|
16
|
+
* So "verification nodes run read-only" is spelled: give the verify node an
|
|
17
|
+
* envelope allowing only read tools — enforced in-core — while the host's own
|
|
18
|
+
* plan/auto gate still applies on top. A node can only ever be NARROWER than
|
|
19
|
+
* the host allows, never wider: an envelope has no allow-override power, it
|
|
20
|
+
* can only deny.
|
|
21
|
+
*/
|
|
22
|
+
import type { NodeEnvelope } from './types';
|
|
23
|
+
/** Same shape the tool loop's beforeToolExecute uses — kept structural so the
|
|
24
|
+
* graph module doesn't import loop types it doesn't need. */
|
|
25
|
+
export type ToolGate = (call: {
|
|
26
|
+
name: string;
|
|
27
|
+
params: Record<string, string>;
|
|
28
|
+
}) => Promise<{
|
|
29
|
+
allow: boolean;
|
|
30
|
+
reason?: string;
|
|
31
|
+
}> | {
|
|
32
|
+
allow: boolean;
|
|
33
|
+
reason?: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Build a gate from a declarative envelope.
|
|
37
|
+
* - `denyTools` always blocks its entries (deny wins over allow).
|
|
38
|
+
* - `allowTools`, when present, blocks everything NOT listed.
|
|
39
|
+
* - No envelope / empty envelope = allow everything (the host gate still runs).
|
|
40
|
+
*/
|
|
41
|
+
export declare function envelopeGate(envelope: NodeEnvelope | undefined): ToolGate;
|
|
42
|
+
/**
|
|
43
|
+
* Compose gates left → right: the first deny wins (its reason surfaces), a
|
|
44
|
+
* call must pass every gate to run. Undefined entries are skipped so callers
|
|
45
|
+
* can pass optional host gates without branching.
|
|
46
|
+
*/
|
|
47
|
+
export declare function composeGates(...gates: Array<ToolGate | undefined>): ToolGate;
|
|
48
|
+
//# sourceMappingURL=envelopes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelopes.d.ts","sourceRoot":"","sources":["../../src/graph/envelopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C;8DAC8D;AAC9D,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,KAC1E,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5C;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,QAAQ,CAkBzE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,QAAQ,CAS5E"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.envelopeGate = envelopeGate;
|
|
4
|
+
exports.composeGates = composeGates;
|
|
5
|
+
/**
|
|
6
|
+
* Build a gate from a declarative envelope.
|
|
7
|
+
* - `denyTools` always blocks its entries (deny wins over allow).
|
|
8
|
+
* - `allowTools`, when present, blocks everything NOT listed.
|
|
9
|
+
* - No envelope / empty envelope = allow everything (the host gate still runs).
|
|
10
|
+
*/
|
|
11
|
+
function envelopeGate(envelope) {
|
|
12
|
+
const deny = new Set(envelope?.denyTools ?? []);
|
|
13
|
+
const allow = envelope?.allowTools ? new Set(envelope.allowTools) : null;
|
|
14
|
+
return (call) => {
|
|
15
|
+
if (deny.has(call.name)) {
|
|
16
|
+
return {
|
|
17
|
+
allow: false,
|
|
18
|
+
reason: `node envelope denies "${call.name}" — this node may not use that tool; work within its declared capabilities or report what you would have done.`
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (allow && !allow.has(call.name)) {
|
|
22
|
+
return {
|
|
23
|
+
allow: false,
|
|
24
|
+
reason: `node envelope allows only [${[...allow].join(', ')}] — "${call.name}" is outside this node's capabilities; use the allowed tools or report what you would have done.`
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return { allow: true };
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compose gates left → right: the first deny wins (its reason surfaces), a
|
|
32
|
+
* call must pass every gate to run. Undefined entries are skipped so callers
|
|
33
|
+
* can pass optional host gates without branching.
|
|
34
|
+
*/
|
|
35
|
+
function composeGates(...gates) {
|
|
36
|
+
const active = gates.filter((g) => typeof g === 'function');
|
|
37
|
+
return async (call) => {
|
|
38
|
+
for (const gate of active) {
|
|
39
|
+
const verdict = await gate(call);
|
|
40
|
+
if (!verdict.allow)
|
|
41
|
+
return verdict;
|
|
42
|
+
}
|
|
43
|
+
return { allow: true };
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=envelopes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelopes.js","sourceRoot":"","sources":["../../src/graph/envelopes.ts"],"names":[],"mappings":";;AAmCA,oCAkBC;AAOD,oCASC;AAxCD;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,QAAkC;IAC7D,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzE,OAAO,CAAC,IAAI,EAAE,EAAE;QACd,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,yBAAyB,IAAI,CAAC,IAAI,gHAAgH;aAC3J,CAAC;QACJ,CAAC;QACD,IAAI,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,8BAA8B,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,kGAAkG;aAC/K,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,YAAY,CAAC,GAAG,KAAkC;IAChE,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAiB,EAAE,CAAC,OAAO,CAAC,KAAK,UAAU,CAAC,CAAC;IAC3E,OAAO,KAAK,EAAE,IAAI,EAAE,EAAE;QACpB,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,CAAC,OAAO,CAAC,KAAK;gBAAE,OAAO,OAAO,CAAC;QACrC,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/graph/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC"}
|
package/dist/graph/index.js
CHANGED
|
@@ -18,4 +18,5 @@ __exportStar(require("./types"), exports);
|
|
|
18
18
|
__exportStar(require("./scheduler"), exports);
|
|
19
19
|
__exportStar(require("./loopNode"), exports);
|
|
20
20
|
__exportStar(require("./contracts"), exports);
|
|
21
|
+
__exportStar(require("./envelopes"), exports);
|
|
21
22
|
//# sourceMappingURL=index.js.map
|
package/dist/graph/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,8CAA4B;AAC5B,6CAA2B;AAC3B,8CAA4B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,8CAA4B;AAC5B,6CAA2B;AAC3B,8CAA4B;AAC5B,8CAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loopNode.d.ts","sourceRoot":"","sources":["../../src/graph/loopNode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAgB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"loopNode.d.ts","sourceRoot":"","sources":["../../src/graph/loopNode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACpF,OAAO,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAgB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG1E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,YAAY,CAAC;IACvB,GAAG,EAAE,oBAAoB,CAAC;IAC1B;kCAC8B;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,WAAW,CAAC,EAAE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;iEAC6D;IAC7D,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,CAAC;AAEhE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAWjE;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,GAAG,YAAY,CA2C/F"}
|
package/dist/graph/loopNode.js
CHANGED
|
@@ -10,6 +10,7 @@ exports.wrapLoopAsNode = wrapLoopAsNode;
|
|
|
10
10
|
* graph inspectable and retryable per-node later).
|
|
11
11
|
*/
|
|
12
12
|
const tool_use_loop_1 = require("../tools/tool-use-loop");
|
|
13
|
+
const envelopes_1 = require("./envelopes");
|
|
13
14
|
function defaultNodePrompt(base) {
|
|
14
15
|
return (ctx) => {
|
|
15
16
|
const upstreamIds = Object.keys(ctx.upstream);
|
|
@@ -48,8 +49,13 @@ function wrapLoopAsNode(deps, buildPrompt) {
|
|
|
48
49
|
}
|
|
49
50
|
callerEmit?.(type, payload);
|
|
50
51
|
};
|
|
52
|
+
// Phase 6: the node's envelope (from its spec, threaded via NodeRunContext)
|
|
53
|
+
// composes with any host-injected gate — envelope first, host policy
|
|
54
|
+
// second, first deny wins. The envelope can only narrow, never widen.
|
|
55
|
+
const gate = (0, envelopes_1.composeGates)((0, envelopes_1.envelopeGate)(nodeCtx.envelope), deps.loopOptions?.beforeToolExecute);
|
|
51
56
|
const loop = (0, tool_use_loop_1.createToolUseLoop)(deps.registry, deps.ctx, {
|
|
52
57
|
...(deps.loopOptions ?? {}),
|
|
58
|
+
beforeToolExecute: gate,
|
|
53
59
|
emitEvent,
|
|
54
60
|
signal: nodeCtx.signal,
|
|
55
61
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loopNode.js","sourceRoot":"","sources":["../../src/graph/loopNode.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"loopNode.js","sourceRoot":"","sources":["../../src/graph/loopNode.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* (Phase 7): graph:start, graph:node_start, graph:node_done,
|
|
22
22
|
* graph:node_failed, graph:node_skipped, graph:node_cancelled, graph:done.
|
|
23
23
|
*/
|
|
24
|
-
import { type GraphRunResult, type GraphSpec, type NodeExecutor } from './types';
|
|
24
|
+
import { type GraphCheckpoint, type GraphRunResult, type GraphSpec, type NodeExecutor } from './types';
|
|
25
25
|
export interface RunGraphOptions {
|
|
26
26
|
/** Cap on simultaneously running nodes. Default 2 (conservative). */
|
|
27
27
|
maxConcurrency?: number;
|
|
@@ -29,6 +29,20 @@ export interface RunGraphOptions {
|
|
|
29
29
|
signal?: AbortSignal;
|
|
30
30
|
/** Progress events — same shape as the tool loop's emitEvent. */
|
|
31
31
|
emitEvent?: (type: string, payload?: unknown) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Durability hook (Phase 5): called with a fresh checkpoint after every
|
|
34
|
+
* node settles and once at the end. Best-effort like the loop's
|
|
35
|
+
* onMessagesSnapshot — not awaited, a throw is swallowed; persistence
|
|
36
|
+
* must never stall or kill a run.
|
|
37
|
+
*/
|
|
38
|
+
onCheckpoint?: (checkpoint: GraphCheckpoint) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Resume a prior run: nodes 'done' in the checkpoint are restored without
|
|
41
|
+
* re-running (outputs/evidence flow to dependents; emits graph:node_restored);
|
|
42
|
+
* every other state re-runs — failures included, retrying them is the point.
|
|
43
|
+
* Throws if the checkpoint's spec fingerprint doesn't match this spec.
|
|
44
|
+
*/
|
|
45
|
+
resumeFrom?: GraphCheckpoint;
|
|
32
46
|
}
|
|
33
47
|
/** Executors per node id, or one executor shared by every node. */
|
|
34
48
|
export type GraphExecutors = NodeExecutor | Record<string, NodeExecutor>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/graph/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/graph/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,YAAY,EAElB,MAAM,SAAS,CAAC;AAGjB,MAAM,WAAW,eAAe;IAC9B,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2BAA2B;IAC3B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,iEAAiE;IACjE,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACtD;;;;;OAKG;IACH,YAAY,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD;;;;;OAKG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,mEAAmE;AACnE,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAEzE,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,SAAS,EACf,SAAS,EAAE,cAAc,EACzB,IAAI,GAAE,eAAoB,GACzB,OAAO,CAAC,cAAc,CAAC,CAoMzB"}
|
package/dist/graph/scheduler.js
CHANGED
|
@@ -47,10 +47,37 @@ async function runGraph(spec, executors, opts = {}) {
|
|
|
47
47
|
// node starts, not halfway through.
|
|
48
48
|
for (const node of spec.nodes)
|
|
49
49
|
executorFor(node.id);
|
|
50
|
+
const fingerprint = (0, types_1.graphFingerprint)(spec);
|
|
51
|
+
if (opts.resumeFrom && opts.resumeFrom.specFingerprint !== fingerprint) {
|
|
52
|
+
throw new Error('resume checkpoint does not match this graph (node ids/dependencies differ)');
|
|
53
|
+
}
|
|
50
54
|
const results = {};
|
|
51
55
|
for (const node of spec.nodes) {
|
|
52
|
-
|
|
56
|
+
const prior = opts.resumeFrom?.nodes[node.id];
|
|
57
|
+
if (prior && prior.state === 'done') {
|
|
58
|
+
// Restore completed work verbatim — the executor does NOT re-run, and
|
|
59
|
+
// dependents see the original output/evidence.
|
|
60
|
+
results[node.id] = { ...prior };
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
results[node.id] = { id: node.id, state: 'pending' };
|
|
64
|
+
}
|
|
53
65
|
}
|
|
66
|
+
const checkpoint = () => ({
|
|
67
|
+
version: 1,
|
|
68
|
+
specFingerprint: fingerprint,
|
|
69
|
+
// Deep-ish copy so a persisted checkpoint can't be mutated by the
|
|
70
|
+
// still-running scheduler between write and flush.
|
|
71
|
+
nodes: Object.fromEntries(Object.entries(results).map(([id, r]) => [id, { ...r }])),
|
|
72
|
+
});
|
|
73
|
+
const fireCheckpoint = () => {
|
|
74
|
+
try {
|
|
75
|
+
opts.onCheckpoint?.(checkpoint());
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
/* persistence must never stall or kill the run */
|
|
79
|
+
}
|
|
80
|
+
};
|
|
54
81
|
const dependents = new Map();
|
|
55
82
|
for (const node of spec.nodes) {
|
|
56
83
|
for (const dep of node.dependsOn ?? []) {
|
|
@@ -100,6 +127,7 @@ async function runGraph(spec, executors, opts = {}) {
|
|
|
100
127
|
nodeId: id,
|
|
101
128
|
signal: signal ?? new AbortController().signal,
|
|
102
129
|
upstream,
|
|
130
|
+
envelope: specOf.get(id)?.envelope,
|
|
103
131
|
});
|
|
104
132
|
// Phase 3: the node only counts as done if its completion contract
|
|
105
133
|
// holds. A violation is a FAILURE — "finished but produced nothing it
|
|
@@ -131,11 +159,19 @@ async function runGraph(spec, executors, opts = {}) {
|
|
|
131
159
|
record.endedAt = Date.now();
|
|
132
160
|
record.durationMs = record.endedAt - (record.startedAt ?? record.endedAt);
|
|
133
161
|
running.delete(id);
|
|
162
|
+
// Durability: snapshot after every settle so a crash between nodes
|
|
163
|
+
// loses at most the in-flight node's work.
|
|
164
|
+
fireCheckpoint();
|
|
134
165
|
}
|
|
135
166
|
})();
|
|
136
167
|
running.set(id, promise);
|
|
137
168
|
};
|
|
138
|
-
emit('graph:start', { nodes: spec.nodes.length, maxConcurrency });
|
|
169
|
+
emit('graph:start', { nodes: spec.nodes.length, maxConcurrency, resumed: Boolean(opts.resumeFrom) });
|
|
170
|
+
for (const node of spec.nodes) {
|
|
171
|
+
if (results[node.id].state === 'done' && opts.resumeFrom) {
|
|
172
|
+
emit('graph:node_restored', { id: node.id, label: labelOf.get(node.id), summary: results[node.id].summary });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
139
175
|
// Main pump: launch every ready node up to the cap, wait for one running
|
|
140
176
|
// node to settle, repeat. Skip-cascade runs each pass so a failure releases
|
|
141
177
|
// its blocked subtree immediately (as 'skipped', not stuck 'pending').
|
|
@@ -161,6 +197,9 @@ async function runGraph(spec, executors, opts = {}) {
|
|
|
161
197
|
emit('graph:node_cancelled', { id: node.id, label: labelOf.get(node.id) });
|
|
162
198
|
}
|
|
163
199
|
}
|
|
200
|
+
// Terminal snapshot — includes skips/cancels the per-settle checkpoints
|
|
201
|
+
// may not have seen.
|
|
202
|
+
fireCheckpoint();
|
|
164
203
|
const status = signal?.aborted
|
|
165
204
|
? 'cancelled'
|
|
166
205
|
: anyFailed
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/graph/scheduler.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/graph/scheduler.ts"],"names":[],"mappings":"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"}
|
package/dist/graph/types.d.ts
CHANGED
|
@@ -40,6 +40,15 @@ export interface CompletionContract {
|
|
|
40
40
|
outputMatches?: string;
|
|
41
41
|
requireEvidence?: EvidenceRequirement[];
|
|
42
42
|
}
|
|
43
|
+
/** Per-node capability envelope (Phase 6) — declarative tool-name bounds.
|
|
44
|
+
* `denyTools` always blocks; `allowTools`, when present, blocks everything
|
|
45
|
+
* not listed. An envelope can only NARROW what the host's own permission
|
|
46
|
+
* gate allows, never widen it. Plain data on purpose (planner-proposable,
|
|
47
|
+
* checkpoint-persistable). */
|
|
48
|
+
export interface NodeEnvelope {
|
|
49
|
+
allowTools?: string[];
|
|
50
|
+
denyTools?: string[];
|
|
51
|
+
}
|
|
43
52
|
/** One node in the DAG. */
|
|
44
53
|
export interface GraphNodeSpec {
|
|
45
54
|
/** Unique id within the graph. */
|
|
@@ -50,6 +59,8 @@ export interface GraphNodeSpec {
|
|
|
50
59
|
label?: string;
|
|
51
60
|
/** Completion contract enforced on this node's outcome. */
|
|
52
61
|
contract?: CompletionContract;
|
|
62
|
+
/** Capability envelope enforced while this node runs. */
|
|
63
|
+
envelope?: NodeEnvelope;
|
|
53
64
|
}
|
|
54
65
|
export interface GraphSpec {
|
|
55
66
|
nodes: GraphNodeSpec[];
|
|
@@ -80,6 +91,26 @@ export interface NodeResult {
|
|
|
80
91
|
durationMs?: number;
|
|
81
92
|
}
|
|
82
93
|
export type GraphRunStatus = 'completed' | 'failed' | 'cancelled';
|
|
94
|
+
/**
|
|
95
|
+
* Durable snapshot of a graph run (Phase 5). Emitted after every node
|
|
96
|
+
* settles; feed it back as `resumeFrom` to continue a dead run — nodes that
|
|
97
|
+
* were 'done' are RESTORED (executor not re-run, output/evidence available to
|
|
98
|
+
* dependents), everything else re-runs, including failures (retrying them is
|
|
99
|
+
* the point of resuming). JSON-serializable as long as node outputs are —
|
|
100
|
+
* hosts persist it however they like (the graph module never touches disk).
|
|
101
|
+
*/
|
|
102
|
+
export interface GraphCheckpoint {
|
|
103
|
+
version: 1;
|
|
104
|
+
/** Structural identity of the spec (node ids + deps). Resume refuses a
|
|
105
|
+
* checkpoint whose fingerprint doesn't match the current spec — resuming
|
|
106
|
+
* a DIFFERENT graph silently would corrupt, loudly beats wrongly. */
|
|
107
|
+
specFingerprint: string;
|
|
108
|
+
nodes: Record<string, NodeResult>;
|
|
109
|
+
}
|
|
110
|
+
/** Canonical structural identity: sorted [id → sorted deps] pairs. Label,
|
|
111
|
+
* contract, and envelope changes deliberately DON'T break resume — retrying
|
|
112
|
+
* with a tightened contract or envelope is a legitimate fix-and-resume. */
|
|
113
|
+
export declare function graphFingerprint(spec: GraphSpec): string;
|
|
83
114
|
export interface GraphRunResult {
|
|
84
115
|
status: GraphRunStatus;
|
|
85
116
|
/** Terminal result per node id — every node in the spec appears. */
|
|
@@ -93,6 +124,10 @@ export interface NodeRunContext {
|
|
|
93
124
|
signal: AbortSignal;
|
|
94
125
|
/** Terminal results of this node's direct dependencies (all state 'done'). */
|
|
95
126
|
upstream: Record<string, NodeResult>;
|
|
127
|
+
/** The node's capability envelope, threaded from its spec. Loop-wrapped
|
|
128
|
+
* executors enforce it automatically (see loopNode.ts); custom executors
|
|
129
|
+
* receive it here and are expected to honor it. */
|
|
130
|
+
envelope?: NodeEnvelope;
|
|
96
131
|
}
|
|
97
132
|
export type NodeExecutor = (ctx: NodeRunContext) => Promise<NodeOutcome> | NodeOutcome;
|
|
98
133
|
export interface GraphValidation {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;4EAC4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;kDAGkD;AAClD,MAAM,WAAW,kBAAkB;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACzC;AAED,2BAA2B;AAC3B,MAAM,WAAW,aAAa;IAC5B,kCAAkC;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"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"}
|
package/dist/graph/types.js
CHANGED
|
@@ -20,7 +20,17 @@
|
|
|
20
20
|
* Terminal states never transition again.
|
|
21
21
|
*/
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.graphFingerprint = graphFingerprint;
|
|
23
24
|
exports.validateGraph = validateGraph;
|
|
25
|
+
/** Canonical structural identity: sorted [id → sorted deps] pairs. Label,
|
|
26
|
+
* contract, and envelope changes deliberately DON'T break resume — retrying
|
|
27
|
+
* with a tightened contract or envelope is a legitimate fix-and-resume. */
|
|
28
|
+
function graphFingerprint(spec) {
|
|
29
|
+
const shape = [...spec.nodes]
|
|
30
|
+
.map((n) => [n.id, [...(n.dependsOn ?? [])].sort()])
|
|
31
|
+
.sort((a, b) => a[0].localeCompare(b[0]));
|
|
32
|
+
return JSON.stringify(shape);
|
|
33
|
+
}
|
|
24
34
|
/**
|
|
25
35
|
* Structural validation: duplicate ids, unknown/self dependencies, cycles.
|
|
26
36
|
* Kahn's algorithm for cycle detection — if a topological pass can't consume
|
package/dist/graph/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"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"}
|