@deepstrike/sdk 0.2.39 → 0.2.41
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 +64 -34
- 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 +6 -1
- package/dist/memory/public.js +3 -0
- package/dist/memory/ranking.d.ts +32 -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 +5 -4
- package/dist/os/public.js +2 -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
package/README.md
CHANGED
|
@@ -88,13 +88,13 @@ The root export is the **intent layer** — what you reach for to run an agent,
|
|
|
88
88
|
|
|
89
89
|
| Import | Contains |
|
|
90
90
|
|--------|----------|
|
|
91
|
-
| `@deepstrike/sdk` | `runAgent` · `runFanout` · `RuntimeRunner` · `tool` · `LocalExecutionPlane` · `InMemorySessionLog`/`FileSessionLog` · `AnthropicProvider`/`OpenAIProvider`/`OpenAIResponsesProvider` · `createProvider` · `Governance` · `AgentPool` · core types |
|
|
91
|
+
| `@deepstrike/sdk` | `runAgent` · `runFanout` · `RuntimeRunner` · `tool` · `LocalExecutionPlane` · `InMemorySessionLog`/`FileSessionLog` · `AnthropicProvider`/`OpenAIProvider`/`OpenAIResponsesProvider` · `createProvider` · `Governance` · `AgentPool` · `operationAbortSignal` · core types |
|
|
92
92
|
| `@deepstrike/sdk/providers` | backend factories (`deepseek`, `kimi`, `qwen`, `glm`, `minimax`, `gemini`, `ollama`), profiles, `CircuitBreaker` |
|
|
93
93
|
| `@deepstrike/sdk/workflow` | `SubAgentOrchestrator`, `spawnStandalone`, reducers, contracts, handoff/modes, agent + spec types |
|
|
94
94
|
| `@deepstrike/sdk/planes` | `WorktreeExecutionPlane`, `ProcessSandboxPlane`, `McpProxyPlane`, `RemoteVpcPlane`, archive/credential stores |
|
|
95
|
-
| `@deepstrike/sdk/memory` | `DreamStore`, `WorkingMemory`, `InMemoryDreamStore`, `KnowledgeSource` |
|
|
96
|
-
| `@deepstrike/sdk/harness` | `
|
|
97
|
-
| `@deepstrike/sdk/os` | profiles, `KernelPrimitivesDashboard`, signals, `PermissionManager`, replay-testing utilities |
|
|
95
|
+
| `@deepstrike/sdk/memory` | `DreamStore`, `WorkingMemory`, `InMemoryDreamStore`, `rankMemories`, `extractSessionMemories`, `KnowledgeSource` |
|
|
96
|
+
| `@deepstrike/sdk/harness` | `AttemptLoop`, body/judge/carry policies, `judge` |
|
|
97
|
+
| `@deepstrike/sdk/os` | profiles, `KernelPrimitivesDashboard`, `primitiveForKind` / `KernelPrimitive`, signals, `PermissionManager`, replay-testing utilities |
|
|
98
98
|
|
|
99
99
|
> **Migration from 0.2.x:** the kernel-lowering converters (`*ToKernel`), low-level prompt/eval builders, and the `OpenAIChatProvider` alias are no longer exported from root; backend providers, planes, memory, harness, and OS utilities moved to the subpaths above. See [`MIGRATION-v0.2.300.md`](./MIGRATION-v0.2.300.md).
|
|
100
100
|
|
|
@@ -190,7 +190,7 @@ Tool calls, spawns, compression, and signals pass through one kernel gate with a
|
|
|
190
190
|
Oversized tool results (> 50 KB) stay in context as a preview plus a `.spool/` reference — the model reads the full payload on demand via ordinary file tools. When pressure triggers semantic eviction, the SDK summarizes archived content into `DreamStore`. Long tasks survive token pressure instead of failing mid-run.
|
|
191
191
|
|
|
192
192
|
**Safety and governance by default (OS native profile)**
|
|
193
|
-
Every run loads declarative `governancePolicy` (deny / ask_user / rate-limit / param rules) and in-kernel signal routing (`
|
|
193
|
+
Every run loads declarative `governancePolicy` (deny / ask_user / rate-limit / param rules) and in-kernel signal routing (`signalPolicy`, default queue 64). Dangerous tools, external interrupts, and approval flows are policy — not ad-hoc `if` checks in your handlers.
|
|
194
194
|
|
|
195
195
|
**Long-term memory as syscalls (Phase-7)**
|
|
196
196
|
`writeMemory` and `queryMemory` run outside the main tool loop: kernel validation before `DreamStore.commit`, search → `selectMemories` → `memory_retrieval_result` on query. Failed writes emit `memory_validation_failed` for audit; good memory is durable without polluting history.
|
|
@@ -204,7 +204,7 @@ Spool, page-out, signals, processes, budgets, and memory events land in `Session
|
|
|
204
204
|
| You need… | Use… |
|
|
205
205
|
|---|---|
|
|
206
206
|
| Policy before tools run | `governancePolicy` (default: allow-all native profile) |
|
|
207
|
-
| External interrupts | `signalSource` + in-kernel `
|
|
207
|
+
| External interrupts | `signalSource` + in-kernel `signalPolicy` |
|
|
208
208
|
| Huge tool output | Automatic Layer-1 spool; optional custom `resultSpool` |
|
|
209
209
|
| Durable recall across runs | `DreamStore` + semantic `page_out` via `dreamSummarizer` |
|
|
210
210
|
| Programmatic memory I/O | `runner.writeMemory()` / `runner.queryMemory()` |
|
|
@@ -336,7 +336,7 @@ Full reference: [docs/concepts/context-slots-compression.md](../docs/concepts/co
|
|
|
336
336
|
```typescript
|
|
337
337
|
import {
|
|
338
338
|
DEFAULT_NATIVE_GOVERNANCE_POLICY,
|
|
339
|
-
|
|
339
|
+
DEFAULT_NATIVE_SIGNAL_POLICY,
|
|
340
340
|
} from "@deepstrike/sdk"
|
|
341
341
|
|
|
342
342
|
const runner = new RuntimeRunner({
|
|
@@ -348,7 +348,13 @@ const runner = new RuntimeRunner({
|
|
|
348
348
|
maxTokens: 128_000,
|
|
349
349
|
maxTurns: 25,
|
|
350
350
|
timeoutMs: 60_000,
|
|
351
|
-
|
|
351
|
+
schedulerPolicy: {
|
|
352
|
+
version: 1,
|
|
353
|
+
criticalPathWeight: 1_000_000,
|
|
354
|
+
fanoutWeight: 10_000,
|
|
355
|
+
ageWeight: 1_000,
|
|
356
|
+
tokenCostWeight: 1,
|
|
357
|
+
},
|
|
352
358
|
|
|
353
359
|
// Resource quotas (M2) — enforced at the kernel syscall trap. Opt-in; omit for unbounded.
|
|
354
360
|
resourceQuota: {
|
|
@@ -369,7 +375,12 @@ const runner = new RuntimeRunner({
|
|
|
369
375
|
|
|
370
376
|
// Agent OS native profile (defaults shown)
|
|
371
377
|
governancePolicy: DEFAULT_NATIVE_GOVERNANCE_POLICY,
|
|
372
|
-
|
|
378
|
+
signalPolicy: DEFAULT_NATIVE_SIGNAL_POLICY, // SignalRouter queue size 64
|
|
379
|
+
promptBudget: {
|
|
380
|
+
promptOverheadTokens: 20,
|
|
381
|
+
outputReserveTokens: 4096,
|
|
382
|
+
safetyMarginTokens: 256,
|
|
383
|
+
},
|
|
373
384
|
|
|
374
385
|
// Host I/O
|
|
375
386
|
extensions: { temperature: 0.1 },
|
|
@@ -404,7 +415,8 @@ const runner = new RuntimeRunner({
|
|
|
404
415
|
| Option | Purpose |
|
|
405
416
|
|--------|---------|
|
|
406
417
|
| `governancePolicy` | Declarative deny / ask_user / rate-limit / param rules loaded into the kernel before `start_run` |
|
|
407
|
-
| `
|
|
418
|
+
| `signalPolicy` | Versioned in-kernel signal queue/TTL policy (default queue 64) |
|
|
419
|
+
| `promptBudget` | Provider-envelope overhead, output reserve, and safety margin deducted from the context window |
|
|
408
420
|
| `resourceQuota` | M2 declarative limits — `maxConcurrentSubagents` / `maxSpawnDepth` / `memoryWritesPerWindow` — enforced at the kernel syscall trap (`set_resource_quota`); over-quota spawns roll back, over-rate writes surface as `memory_validation_failed` |
|
|
409
421
|
| `memoryPolicy` | Long-term memory config sent as `set_memory_policy` and **kernel-enforced**: `validationEnabled: false` admits writes without validation, `maxContentBytes` / `maxNameLength` override validation limits, `retrievalTopK` caps `query_memory` breadth; `memoryPath` / `staleWarningDays` are SDK-consumed (requires `dreamStore` + `agentId` to enable memory) |
|
|
410
422
|
| `onPermissionRequest` | Resolves `tool_gated` + `suspended` → kernel `resume` with approved/denied call IDs |
|
|
@@ -528,7 +540,7 @@ const runner = new RuntimeRunner({
|
|
|
528
540
|
`WorkingMemory` is an SDK helper — not the kernel working partition. Kernel task state lives in `task_state` and renders into Slot 3 (`turns[0]`).
|
|
529
541
|
|
|
530
542
|
```typescript
|
|
531
|
-
import { WorkingMemory } from "@deepstrike/sdk"
|
|
543
|
+
import { WorkingMemory } from "@deepstrike/sdk/memory"
|
|
532
544
|
const mem = new WorkingMemory()
|
|
533
545
|
mem.set("step", 1)
|
|
534
546
|
mem.get("step") // 1
|
|
@@ -538,13 +550,13 @@ mem.clear()
|
|
|
538
550
|
### DreamStore (long-term memory)
|
|
539
551
|
|
|
540
552
|
```typescript
|
|
541
|
-
import type { DreamStore } from "@deepstrike/sdk"
|
|
553
|
+
import type { DreamStore } from "@deepstrike/sdk/memory"
|
|
542
554
|
|
|
543
555
|
class MyStore implements DreamStore {
|
|
544
556
|
async loadSessions(agentId) { ... }
|
|
545
557
|
async loadMemories(agentId) { ... }
|
|
546
558
|
async commit(agentId, result, existing) { ... }
|
|
547
|
-
async search(agentId, query
|
|
559
|
+
async search(agentId, query) { ... } // Promise<MemoryRecall[]>
|
|
548
560
|
}
|
|
549
561
|
|
|
550
562
|
const runner = new RuntimeRunner({
|
|
@@ -577,21 +589,26 @@ Kernel-validated long-term memory I/O outside the main tool loop:
|
|
|
577
589
|
|
|
578
590
|
```typescript
|
|
579
591
|
await runner.writeMemory({
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
created_at: Date.now(),
|
|
585
|
-
updated_at: Date.now(),
|
|
586
|
-
},
|
|
592
|
+
record_id: crypto.randomUUID(),
|
|
593
|
+
scope: { tenant_id: "acme", namespace: "assistant" },
|
|
594
|
+
name: "prefers-small-tests",
|
|
595
|
+
kind: "feedback",
|
|
587
596
|
content: "User prefers focused unit tests for SDK behavior.",
|
|
597
|
+
description: "Testing preference",
|
|
598
|
+
provenance: { author: "host", trust: "user_asserted", evidence_refs: [] },
|
|
599
|
+
created_at: Date.now(),
|
|
600
|
+
updated_at: Date.now(),
|
|
601
|
+
recall_count: 0,
|
|
602
|
+
confidence: 1,
|
|
603
|
+
links: [],
|
|
604
|
+
pinned: false,
|
|
588
605
|
}, { sessionId: "my-session" })
|
|
589
606
|
|
|
590
607
|
const hits = await runner.queryMemory({
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
already_surfaced: [],
|
|
608
|
+
scope: { tenant_id: "acme", namespace: "assistant" },
|
|
609
|
+
query: "Need testing preferences",
|
|
594
610
|
top_k: 5,
|
|
611
|
+
kinds: ["feedback"],
|
|
595
612
|
}, { sessionId: "my-session" })
|
|
596
613
|
```
|
|
597
614
|
|
|
@@ -676,14 +693,14 @@ const runner = new RuntimeRunner({
|
|
|
676
693
|
executionPlane: plane,
|
|
677
694
|
sessionLog,
|
|
678
695
|
signalSource: gw,
|
|
679
|
-
|
|
696
|
+
signalPolicy: { queueMax: 64, ttlMs: 60_000 },
|
|
680
697
|
})
|
|
681
698
|
|
|
682
699
|
runner.interrupt() // cooperative abort → kernel timeout path
|
|
683
700
|
gw.destroy()
|
|
684
701
|
```
|
|
685
702
|
|
|
686
|
-
Each routed signal produces a `
|
|
703
|
+
Each routed signal produces a correlated `signal_delivery_disposed` session event (`category: "ipc"`).
|
|
687
704
|
|
|
688
705
|
---
|
|
689
706
|
|
|
@@ -709,15 +726,25 @@ Requires an active parent run (`run()` / `wake()` in progress). The kernel emits
|
|
|
709
726
|
## Harness (evaluation framework)
|
|
710
727
|
|
|
711
728
|
```typescript
|
|
712
|
-
import {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
729
|
+
import {
|
|
730
|
+
AttemptLoop,
|
|
731
|
+
RuntimeAttemptBody,
|
|
732
|
+
LlmEvalJudge,
|
|
733
|
+
freshWithFeedback,
|
|
734
|
+
} from "@deepstrike/sdk/harness"
|
|
735
|
+
|
|
736
|
+
const loop = new AttemptLoop({
|
|
737
|
+
body: new RuntimeAttemptBody(runner),
|
|
738
|
+
judge: new LlmEvalJudge(evalProvider, false),
|
|
739
|
+
stop: { maxAttempts: 3 },
|
|
740
|
+
// carry defaults to continueSession: stable session + journaled feedback signal.
|
|
741
|
+
// Use `carry: freshWithFeedback` only when attempts must be isolated.
|
|
742
|
+
})
|
|
743
|
+
const outcome = await loop.run({
|
|
744
|
+
sessionId: "task-42",
|
|
745
|
+
goal: "Say hello",
|
|
746
|
+
criteria: [{ text: "result greets the user", required: true }],
|
|
747
|
+
})
|
|
721
748
|
|
|
722
749
|
const runnerWithHarness = new RuntimeRunner({
|
|
723
750
|
provider,
|
|
@@ -727,6 +754,9 @@ const runnerWithHarness = new RuntimeRunner({
|
|
|
727
754
|
})
|
|
728
755
|
```
|
|
729
756
|
|
|
757
|
+
`AttemptOutcome` keeps run health (`runStatus`) separate from evaluation (`verdict`) and reports a
|
|
758
|
+
terminal `outcome`: `passed`, `failed_judge`, `exhausted`, or `run_error`.
|
|
759
|
+
|
|
730
760
|
---
|
|
731
761
|
|
|
732
762
|
## Stream events
|
|
@@ -48,8 +48,8 @@ export declare class ContractBuilder {
|
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* Render the contract as a markdown block for injection into a system prompt.
|
|
51
|
-
* Used by
|
|
51
|
+
* Used by CreatorVerifierBody to inject into the executor's system partition.
|
|
52
52
|
*/
|
|
53
53
|
export declare function formatContractForSystemPrompt(contract: VerificationContract): string;
|
|
54
|
-
/** Derive a flat string[] of criterion texts for
|
|
54
|
+
/** Derive a flat string[] of criterion texts for RuntimeRunner criteria input. */
|
|
55
55
|
export declare function contractToCriteriaStrings(contract: VerificationContract): string[];
|
|
@@ -35,7 +35,7 @@ export class ContractBuilder {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* Render the contract as a markdown block for injection into a system prompt.
|
|
38
|
-
* Used by
|
|
38
|
+
* Used by CreatorVerifierBody to inject into the executor's system partition.
|
|
39
39
|
*/
|
|
40
40
|
export function formatContractForSystemPrompt(contract) {
|
|
41
41
|
const lines = [
|
|
@@ -59,7 +59,7 @@ export function formatContractForSystemPrompt(contract) {
|
|
|
59
59
|
}
|
|
60
60
|
return lines.join("\n");
|
|
61
61
|
}
|
|
62
|
-
/** Derive a flat string[] of criterion texts for
|
|
62
|
+
/** Derive a flat string[] of criterion texts for RuntimeRunner criteria input. */
|
|
63
63
|
export function contractToCriteriaStrings(contract) {
|
|
64
64
|
return contract.acceptance.map(c => c.text);
|
|
65
65
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import type { ContractCheckResult, VerificationContract } from "./contract.js";
|
|
2
|
-
import type { DreamResult } from "../memory/protocols.js";
|
|
3
2
|
/**
|
|
4
3
|
* HandoffArtifact — the single exchange token between sprints and agent instances.
|
|
5
4
|
*
|
|
6
5
|
* All handoff paths converge here:
|
|
7
|
-
* -
|
|
6
|
+
* - CreatorVerifier AttemptLoop completion → HandoffBus.fromContractOutcome()
|
|
8
7
|
* - Sub-agent completion → HandoffBus.fromSubAgentResult()
|
|
9
|
-
* - Dream consolidation → HandoffBus.fromDream()
|
|
10
8
|
* - Context renewal (kernel) → carried in kernel's HandoffArtifact type
|
|
11
9
|
*
|
|
12
10
|
* The invariant: a HandoffArtifact tells the next agent not only *what was done*
|
|
@@ -41,7 +39,7 @@ export interface ContractOutcomeInput {
|
|
|
41
39
|
*/
|
|
42
40
|
export declare class HandoffBus {
|
|
43
41
|
/**
|
|
44
|
-
* Build a HandoffArtifact from a
|
|
42
|
+
* Build a HandoffArtifact from a creator-verifier AttemptLoop outcome.
|
|
45
43
|
* The artifact field is used as the progress summary.
|
|
46
44
|
*/
|
|
47
45
|
static fromContractOutcome(input: ContractOutcomeInput): HandoffArtifact;
|
|
@@ -54,16 +52,6 @@ export declare class HandoffBus {
|
|
|
54
52
|
finalMessage: string;
|
|
55
53
|
sprint?: number;
|
|
56
54
|
}): HandoffArtifact;
|
|
57
|
-
/**
|
|
58
|
-
* Build a HandoffArtifact from a dream consolidation result.
|
|
59
|
-
* Used when the idle pipeline produces new memories that should be
|
|
60
|
-
* carried into the next sprint's context.
|
|
61
|
-
*/
|
|
62
|
-
static fromDream(opts: {
|
|
63
|
-
goal: string;
|
|
64
|
-
dreamResult: DreamResult;
|
|
65
|
-
sprint?: number;
|
|
66
|
-
}): HandoffArtifact;
|
|
67
55
|
/**
|
|
68
56
|
* Render the artifact as a compact injection string for the next agent's
|
|
69
57
|
* working partition (not system — this is a handoff note, not a permanent rule).
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export class HandoffBus {
|
|
9
9
|
/**
|
|
10
|
-
* Build a HandoffArtifact from a
|
|
10
|
+
* Build a HandoffArtifact from a creator-verifier AttemptLoop outcome.
|
|
11
11
|
* The artifact field is used as the progress summary.
|
|
12
12
|
*/
|
|
13
13
|
static fromContractOutcome(input) {
|
|
@@ -46,22 +46,6 @@ export class HandoffBus {
|
|
|
46
46
|
blockedOn: [],
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Build a HandoffArtifact from a dream consolidation result.
|
|
51
|
-
* Used when the idle pipeline produces new memories that should be
|
|
52
|
-
* carried into the next sprint's context.
|
|
53
|
-
*/
|
|
54
|
-
static fromDream(opts) {
|
|
55
|
-
return {
|
|
56
|
-
goal: opts.goal,
|
|
57
|
-
sprint: opts.sprint ?? 1,
|
|
58
|
-
progressSummary: `Memory consolidated: ${opts.dreamResult.entriesAdded} added, ${opts.dreamResult.entriesRemoved} removed.`,
|
|
59
|
-
openTasks: [],
|
|
60
|
-
contractStatus: [],
|
|
61
|
-
driftRate24h: 0,
|
|
62
|
-
blockedOn: [],
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
49
|
/**
|
|
66
50
|
* Render the artifact as a compact injection string for the next agent's
|
|
67
51
|
* working partition (not system — this is a handoff note, not a permanent rule).
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { AttemptBody, AttemptBodyContext, AttemptBodyEvent } from "../harness/harness.js";
|
|
2
|
+
import type { AttemptJudge, JudgeContext, JudgeResult } from "../harness/judge.js";
|
|
3
|
+
import type { ContractCheckResult, VerificationContract } from "./contract.js";
|
|
3
4
|
import type { HandoffArtifact } from "./handoff.js";
|
|
4
|
-
|
|
5
|
-
criterionId: string;
|
|
6
|
-
text: string;
|
|
7
|
-
detail: string;
|
|
8
|
-
}
|
|
5
|
+
import type { AgentPool } from "./pool.js";
|
|
9
6
|
export interface ContractOutcome {
|
|
10
7
|
success: boolean;
|
|
11
8
|
artifact: string;
|
|
@@ -14,45 +11,17 @@ export interface ContractOutcome {
|
|
|
14
11
|
totalTokensConsumed: number;
|
|
15
12
|
handoff: HandoffArtifact;
|
|
16
13
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
14
|
+
/** The creator-verifier body owns execution only; verification is an AttemptJudge. */
|
|
15
|
+
export declare class CreatorVerifierBody implements AttemptBody {
|
|
16
|
+
private readonly pool;
|
|
17
|
+
private readonly contract;
|
|
18
|
+
constructor(pool: AgentPool, contract: VerificationContract);
|
|
19
|
+
run(context: AttemptBodyContext): AsyncIterable<AttemptBodyEvent>;
|
|
22
20
|
}
|
|
23
|
-
/**
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
* 3. Feedback returned to the executor is a structured list of Violations,
|
|
30
|
-
* not a free-text LLM summary.
|
|
31
|
-
*
|
|
32
|
-
* Protocol per attempt:
|
|
33
|
-
* executor.run(goal, contract) → artifact
|
|
34
|
-
* verifier.runIsolated(artifact, contract) → audit text
|
|
35
|
-
* parse audit text → ContractCheckResult[]
|
|
36
|
-
* all required criteria pass → Done
|
|
37
|
-
* violations remain → inject only violation list into next executor goal
|
|
38
|
-
* maxAttempts exceeded → produce HandoffArtifact with blocked_on
|
|
39
|
-
*/
|
|
40
|
-
export declare class ContractDrivenHarness {
|
|
41
|
-
private pool;
|
|
42
|
-
private contract;
|
|
43
|
-
private maxAttempts;
|
|
44
|
-
private onViolation?;
|
|
45
|
-
constructor(pool: AgentPool, contract: VerificationContract, options?: ContractHarnessOptions);
|
|
46
|
-
stream(): AsyncIterable<ContractOutcome>;
|
|
47
|
-
run(): Promise<ContractOutcome>;
|
|
48
|
-
private _findViolations;
|
|
49
|
-
private _formatViolationsForFeedback;
|
|
50
|
-
/**
|
|
51
|
-
* Parse the verifier's free-text audit into structured ContractCheckResult[].
|
|
52
|
-
*
|
|
53
|
-
* The verifier is prompted to produce a structured PASS/FAIL per criterion.
|
|
54
|
-
* This parser handles the common patterns; callers can subclass and override
|
|
55
|
-
* for stricter parsing.
|
|
56
|
-
*/
|
|
57
|
-
private _parseAuditText;
|
|
21
|
+
/** Structured verifier output only. Free-text PASS/FAIL inference is intentionally unsupported. */
|
|
22
|
+
export declare class StructuredContractJudge implements AttemptJudge {
|
|
23
|
+
private readonly pool;
|
|
24
|
+
private readonly contract;
|
|
25
|
+
constructor(pool: AgentPool, contract: VerificationContract);
|
|
26
|
+
judge(context: JudgeContext): Promise<JudgeResult>;
|
|
58
27
|
}
|
|
@@ -1,169 +1,68 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { formatContractForSystemPrompt
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
* ContractDrivenHarness — the core multi-agent execution primitive.
|
|
6
|
-
*
|
|
7
|
-
* Differs from HarnessLoop in three ways:
|
|
8
|
-
* 1. Executor and verifier are **separate Agent instances** — no shared history.
|
|
9
|
-
* 2. Verifier receives only the artifact + contract, not the implementation transcript.
|
|
10
|
-
* 3. Feedback returned to the executor is a structured list of Violations,
|
|
11
|
-
* not a free-text LLM summary.
|
|
12
|
-
*
|
|
13
|
-
* Protocol per attempt:
|
|
14
|
-
* executor.run(goal, contract) → artifact
|
|
15
|
-
* verifier.runIsolated(artifact, contract) → audit text
|
|
16
|
-
* parse audit text → ContractCheckResult[]
|
|
17
|
-
* all required criteria pass → Done
|
|
18
|
-
* violations remain → inject only violation list into next executor goal
|
|
19
|
-
* maxAttempts exceeded → produce HandoffArtifact with blocked_on
|
|
20
|
-
*/
|
|
21
|
-
export class ContractDrivenHarness {
|
|
1
|
+
import { parseVerdict } from "../runtime/eval.js";
|
|
2
|
+
import { formatContractForSystemPrompt } from "./contract.js";
|
|
3
|
+
/** The creator-verifier body owns execution only; verification is an AttemptJudge. */
|
|
4
|
+
export class CreatorVerifierBody {
|
|
22
5
|
pool;
|
|
23
6
|
contract;
|
|
24
|
-
|
|
25
|
-
onViolation;
|
|
26
|
-
constructor(pool, contract, options = {}) {
|
|
7
|
+
constructor(pool, contract) {
|
|
27
8
|
this.pool = pool;
|
|
28
9
|
this.contract = contract;
|
|
29
|
-
this.maxAttempts = options.maxAttempts ?? 3;
|
|
30
|
-
this.onViolation = options.onViolation;
|
|
31
|
-
if (options.coordinator) {
|
|
32
|
-
this.pool.configureCoordinator(options.coordinator.opts, options.coordinator.sessionId);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
async *stream() {
|
|
36
|
-
yield await this.run();
|
|
37
10
|
}
|
|
38
|
-
async run() {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
artifact = execResult.result.finalMessage?.content ?? "";
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
artifact = await collectText(this.pool.get("executor").run({
|
|
60
|
-
sessionId: crypto.randomUUID(),
|
|
61
|
-
goal: executorGoal,
|
|
62
|
-
criteria: contractToCriteriaStrings(this.contract),
|
|
63
|
-
}));
|
|
64
|
-
}
|
|
65
|
-
// ── Phase 2: Verifier ──────────────────────────────────────────────────
|
|
66
|
-
// Verifier sees: artifact + contract only. No executor history.
|
|
67
|
-
const auditText = await this.pool.verify({ contract: this.contract, artifact });
|
|
68
|
-
// ── Phase 3: Parse audit → ContractCheckResult[] ──────────────────────
|
|
69
|
-
checkResults = this._parseAuditText(auditText);
|
|
70
|
-
const violations = this._findViolations(checkResults);
|
|
71
|
-
if (violations.length === 0) {
|
|
72
|
-
// All required criteria passed
|
|
73
|
-
return {
|
|
74
|
-
success: true,
|
|
75
|
-
artifact,
|
|
76
|
-
checkResults,
|
|
77
|
-
attemptsUsed,
|
|
78
|
-
totalTokensConsumed: 0,
|
|
79
|
-
handoff: HandoffBus.fromContractOutcome({
|
|
80
|
-
contract: this.contract,
|
|
81
|
-
checkResults,
|
|
82
|
-
artifact,
|
|
83
|
-
success: true,
|
|
84
|
-
}),
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
this.onViolation?.(violations);
|
|
88
|
-
}
|
|
89
|
-
// Max attempts exhausted
|
|
90
|
-
const blockedOn = this._findViolations(checkResults).map(v => `[${v.criterionId}] ${v.text}: ${v.detail}`);
|
|
91
|
-
return {
|
|
92
|
-
success: false,
|
|
93
|
-
artifact,
|
|
94
|
-
checkResults,
|
|
95
|
-
attemptsUsed,
|
|
96
|
-
totalTokensConsumed: 0,
|
|
97
|
-
handoff: HandoffBus.fromContractOutcome({
|
|
98
|
-
contract: this.contract,
|
|
99
|
-
checkResults,
|
|
100
|
-
artifact,
|
|
101
|
-
success: false,
|
|
102
|
-
blockedOn,
|
|
103
|
-
}),
|
|
11
|
+
async *run(context) {
|
|
12
|
+
const contractBlock = formatContractForSystemPrompt(this.contract);
|
|
13
|
+
const result = await this.pool.execute("executor", {
|
|
14
|
+
sessionId: context.sessionId,
|
|
15
|
+
goal: `${contractBlock}\n\n---\n\n${context.goal}`,
|
|
16
|
+
...(context.contextInput ? { contextInput: context.contextInput } : {}),
|
|
17
|
+
verificationContractId: this.contract.id,
|
|
18
|
+
});
|
|
19
|
+
const artifact = result.result.finalMessage?.content ?? "";
|
|
20
|
+
if (artifact)
|
|
21
|
+
yield { type: "token", text: artifact };
|
|
22
|
+
yield {
|
|
23
|
+
type: "body_done",
|
|
24
|
+
runStatus: String(result.result.termination),
|
|
25
|
+
result: artifact,
|
|
26
|
+
turns: result.result.turnsUsed,
|
|
27
|
+
totalTokens: result.result.totalTokensUsed,
|
|
28
|
+
...(result.submittedNodes?.length ? { submittedNodes: result.submittedNodes } : {}),
|
|
104
29
|
};
|
|
105
30
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
text: criterion.text,
|
|
115
|
-
detail: result.evidence ?? "no evidence provided",
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return violations;
|
|
121
|
-
}
|
|
122
|
-
_formatViolationsForFeedback(results) {
|
|
123
|
-
return this._findViolations(results)
|
|
124
|
-
.map(v => `- [${v.criterionId}] ${v.text}: ${v.detail}`)
|
|
125
|
-
.join("\n");
|
|
31
|
+
}
|
|
32
|
+
/** Structured verifier output only. Free-text PASS/FAIL inference is intentionally unsupported. */
|
|
33
|
+
export class StructuredContractJudge {
|
|
34
|
+
pool;
|
|
35
|
+
contract;
|
|
36
|
+
constructor(pool, contract) {
|
|
37
|
+
this.pool = pool;
|
|
38
|
+
this.contract = contract;
|
|
126
39
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
* for stricter parsing.
|
|
133
|
-
*/
|
|
134
|
-
_parseAuditText(auditText) {
|
|
135
|
-
const results = [];
|
|
136
|
-
const lower = auditText.toLowerCase();
|
|
137
|
-
for (const criterion of this.contract.acceptance) {
|
|
138
|
-
// Look for explicit "id: PASS" or "id: FAIL" patterns from the verifier prompt
|
|
139
|
-
const idPattern = new RegExp(`\\b${criterion.id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b[^\\n]*?(pass|fail)`, "i");
|
|
140
|
-
const match = auditText.match(idPattern);
|
|
141
|
-
if (match) {
|
|
142
|
-
const passed = match[1].toLowerCase() === "pass";
|
|
143
|
-
// Extract the line as evidence
|
|
144
|
-
const lineStart = auditText.lastIndexOf("\n", match.index ?? 0) + 1;
|
|
145
|
-
const lineEnd = auditText.indexOf("\n", match.index ?? 0);
|
|
146
|
-
const evidence = auditText.slice(lineStart, lineEnd > 0 ? lineEnd : undefined).trim();
|
|
147
|
-
results.push({ criterionId: criterion.id, passed, evidence });
|
|
148
|
-
}
|
|
149
|
-
else {
|
|
150
|
-
// Fallback: search for criterion text near PASS/FAIL keywords
|
|
151
|
-
const textIdx = lower.indexOf(criterion.text.toLowerCase().slice(0, 30));
|
|
152
|
-
if (textIdx !== -1) {
|
|
153
|
-
const window = lower.slice(textIdx, textIdx + 200);
|
|
154
|
-
const passed = window.includes("pass") && !window.includes("fail");
|
|
155
|
-
results.push({ criterionId: criterion.id, passed, evidence: "inferred from context" });
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// No mention found — conservative: treat as failed
|
|
159
|
-
results.push({
|
|
160
|
-
criterionId: criterion.id,
|
|
161
|
-
passed: false,
|
|
162
|
-
evidence: "criterion not mentioned in audit",
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
}
|
|
40
|
+
async judge(context) {
|
|
41
|
+
const auditText = await this.pool.verify({ contract: this.contract, artifact: context.result });
|
|
42
|
+
const wire = JSON.parse(auditText);
|
|
43
|
+
if (typeof wire !== "object" || wire === null || Array.isArray(wire)) {
|
|
44
|
+
throw new Error("structured verifier output must be a JSON object");
|
|
166
45
|
}
|
|
167
|
-
|
|
46
|
+
const parsed = parseVerdict(auditText);
|
|
47
|
+
const details = this.contract.acceptance.map(criterion => {
|
|
48
|
+
const detail = parsed.details.find(candidate => candidate.criterion === criterion.id || candidate.criterion === criterion.text);
|
|
49
|
+
return detail
|
|
50
|
+
? { ...detail, criterion: criterion.id }
|
|
51
|
+
: {
|
|
52
|
+
criterion: criterion.id,
|
|
53
|
+
passed: false,
|
|
54
|
+
score: 0,
|
|
55
|
+
feedback: "criterion missing from structured verifier output",
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
const requiredPassed = this.contract.acceptance.every((criterion, index) => !criterion.required || details[index].passed);
|
|
59
|
+
return {
|
|
60
|
+
verdict: {
|
|
61
|
+
passed: parsed.passed && requiredPassed,
|
|
62
|
+
overallScore: parsed.overallScore,
|
|
63
|
+
feedback: parsed.feedback,
|
|
64
|
+
details,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
168
67
|
}
|
|
169
68
|
}
|
|
@@ -2,8 +2,8 @@ export type { AcceptanceCriterion, VerificationContract, ContractCheckResult, }
|
|
|
2
2
|
export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./contract.js";
|
|
3
3
|
export { AgentPool } from "./pool.js";
|
|
4
4
|
export type { AgentRole, IsolatedVerifierContext } from "./pool.js";
|
|
5
|
-
export {
|
|
6
|
-
export type { ContractOutcome
|
|
5
|
+
export { CreatorVerifierBody, StructuredContractJudge } from "./harness.js";
|
|
6
|
+
export type { ContractOutcome } from "./harness.js";
|
|
7
7
|
export { HandoffBus } from "./handoff.js";
|
|
8
8
|
export type { HandoffArtifact, ContractOutcomeInput } from "./handoff.js";
|
|
9
9
|
export { CreatorVerifierMode, OrchestrationMode } from "./modes/creator-verifier.js";
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./contract.js";
|
|
2
2
|
// AgentPool
|
|
3
3
|
export { AgentPool } from "./pool.js";
|
|
4
|
-
|
|
5
|
-
export { ContractDrivenHarness } from "./harness.js";
|
|
4
|
+
export { CreatorVerifierBody, StructuredContractJudge } from "./harness.js";
|
|
6
5
|
// HandoffBus
|
|
7
6
|
export { HandoffBus } from "./handoff.js";
|
|
8
7
|
// Collaboration modes
|