@deepstrike/sdk 0.2.38 → 0.2.40
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/README.md +61 -31
- package/dist/collaboration/contract.d.ts +2 -2
- package/dist/collaboration/contract.js +2 -2
- package/dist/collaboration/handoff.d.ts +2 -14
- package/dist/collaboration/handoff.js +1 -17
- package/dist/collaboration/harness.d.ts +16 -47
- package/dist/collaboration/harness.js +57 -158
- package/dist/collaboration/index.d.ts +2 -2
- package/dist/collaboration/index.js +1 -2
- package/dist/collaboration/modes/creator-verifier.js +42 -6
- package/dist/collaboration/pool.d.ts +8 -0
- package/dist/collaboration/pool.js +56 -3
- package/dist/harness/harness.d.ts +97 -97
- package/dist/harness/harness.js +190 -144
- package/dist/harness/judge.d.ts +3 -2
- package/dist/harness/judge.js +7 -3
- package/dist/harness/public.d.ts +5 -3
- package/dist/harness/public.js +3 -2
- package/dist/index.d.ts +22 -7
- package/dist/index.js +8 -1
- package/dist/kernel.d.ts +12 -39
- package/dist/memory/agent.d.ts +8 -41
- package/dist/memory/agent.js +34 -117
- package/dist/memory/extraction.d.ts +4 -0
- package/dist/memory/extraction.js +79 -0
- package/dist/memory/in-memory-store.d.ts +28 -15
- package/dist/memory/in-memory-store.js +74 -25
- package/dist/memory/protocols.d.ts +56 -56
- package/dist/memory/protocols.js +1 -0
- package/dist/memory/public.d.ts +3 -1
- package/dist/memory/public.js +1 -0
- package/dist/memory/ranking.d.ts +33 -0
- package/dist/memory/ranking.js +77 -0
- package/dist/memory/retention.d.ts +17 -0
- package/dist/memory/retention.js +54 -0
- package/dist/os/public.d.ts +3 -3
- package/dist/os/public.js +1 -1
- package/dist/providers/base.d.ts +8 -0
- package/dist/providers/base.js +0 -0
- package/dist/providers/gemini.js +12 -0
- package/dist/providers/ollama.js +3 -1
- package/dist/providers/openai-responses.js +9 -2
- package/dist/providers/profiles.d.ts +5 -3
- package/dist/providers/profiles.js +3 -3
- package/dist/runtime/context-policy.d.ts +35 -0
- package/dist/runtime/context-policy.js +66 -0
- package/dist/runtime/eval.d.ts +6 -2
- package/dist/runtime/eval.js +2 -2
- package/dist/runtime/event-stream.d.ts +9 -0
- package/dist/runtime/event-stream.js +25 -11
- package/dist/runtime/execution-plane.d.ts +5 -1
- package/dist/runtime/execution-plane.js +9 -3
- package/dist/runtime/facade.js +2 -1
- package/dist/runtime/kernel-event-log.d.ts +0 -2
- package/dist/runtime/kernel-event-log.js +61 -13
- package/dist/runtime/kernel-primitives-dashboard.js +1 -1
- package/dist/runtime/kernel-rebuild.d.ts +13 -0
- package/dist/runtime/kernel-rebuild.js +75 -0
- package/dist/runtime/kernel-step.d.ts +157 -8
- package/dist/runtime/kernel-step.js +220 -7
- package/dist/runtime/kernel-transaction-log.d.ts +61 -0
- package/dist/runtime/kernel-transaction-log.js +149 -0
- package/dist/runtime/large-result-spool.d.ts +3 -1
- package/dist/runtime/large-result-spool.js +24 -5
- package/dist/runtime/loop-driver.d.ts +1 -1
- package/dist/runtime/loop-driver.js +2 -7
- package/dist/runtime/mcp-proxy-plane.d.ts +1 -0
- package/dist/runtime/mcp-proxy-plane.js +23 -6
- package/dist/runtime/os-profile.d.ts +9 -10
- package/dist/runtime/os-profile.js +14 -10
- package/dist/runtime/os-snapshot.d.ts +19 -0
- package/dist/runtime/os-snapshot.js +33 -3
- package/dist/runtime/process-sandbox-plane.js +16 -11
- package/dist/runtime/reaction-checkpoint.d.ts +51 -0
- package/dist/runtime/reaction-checkpoint.js +83 -0
- package/dist/runtime/reactive-session.d.ts +9 -3
- package/dist/runtime/reactive-session.js +44 -14
- package/dist/runtime/reliability.d.ts +48 -0
- package/dist/runtime/reliability.js +86 -0
- package/dist/runtime/remote-vpc-plane.js +4 -3
- package/dist/runtime/run-group.d.ts +38 -35
- package/dist/runtime/run-group.js +97 -54
- package/dist/runtime/runner.d.ts +117 -78
- package/dist/runtime/runner.js +1516 -1197
- package/dist/runtime/session-log.d.ts +71 -12
- package/dist/runtime/session-log.js +192 -32
- package/dist/runtime/session-repair.d.ts +11 -7
- package/dist/runtime/session-repair.js +11 -8
- package/dist/runtime/sub-agent-orchestrator.d.ts +6 -2
- package/dist/runtime/sub-agent-orchestrator.js +45 -18
- package/dist/signals/gateway.d.ts +23 -10
- package/dist/signals/gateway.js +81 -17
- package/dist/signals/scheduled.js +0 -1
- package/dist/signals/types.d.ts +21 -13
- package/dist/skills/loader.js +12 -2
- package/dist/tools/index.d.ts +2 -0
- package/dist/types/agent.d.ts +40 -1
- package/dist/types/agent.js +61 -1
- package/dist/types.d.ts +6 -1
- package/dist/workflow/public.d.ts +2 -3
- package/dist/workflow/public.js +0 -1
- package/package.json +2 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { agentRunSpecToKernel, findSpawnProcessObservation, spawnObservationToManifest } from "../types/agent.js";
|
|
2
2
|
import { FilteredExecutionPlane } from "./filtered-plane.js";
|
|
3
3
|
import { WorktreeExecutionPlane } from "./worktree-plane.js";
|
|
4
|
-
import {
|
|
4
|
+
import { durableKernelApply } from "./kernel-step.js";
|
|
5
5
|
function terminationFromStatus(status) {
|
|
6
6
|
const normalized = status.toLowerCase();
|
|
7
7
|
if (normalized === "completed" ||
|
|
@@ -142,6 +142,8 @@ export class SubAgentOrchestrator {
|
|
|
142
142
|
async *stream(ctx) {
|
|
143
143
|
const { childRunner, inheritEvents, cleanupWorktree } = await this.buildChild(ctx);
|
|
144
144
|
try {
|
|
145
|
+
if (ctx.contextInput)
|
|
146
|
+
childRunner.injectNote(ctx.contextInput);
|
|
145
147
|
yield* childRunner.run({
|
|
146
148
|
sessionId: ctx.spec.identity.sessionId,
|
|
147
149
|
goal: ctx.spec.goal,
|
|
@@ -154,22 +156,25 @@ export class SubAgentOrchestrator {
|
|
|
154
156
|
}
|
|
155
157
|
async run(ctx) {
|
|
156
158
|
if (ctx.harness) {
|
|
157
|
-
const {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
159
|
+
const { AttemptLoop, RuntimeAttemptBody } = await import("../harness/harness.js");
|
|
160
|
+
const { LlmEvalJudge } = await import("../harness/judge.js");
|
|
161
|
+
const { childRunner, inheritEvents, cleanupWorktree } = await this.buildChild(ctx);
|
|
162
|
+
if (ctx.contextInput)
|
|
163
|
+
childRunner.injectNote(ctx.contextInput);
|
|
164
|
+
const loop = new AttemptLoop({
|
|
165
|
+
body: new RuntimeAttemptBody(childRunner),
|
|
166
|
+
judge: new LlmEvalJudge(ctx.harness.evalProvider, false),
|
|
167
|
+
stop: { maxAttempts: ctx.harness.maxAttempts ?? 3 },
|
|
165
168
|
});
|
|
166
169
|
let outcome;
|
|
167
170
|
try {
|
|
168
171
|
outcome = await loop.run({
|
|
172
|
+
sessionId: ctx.spec.identity.sessionId,
|
|
169
173
|
goal: ctx.spec.goal,
|
|
170
174
|
criteria: (ctx.spec.milestones?.phases.flatMap(p => p.criteria) ?? [])
|
|
171
175
|
.filter((t) => typeof t === "string")
|
|
172
176
|
.map(text => ({ text, required: true })),
|
|
177
|
+
inheritEvents,
|
|
173
178
|
});
|
|
174
179
|
}
|
|
175
180
|
finally {
|
|
@@ -177,12 +182,7 @@ export class SubAgentOrchestrator {
|
|
|
177
182
|
}
|
|
178
183
|
return {
|
|
179
184
|
agentId: ctx.spec.identity.agentId,
|
|
180
|
-
result:
|
|
181
|
-
termination: outcome.passed ? "completed" : "error",
|
|
182
|
-
turnsUsed: outcome.iterations,
|
|
183
|
-
totalTokensUsed: outcome.totalTokens,
|
|
184
|
-
...(outcome.result ? { finalMessage: { role: "assistant", content: outcome.result, toolCalls: [] } } : {}),
|
|
185
|
-
},
|
|
185
|
+
result: attemptOutcomeToLoopResult(outcome),
|
|
186
186
|
// R3-1: surface nodes the agent submitted under the harness so `runWorkflow` appends them.
|
|
187
187
|
...(outcome.submittedNodes?.length ? { submittedNodes: outcome.submittedNodes } : {}),
|
|
188
188
|
};
|
|
@@ -219,8 +219,34 @@ export class SubAgentOrchestrator {
|
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
export const defaultSubAgentOrchestrator = new SubAgentOrchestrator();
|
|
222
|
+
export function attemptOutcomeToLoopResult(outcome) {
|
|
223
|
+
// H4: the run-health axis survives independently from the judge axis. A one-shot judge reject
|
|
224
|
+
// is a healthy completion carrying verdict=false; only exhausting the retry policy promotes the
|
|
225
|
+
// harness-level failure to a workflow error. A body run_error keeps its concrete kernel
|
|
226
|
+
// termination when valid, and normalizes non-kernel statuses (for example invalid_arg) to error.
|
|
227
|
+
const runTermination = terminationFromStatus(outcome.runStatus);
|
|
228
|
+
const termination = outcome.outcome === "exhausted"
|
|
229
|
+
? "error"
|
|
230
|
+
: outcome.outcome === "run_error" && runTermination !== "error" && runTermination !== "user_abort"
|
|
231
|
+
? "error"
|
|
232
|
+
: runTermination;
|
|
233
|
+
return {
|
|
234
|
+
termination,
|
|
235
|
+
...(outcome.result
|
|
236
|
+
? { finalMessage: { role: "assistant", content: outcome.result, toolCalls: [] } }
|
|
237
|
+
: {}),
|
|
238
|
+
turnsUsed: outcome.turns,
|
|
239
|
+
totalTokensUsed: outcome.totalTokens,
|
|
240
|
+
attempt: {
|
|
241
|
+
outcome: outcome.outcome,
|
|
242
|
+
runStatus: outcome.runStatus,
|
|
243
|
+
attempts: outcome.attempts,
|
|
244
|
+
...(outcome.verdict ? { verdict: outcome.verdict } : {}),
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
222
248
|
/** Kernel spawn without an active parent run loop (harness / coordinator use). */
|
|
223
|
-
export async function spawnStandalone(parentOpts, parentSessionId, spec, orchestrator = defaultSubAgentOrchestrator) {
|
|
249
|
+
export async function spawnStandalone(parentOpts, parentSessionId, spec, orchestrator = defaultSubAgentOrchestrator, contextInput) {
|
|
224
250
|
const kernel = (await import("../kernel.js")).getKernel();
|
|
225
251
|
const runtime = new kernel.KernelRuntime({
|
|
226
252
|
maxTokens: parentOpts.maxTokens,
|
|
@@ -228,8 +254,8 @@ export async function spawnStandalone(parentOpts, parentSessionId, spec, orchest
|
|
|
228
254
|
timeoutMs: parentOpts.timeoutMs !== undefined ? BigInt(parentOpts.timeoutMs) : undefined,
|
|
229
255
|
});
|
|
230
256
|
const pending = [];
|
|
231
|
-
|
|
232
|
-
const observations =
|
|
257
|
+
await durableKernelApply(runtime, parentOpts.sessionLog, parentSessionId, pending, { kind: "start_run", task: { goal: "coordinator", criteria: [] } });
|
|
258
|
+
const observations = await durableKernelApply(runtime, parentOpts.sessionLog, parentSessionId, pending, {
|
|
233
259
|
kind: "spawn_sub_agent",
|
|
234
260
|
spec: agentRunSpecToKernel(spec),
|
|
235
261
|
parent_session_id: parentSessionId,
|
|
@@ -256,5 +282,6 @@ export async function spawnStandalone(parentOpts, parentSessionId, spec, orchest
|
|
|
256
282
|
spec,
|
|
257
283
|
manifest,
|
|
258
284
|
sessionLog: parentOpts.sessionLog,
|
|
285
|
+
...(contextInput ? { contextInput } : {}),
|
|
259
286
|
});
|
|
260
287
|
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
|
-
import type { RuntimeSignal, SignalSource } from "./types.js";
|
|
1
|
+
import type { RuntimeSignal, SignalClaim, SignalDeliveryReceipt, SignalSource } from "./types.js";
|
|
2
2
|
import type { ScheduledPrompt } from "./scheduled.js";
|
|
3
|
+
import type { ObserverErrorHandler } from "../runtime/reliability.js";
|
|
4
|
+
export interface SignalGatewayOptions {
|
|
5
|
+
onObserverError?: ObserverErrorHandler;
|
|
6
|
+
/** Injectable wall clock for deterministic lease tests. */
|
|
7
|
+
now?: () => number;
|
|
8
|
+
/** Default claim lease. Must be positive. Default: 30 seconds. */
|
|
9
|
+
defaultLeaseMs?: number;
|
|
10
|
+
}
|
|
3
11
|
/**
|
|
4
12
|
* SignalGateway — entry point for all external signals into the agent.
|
|
5
13
|
*
|
|
6
14
|
* Implements `SignalSource` so it can be passed directly to `AgentOptions.signalSource`.
|
|
7
|
-
* The gateway maintains an internal FIFO queue
|
|
8
|
-
* on each agent turn.
|
|
15
|
+
* The gateway maintains an internal FIFO queue and exposes claim/ack/nack delivery leases.
|
|
9
16
|
*
|
|
10
17
|
* Responsibilities:
|
|
11
18
|
* - Cron scheduling: fires ScheduledPrompts at the right wall-clock time (idempotent by goal+time)
|
|
@@ -13,16 +20,19 @@ import type { ScheduledPrompt } from "./scheduled.js";
|
|
|
13
20
|
* - Listener API: `onSignal()` for side-channel observers that don't need the pull interface
|
|
14
21
|
*/
|
|
15
22
|
export declare class SignalGateway implements SignalSource {
|
|
23
|
+
private readonly opts;
|
|
16
24
|
private timers;
|
|
17
25
|
private queue;
|
|
18
26
|
private listeners;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
private deliverySeq;
|
|
28
|
+
private leaseSeq;
|
|
29
|
+
constructor(opts?: SignalGatewayOptions);
|
|
30
|
+
/** Claim one visible signal without deleting it. Unacked claims are redelivered after expiry. */
|
|
31
|
+
claimSignal(recipient?: string, leaseMs?: number): Promise<SignalClaim | null>;
|
|
32
|
+
/** Permanently remove the delivery iff the receipt still owns its current lease. */
|
|
33
|
+
ackSignal(receipt: SignalDeliveryReceipt): Promise<boolean>;
|
|
34
|
+
/** Release the current lease for immediate retry. Stale receipts are ignored. */
|
|
35
|
+
nackSignal(receipt: SignalDeliveryReceipt): Promise<boolean>;
|
|
26
36
|
/** Register a listener that is called synchronously whenever a signal is emitted.
|
|
27
37
|
* Returns an unsubscribe function — long-lived consumers (e.g. a loop's
|
|
28
38
|
* `signalAwareSleeper`, re-registered per sleep) must call it or the listener leaks. */
|
|
@@ -33,9 +43,12 @@ export declare class SignalGateway implements SignalSource {
|
|
|
33
43
|
cancel(goal: string, runAtMs: number): void;
|
|
34
44
|
/** Push a raw signal directly (e.g. from a webhook handler). */
|
|
35
45
|
ingest(sig: RuntimeSignal): void;
|
|
46
|
+
/** Fan one logical signal out to a known recipient set. Each recipient gets one queue item. */
|
|
47
|
+
broadcast(recipients: Iterable<string>, sig: RuntimeSignal): void;
|
|
36
48
|
/** Number of signals currently buffered in the queue. */
|
|
37
49
|
get depth(): number;
|
|
38
50
|
/** Clear all pending timers. Call when shutting down to avoid process leaks. */
|
|
39
51
|
destroy(): void;
|
|
40
52
|
private emit;
|
|
53
|
+
private currentLeaseIndex;
|
|
41
54
|
}
|
package/dist/signals/gateway.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { reportObserverFailure } from "../runtime/reliability.js";
|
|
1
2
|
/**
|
|
2
3
|
* SignalGateway — entry point for all external signals into the agent.
|
|
3
4
|
*
|
|
4
5
|
* Implements `SignalSource` so it can be passed directly to `AgentOptions.signalSource`.
|
|
5
|
-
* The gateway maintains an internal FIFO queue
|
|
6
|
-
* on each agent turn.
|
|
6
|
+
* The gateway maintains an internal FIFO queue and exposes claim/ack/nack delivery leases.
|
|
7
7
|
*
|
|
8
8
|
* Responsibilities:
|
|
9
9
|
* - Cron scheduling: fires ScheduledPrompts at the right wall-clock time (idempotent by goal+time)
|
|
@@ -11,23 +11,59 @@
|
|
|
11
11
|
* - Listener API: `onSignal()` for side-channel observers that don't need the pull interface
|
|
12
12
|
*/
|
|
13
13
|
export class SignalGateway {
|
|
14
|
+
opts;
|
|
14
15
|
timers = new Map();
|
|
15
16
|
queue = [];
|
|
16
17
|
listeners = [];
|
|
18
|
+
deliverySeq = 0;
|
|
19
|
+
leaseSeq = 0;
|
|
20
|
+
constructor(opts = {}) {
|
|
21
|
+
this.opts = opts;
|
|
22
|
+
}
|
|
17
23
|
// ── SignalSource interface (pull model) ─────────────────────────────────────
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
/** Claim one visible signal without deleting it. Unacked claims are redelivered after expiry. */
|
|
25
|
+
async claimSignal(recipient, leaseMs = this.opts.defaultLeaseMs ?? 30_000) {
|
|
26
|
+
if (!Number.isFinite(leaseMs) || leaseMs <= 0)
|
|
27
|
+
throw new RangeError("leaseMs must be positive");
|
|
28
|
+
const now = this.opts.now?.() ?? Date.now();
|
|
29
|
+
const idx = this.queue.findIndex(entry => {
|
|
30
|
+
const visible = recipient === undefined
|
|
31
|
+
|| entry.signal.recipient === undefined
|
|
32
|
+
|| entry.signal.recipient === recipient;
|
|
33
|
+
const available = entry.lease === undefined || entry.lease.expiresAtMs <= now;
|
|
34
|
+
return visible && available;
|
|
35
|
+
});
|
|
28
36
|
if (idx === -1)
|
|
29
37
|
return null;
|
|
30
|
-
|
|
38
|
+
const entry = this.queue[idx];
|
|
39
|
+
entry.deliveryAttempts += 1;
|
|
40
|
+
const token = `${entry.deliveryId}:lease-${++this.leaseSeq}`;
|
|
41
|
+
const expiresAtMs = now + leaseMs;
|
|
42
|
+
entry.lease = { token, expiresAtMs };
|
|
43
|
+
return {
|
|
44
|
+
deliveryId: entry.deliveryId,
|
|
45
|
+
leaseToken: token,
|
|
46
|
+
signalId: entry.signalId,
|
|
47
|
+
deliveryAttempt: entry.deliveryAttempts,
|
|
48
|
+
leaseExpiresAtMs: expiresAtMs,
|
|
49
|
+
signal: entry.signal,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** Permanently remove the delivery iff the receipt still owns its current lease. */
|
|
53
|
+
async ackSignal(receipt) {
|
|
54
|
+
const idx = this.currentLeaseIndex(receipt);
|
|
55
|
+
if (idx === -1)
|
|
56
|
+
return false;
|
|
57
|
+
this.queue.splice(idx, 1);
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
/** Release the current lease for immediate retry. Stale receipts are ignored. */
|
|
61
|
+
async nackSignal(receipt) {
|
|
62
|
+
const idx = this.currentLeaseIndex(receipt);
|
|
63
|
+
if (idx === -1)
|
|
64
|
+
return false;
|
|
65
|
+
delete this.queue[idx].lease;
|
|
66
|
+
return true;
|
|
31
67
|
}
|
|
32
68
|
// ── Push API ────────────────────────────────────────────────────────────────
|
|
33
69
|
/** Register a listener that is called synchronously whenever a signal is emitted.
|
|
@@ -49,7 +85,6 @@ export class SignalGateway {
|
|
|
49
85
|
const fire = () => {
|
|
50
86
|
this.timers.delete(key);
|
|
51
87
|
this.emit({
|
|
52
|
-
kind: "scheduled",
|
|
53
88
|
source: "cron",
|
|
54
89
|
signalType: "job",
|
|
55
90
|
urgency: "normal",
|
|
@@ -78,6 +113,16 @@ export class SignalGateway {
|
|
|
78
113
|
ingest(sig) {
|
|
79
114
|
this.emit(sig);
|
|
80
115
|
}
|
|
116
|
+
/** Fan one logical signal out to a known recipient set. Each recipient gets one queue item. */
|
|
117
|
+
broadcast(recipients, sig) {
|
|
118
|
+
const seen = new Set();
|
|
119
|
+
for (const recipient of recipients) {
|
|
120
|
+
if (!recipient || seen.has(recipient))
|
|
121
|
+
continue;
|
|
122
|
+
seen.add(recipient);
|
|
123
|
+
this.emit({ ...sig, recipient });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
81
126
|
/** Number of signals currently buffered in the queue. */
|
|
82
127
|
get depth() {
|
|
83
128
|
return this.queue.length;
|
|
@@ -91,8 +136,27 @@ export class SignalGateway {
|
|
|
91
136
|
}
|
|
92
137
|
// ── Internal ────────────────────────────────────────────────────────────────
|
|
93
138
|
emit(sig) {
|
|
94
|
-
this.queue.push(
|
|
95
|
-
|
|
96
|
-
|
|
139
|
+
this.queue.push({
|
|
140
|
+
deliveryId: `signal-${++this.deliverySeq}`,
|
|
141
|
+
signalId: crypto.randomUUID(),
|
|
142
|
+
deliveryAttempts: 0,
|
|
143
|
+
signal: sig,
|
|
144
|
+
});
|
|
145
|
+
for (const listener of this.listeners) {
|
|
146
|
+
try {
|
|
147
|
+
listener(sig);
|
|
148
|
+
}
|
|
149
|
+
catch (cause) {
|
|
150
|
+
reportObserverFailure(this.opts.onObserverError, {
|
|
151
|
+
component: "SignalGateway",
|
|
152
|
+
operation: "signal_listener",
|
|
153
|
+
cause,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
currentLeaseIndex(receipt) {
|
|
159
|
+
return this.queue.findIndex(entry => entry.deliveryId === receipt.deliveryId
|
|
160
|
+
&& entry.lease?.token === receipt.leaseToken);
|
|
97
161
|
}
|
|
98
162
|
}
|
package/dist/signals/types.d.ts
CHANGED
|
@@ -7,20 +7,28 @@ export interface RuntimeSignal {
|
|
|
7
7
|
urgency: RuntimeSignalUrgency;
|
|
8
8
|
payload: Record<string, unknown>;
|
|
9
9
|
dedupeKey?: string;
|
|
10
|
-
/** Target a specific session loop
|
|
10
|
+
/** Target a specific session loop. Omitted means a shared item consumed by one eligible puller. */
|
|
11
11
|
recipient?: string;
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
|
|
12
|
+
/** Absolute journal-clock deadline for optional urgency escalation. */
|
|
13
|
+
deadlineMs?: number;
|
|
14
|
+
/** Merge with an unconsumed queued signal carrying the same key. */
|
|
15
|
+
coalesceKey?: string;
|
|
16
|
+
/** Number of host signals deterministically represented by this signal. */
|
|
17
|
+
coalescedCount?: number;
|
|
18
18
|
}
|
|
19
19
|
export interface SignalSource {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
claimSignal(recipient?: string, leaseMs?: number): Promise<SignalClaim | null>;
|
|
21
|
+
ackSignal(receipt: SignalDeliveryReceipt): Promise<boolean>;
|
|
22
|
+
nackSignal(receipt: SignalDeliveryReceipt): Promise<boolean>;
|
|
23
|
+
}
|
|
24
|
+
/** Opaque proof that one consumer currently owns a leased signal delivery. */
|
|
25
|
+
export interface SignalDeliveryReceipt {
|
|
26
|
+
deliveryId: string;
|
|
27
|
+
leaseToken: string;
|
|
28
|
+
}
|
|
29
|
+
export interface SignalClaim extends SignalDeliveryReceipt {
|
|
30
|
+
signalId: string;
|
|
31
|
+
deliveryAttempt: number;
|
|
32
|
+
signal: RuntimeSignal;
|
|
33
|
+
leaseExpiresAtMs: number;
|
|
26
34
|
}
|
package/dist/skills/loader.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { readFile, readdir } from "fs/promises";
|
|
2
2
|
import path from "path";
|
|
3
|
+
const SAFE_SKILL_NAME = /^[A-Za-z0-9_-]+$/;
|
|
4
|
+
function skillPath(skillDir, name) {
|
|
5
|
+
if (!SAFE_SKILL_NAME.test(name)) {
|
|
6
|
+
throw new Error(`invalid skill name "${name}": use only letters, digits, "-", "_"`);
|
|
7
|
+
}
|
|
8
|
+
return path.join(skillDir, `${name}.md`);
|
|
9
|
+
}
|
|
3
10
|
/** Parse a frontmatter tool list: `read, write` or `[read, write]` → ["read","write"]. */
|
|
4
11
|
function parseToolList(v) {
|
|
5
12
|
if (v == null || v === "")
|
|
@@ -22,11 +29,14 @@ function parseFrontmatter(content) {
|
|
|
22
29
|
}
|
|
23
30
|
/** Read one skill file and return its body (frontmatter stripped). */
|
|
24
31
|
export async function readSkillFile(skillDir, name) {
|
|
32
|
+
const file = skillPath(skillDir, name);
|
|
25
33
|
try {
|
|
26
|
-
const raw = await readFile(
|
|
34
|
+
const raw = await readFile(file, "utf8");
|
|
27
35
|
return parseFrontmatter(raw).body;
|
|
28
36
|
}
|
|
29
|
-
catch {
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error.code !== "ENOENT")
|
|
39
|
+
throw error;
|
|
30
40
|
return null;
|
|
31
41
|
}
|
|
32
42
|
}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ToolChunk, ToolSchema, ToolResult } from "../types.js";
|
|
2
|
+
import type { OperationContext } from "../runtime/reliability.js";
|
|
2
3
|
/** M3/G4: the runtime context a tool may read when executing. Carries the working directory the tool
|
|
3
4
|
* should operate in — set to a sub-agent's git worktree for `isolation: "worktree"` nodes. A narrow,
|
|
4
5
|
* dependency-free shape; the execution plane's `RunContext` is structurally assignable to it.
|
|
@@ -9,6 +10,7 @@ import type { ToolChunk, ToolSchema, ToolResult } from "../types.js";
|
|
|
9
10
|
* the tool still completes successfully — avoiding the foot-gun where a transient audit-store
|
|
10
11
|
* outage flips an already-committed write into `isError: true` and triggers a duplicate retry. */
|
|
11
12
|
export interface ToolExecContext {
|
|
13
|
+
operation?: OperationContext;
|
|
12
14
|
cwd?: string;
|
|
13
15
|
audit?: (label: string, fn: () => Promise<void> | void) => Promise<void>;
|
|
14
16
|
}
|
package/dist/types/agent.d.ts
CHANGED
|
@@ -90,6 +90,14 @@ export interface LoopResult {
|
|
|
90
90
|
* vocabulary (stop → loopContinue=false); the legacy text-sniffed signal is the fallback.
|
|
91
91
|
* SDK-internal — stripped by `subAgentResultToKernel`. */
|
|
92
92
|
paceDecision?: import("../runtime/kernel-step.js").PaceDecision;
|
|
93
|
+
/** Two-axis AttemptLoop result. Serialized alongside `termination` so hosts can observe judge
|
|
94
|
+
* failure independently from run health. */
|
|
95
|
+
attempt?: {
|
|
96
|
+
outcome: import("../harness/harness.js").AttemptOutcomeKind;
|
|
97
|
+
runStatus: string;
|
|
98
|
+
attempts: number;
|
|
99
|
+
verdict?: import("../runtime/eval.js").Verdict;
|
|
100
|
+
};
|
|
93
101
|
}
|
|
94
102
|
export interface SubAgentResult {
|
|
95
103
|
agentId: string;
|
|
@@ -130,6 +138,9 @@ export type WorkflowTaskSpec = {
|
|
|
130
138
|
} | string;
|
|
131
139
|
/** W3 trust level for a workflow node. */
|
|
132
140
|
export type NodeTrust = "trusted" | "quarantined";
|
|
141
|
+
export type WorkflowDependencyPolicy = "all_success" | "accept_partial" | "all_terminal" | "optional";
|
|
142
|
+
export type WorkflowNodeStatus = "completed" | "completed_partial" | "failed" | "skipped_upstream_failed";
|
|
143
|
+
export declare function workflowNodeStatusFromTermination(termination: TerminationReason | string): WorkflowNodeStatus;
|
|
133
144
|
/** One node in a declarative workflow DAG (camelCase host shape). */
|
|
134
145
|
export interface WorkflowNodeSpec {
|
|
135
146
|
task: WorkflowTaskSpec;
|
|
@@ -171,11 +182,39 @@ export interface WorkflowNodeSpec {
|
|
|
171
182
|
maxWallMs?: number;
|
|
172
183
|
/** Indices of nodes this node depends on. */
|
|
173
184
|
dependsOn?: number[];
|
|
185
|
+
/** How dependency terminal states gate this node. Defaults to `all_success`. */
|
|
186
|
+
depPolicy?: WorkflowDependencyPolicy;
|
|
174
187
|
}
|
|
175
188
|
/** A declarative workflow DAG the kernel runs node-by-node, gating each spawn. */
|
|
176
189
|
export interface WorkflowSpec {
|
|
177
190
|
nodes: WorkflowNodeSpec[];
|
|
178
191
|
}
|
|
192
|
+
export interface KernelWorkflowNodeOutcome {
|
|
193
|
+
node_id: string;
|
|
194
|
+
status: WorkflowNodeStatus;
|
|
195
|
+
termination?: TerminationReason;
|
|
196
|
+
output?: {
|
|
197
|
+
role: Message["role"];
|
|
198
|
+
content: string;
|
|
199
|
+
tool_calls?: Array<{
|
|
200
|
+
id: string;
|
|
201
|
+
name: string;
|
|
202
|
+
arguments?: Record<string, unknown>;
|
|
203
|
+
}>;
|
|
204
|
+
token_count?: number;
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
export interface WorkflowNodeOutcome {
|
|
208
|
+
nodeId: string;
|
|
209
|
+
status: WorkflowNodeStatus;
|
|
210
|
+
termination?: TerminationReason;
|
|
211
|
+
output?: Message;
|
|
212
|
+
}
|
|
213
|
+
export interface WorkflowOutcome {
|
|
214
|
+
nodeOutcomes: WorkflowNodeOutcome[];
|
|
215
|
+
outputs: Record<string, string>;
|
|
216
|
+
}
|
|
217
|
+
export declare function workflowNodeOutcomeFromKernel(raw: KernelWorkflowNodeOutcome): WorkflowNodeOutcome;
|
|
179
218
|
/** Per-node spawn descriptor carried in the `workflow_batch_spawned` observation. */
|
|
180
219
|
export interface WorkflowSpawnInfo {
|
|
181
220
|
agent_id: string;
|
|
@@ -267,7 +306,7 @@ export declare function generateAndFilter(generators: WorkflowTaskSpec[], filter
|
|
|
267
306
|
* Generate→evaluate quality gate (the EvalPipeline successor, #6): a `loop` worker node (re-run up
|
|
268
307
|
* to `maxIters`, stopping early on a `loop_continue=false` self-signal) + a bias-resistant `verify`
|
|
269
308
|
* eval node gated on it, carrying the kernel's verdict `outputSchema`. Mirrors the kernel `gen_eval`
|
|
270
|
-
* template. For the iterative retry-with-feedback variant, drive it with `
|
|
309
|
+
* template. For the iterative retry-with-feedback variant, drive it with `AttemptLoop`.
|
|
271
310
|
*/
|
|
272
311
|
export declare function genEval(worker: WorkflowTaskSpec, evaluate: WorkflowTaskSpec, maxIters?: number, extractSkillOnPass?: boolean): WorkflowSpec;
|
|
273
312
|
/**
|
package/dist/types/agent.js
CHANGED
|
@@ -89,6 +89,7 @@ function safeParseToolArgs(raw) {
|
|
|
89
89
|
}
|
|
90
90
|
export function subAgentResultToKernel(result) {
|
|
91
91
|
const finalMessage = result.result.finalMessage;
|
|
92
|
+
const attempt = result.result.attempt;
|
|
92
93
|
return {
|
|
93
94
|
agent_id: result.agentId,
|
|
94
95
|
result: {
|
|
@@ -112,6 +113,30 @@ export function subAgentResultToKernel(result) {
|
|
|
112
113
|
...(result.result.loopContinue !== undefined ? { loop_continue: result.result.loopContinue } : {}),
|
|
113
114
|
...(result.result.classifyBranch !== undefined ? { classify_branch: result.result.classifyBranch } : {}),
|
|
114
115
|
...(result.result.tournamentWinner !== undefined ? { tournament_winner: result.result.tournamentWinner } : {}),
|
|
116
|
+
...(attempt
|
|
117
|
+
? {
|
|
118
|
+
attempt: {
|
|
119
|
+
outcome: attempt.outcome,
|
|
120
|
+
run_status: attempt.runStatus,
|
|
121
|
+
attempts: attempt.attempts,
|
|
122
|
+
...(attempt.verdict
|
|
123
|
+
? {
|
|
124
|
+
verdict: {
|
|
125
|
+
passed: attempt.verdict.passed,
|
|
126
|
+
overall_score: attempt.verdict.overallScore,
|
|
127
|
+
feedback: attempt.verdict.feedback,
|
|
128
|
+
details: attempt.verdict.details.map(detail => ({
|
|
129
|
+
criterion: detail.criterion,
|
|
130
|
+
passed: detail.passed,
|
|
131
|
+
score: detail.score,
|
|
132
|
+
feedback: detail.feedback,
|
|
133
|
+
})),
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
: {}),
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
: {}),
|
|
115
140
|
},
|
|
116
141
|
};
|
|
117
142
|
}
|
|
@@ -121,6 +146,35 @@ export function milestoneCheckPass(phaseId) {
|
|
|
121
146
|
export function milestoneCheckFail(phaseId, reason) {
|
|
122
147
|
return { phaseId, passed: false, reason };
|
|
123
148
|
}
|
|
149
|
+
export function workflowNodeStatusFromTermination(termination) {
|
|
150
|
+
if (termination === "completed")
|
|
151
|
+
return "completed";
|
|
152
|
+
if (termination === "error" || termination === "user_abort")
|
|
153
|
+
return "failed";
|
|
154
|
+
return "completed_partial";
|
|
155
|
+
}
|
|
156
|
+
export function workflowNodeOutcomeFromKernel(raw) {
|
|
157
|
+
const output = raw.output;
|
|
158
|
+
return {
|
|
159
|
+
nodeId: raw.node_id,
|
|
160
|
+
status: raw.status,
|
|
161
|
+
...(raw.termination ? { termination: raw.termination } : {}),
|
|
162
|
+
...(output
|
|
163
|
+
? {
|
|
164
|
+
output: {
|
|
165
|
+
role: output.role,
|
|
166
|
+
content: output.content,
|
|
167
|
+
toolCalls: (output.tool_calls ?? []).map(call => ({
|
|
168
|
+
id: call.id,
|
|
169
|
+
name: call.name,
|
|
170
|
+
arguments: JSON.stringify(call.arguments ?? {}),
|
|
171
|
+
})),
|
|
172
|
+
...(output.token_count != null ? { tokenCount: output.token_count } : {}),
|
|
173
|
+
},
|
|
174
|
+
}
|
|
175
|
+
: {}),
|
|
176
|
+
};
|
|
177
|
+
}
|
|
124
178
|
/** G4: a concise, human-readable budget note appended to a coordinator node's goal, so its agent can
|
|
125
179
|
* size a `submit_workflow_nodes` batch to what is actually available. Returns "" when nothing is
|
|
126
180
|
* bounded (no quota ⇒ no signal). */
|
|
@@ -192,6 +246,7 @@ export function workflowNodeSpecToKernel(n) {
|
|
|
192
246
|
...(n.maxTurns != null ? { max_turns: n.maxTurns } : {}),
|
|
193
247
|
...(n.maxWallMs != null ? { max_wall_ms: n.maxWallMs } : {}),
|
|
194
248
|
...(n.dependsOn && n.dependsOn.length ? { depends_on: n.dependsOn } : {}),
|
|
249
|
+
dep_policy: n.depPolicy ?? "all_success",
|
|
195
250
|
};
|
|
196
251
|
}
|
|
197
252
|
/** Map a host `WorkflowSpec` to the snake_case kernel JSON (`load_workflow.spec`). */
|
|
@@ -321,6 +376,11 @@ const workflowNodesArraySchema = {
|
|
|
321
376
|
items: { type: "integer" },
|
|
322
377
|
description: "Batch-relative, backward-only dependency indices within this submission.",
|
|
323
378
|
},
|
|
379
|
+
depPolicy: {
|
|
380
|
+
type: "string",
|
|
381
|
+
enum: ["all_success", "accept_partial", "all_terminal", "optional"],
|
|
382
|
+
description: "How dependency terminal states gate this node; defaults to all_success.",
|
|
383
|
+
},
|
|
324
384
|
},
|
|
325
385
|
required: ["task", "role"],
|
|
326
386
|
},
|
|
@@ -451,7 +511,7 @@ export function generateAndFilter(generators, filter) {
|
|
|
451
511
|
* Generate→evaluate quality gate (the EvalPipeline successor, #6): a `loop` worker node (re-run up
|
|
452
512
|
* to `maxIters`, stopping early on a `loop_continue=false` self-signal) + a bias-resistant `verify`
|
|
453
513
|
* eval node gated on it, carrying the kernel's verdict `outputSchema`. Mirrors the kernel `gen_eval`
|
|
454
|
-
* template. For the iterative retry-with-feedback variant, drive it with `
|
|
514
|
+
* template. For the iterative retry-with-feedback variant, drive it with `AttemptLoop`.
|
|
455
515
|
*/
|
|
456
516
|
export function genEval(worker, evaluate, maxIters = 3, extractSkillOnPass = true) {
|
|
457
517
|
const schema = JSON.parse(getKernel().verdictOutputSchema(extractSkillOnPass));
|
package/dist/types.d.ts
CHANGED
|
@@ -154,7 +154,6 @@ export interface DoneEvent extends StreamEvent {
|
|
|
154
154
|
iterations: number;
|
|
155
155
|
totalTokens: number;
|
|
156
156
|
status: string;
|
|
157
|
-
dreamResult?: import("./memory/protocols.js").DreamResult;
|
|
158
157
|
/** ③ loop-agent: the kernel-adjudicated after-round decision (absent on non-loop runs). */
|
|
159
158
|
paceDecision?: import("./runtime/kernel-step.js").PaceDecision;
|
|
160
159
|
}
|
|
@@ -372,6 +371,12 @@ export interface RenderedContext {
|
|
|
372
371
|
* yet) ⇒ the provider falls back to the rolling-pair placement.
|
|
373
372
|
*/
|
|
374
373
|
frozenPrefixLen?: number;
|
|
374
|
+
budgetOverflow?: ContextBudgetOverflow;
|
|
375
|
+
}
|
|
376
|
+
export interface ContextBudgetOverflow {
|
|
377
|
+
kind: "fixed_context" | "protected_tail";
|
|
378
|
+
requiredTokens: number;
|
|
379
|
+
maxTokens: number;
|
|
375
380
|
}
|
|
376
381
|
/**
|
|
377
382
|
* Runtime execution policy advertised by a provider.
|
|
@@ -4,12 +4,11 @@ export { builtinReducers, resolveReducer } from "../runtime/reducers.js";
|
|
|
4
4
|
export type { Reducer, ReducerRegistry, ReducerInput } from "../runtime/reducers.js";
|
|
5
5
|
export { FileWorkflowStore } from "../runtime/workflow-store.js";
|
|
6
6
|
export { submitWorkflowNodesTool, startWorkflowTool, generateAndFilter, verifyRules, genEval, milestoneCheckPass, milestoneCheckFail, } from "../types/agent.js";
|
|
7
|
-
export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec, AgentProcessChangedObservation, ContextInheritance, KernelAgentRole, LoopResult, MilestoneCheckResult, MilestoneContract, MilestonePhase, MilestonePolicy, SubAgentResult, TerminationReason, WorkflowSpawnInfo, WorkflowTaskSpec, } from "../types/agent.js";
|
|
7
|
+
export type { AgentCapabilityFilter, AgentIdentity, AgentIsolation, AgentRunSpec, AgentProcessChangedObservation, ContextInheritance, KernelAgentRole, LoopResult, MilestoneCheckResult, MilestoneContract, MilestonePhase, MilestonePolicy, SubAgentResult, TerminationReason, WorkflowSpawnInfo, WorkflowTaskSpec, WorkflowDependencyPolicy, WorkflowNodeStatus, WorkflowNodeOutcome, WorkflowOutcome, } from "../types/agent.js";
|
|
8
8
|
export type { AcceptanceCriterion, VerificationContract, ContractCheckResult } from "../collaboration/contract.js";
|
|
9
9
|
export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings } from "../collaboration/contract.js";
|
|
10
10
|
export type { AgentRole, IsolatedVerifierContext, CoordinatorConfig } from "../collaboration/pool.js";
|
|
11
|
-
export {
|
|
12
|
-
export type { ContractOutcome, ContractHarnessOptions, Violation } from "../collaboration/harness.js";
|
|
11
|
+
export type { ContractOutcome } from "../collaboration/harness.js";
|
|
13
12
|
export { HandoffBus } from "../collaboration/handoff.js";
|
|
14
13
|
export type { HandoffArtifact, ContractOutcomeInput } from "../collaboration/handoff.js";
|
|
15
14
|
export { CreatorVerifierMode, OrchestrationMode } from "../collaboration/modes/creator-verifier.js";
|
package/dist/workflow/public.js
CHANGED
|
@@ -7,7 +7,6 @@ export { builtinReducers, resolveReducer } from "../runtime/reducers.js";
|
|
|
7
7
|
export { FileWorkflowStore } from "../runtime/workflow-store.js";
|
|
8
8
|
export { submitWorkflowNodesTool, startWorkflowTool, generateAndFilter, verifyRules, genEval, milestoneCheckPass, milestoneCheckFail, } from "../types/agent.js";
|
|
9
9
|
export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings } from "../collaboration/contract.js";
|
|
10
|
-
export { ContractDrivenHarness } from "../collaboration/harness.js";
|
|
11
10
|
export { HandoffBus } from "../collaboration/handoff.js";
|
|
12
11
|
export { CreatorVerifierMode, OrchestrationMode } from "../collaboration/modes/creator-verifier.js";
|
|
13
12
|
// Skills loader + lower-level tool execution helpers.
|