@deepstrike/sdk 0.2.39 → 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.
Files changed (102) hide show
  1. package/README.md +61 -31
  2. package/dist/collaboration/contract.d.ts +2 -2
  3. package/dist/collaboration/contract.js +2 -2
  4. package/dist/collaboration/handoff.d.ts +2 -14
  5. package/dist/collaboration/handoff.js +1 -17
  6. package/dist/collaboration/harness.d.ts +16 -47
  7. package/dist/collaboration/harness.js +57 -158
  8. package/dist/collaboration/index.d.ts +2 -2
  9. package/dist/collaboration/index.js +1 -2
  10. package/dist/collaboration/modes/creator-verifier.js +42 -6
  11. package/dist/collaboration/pool.d.ts +8 -0
  12. package/dist/collaboration/pool.js +56 -3
  13. package/dist/harness/harness.d.ts +97 -97
  14. package/dist/harness/harness.js +190 -144
  15. package/dist/harness/judge.d.ts +3 -2
  16. package/dist/harness/judge.js +7 -3
  17. package/dist/harness/public.d.ts +5 -3
  18. package/dist/harness/public.js +3 -2
  19. package/dist/index.d.ts +22 -7
  20. package/dist/index.js +8 -1
  21. package/dist/kernel.d.ts +12 -39
  22. package/dist/memory/agent.d.ts +8 -41
  23. package/dist/memory/agent.js +34 -117
  24. package/dist/memory/extraction.d.ts +4 -0
  25. package/dist/memory/extraction.js +79 -0
  26. package/dist/memory/in-memory-store.d.ts +28 -15
  27. package/dist/memory/in-memory-store.js +74 -25
  28. package/dist/memory/protocols.d.ts +56 -56
  29. package/dist/memory/protocols.js +1 -0
  30. package/dist/memory/public.d.ts +3 -1
  31. package/dist/memory/public.js +1 -0
  32. package/dist/memory/ranking.d.ts +33 -0
  33. package/dist/memory/ranking.js +77 -0
  34. package/dist/memory/retention.d.ts +17 -0
  35. package/dist/memory/retention.js +54 -0
  36. package/dist/os/public.d.ts +3 -3
  37. package/dist/os/public.js +1 -1
  38. package/dist/providers/base.d.ts +8 -0
  39. package/dist/providers/base.js +0 -0
  40. package/dist/providers/gemini.js +12 -0
  41. package/dist/providers/ollama.js +3 -1
  42. package/dist/providers/openai-responses.js +9 -2
  43. package/dist/providers/profiles.d.ts +5 -3
  44. package/dist/providers/profiles.js +3 -3
  45. package/dist/runtime/context-policy.d.ts +35 -0
  46. package/dist/runtime/context-policy.js +66 -0
  47. package/dist/runtime/eval.d.ts +6 -2
  48. package/dist/runtime/eval.js +2 -2
  49. package/dist/runtime/event-stream.d.ts +9 -0
  50. package/dist/runtime/event-stream.js +25 -11
  51. package/dist/runtime/execution-plane.d.ts +5 -1
  52. package/dist/runtime/execution-plane.js +9 -3
  53. package/dist/runtime/facade.js +2 -1
  54. package/dist/runtime/kernel-event-log.d.ts +0 -2
  55. package/dist/runtime/kernel-event-log.js +61 -13
  56. package/dist/runtime/kernel-primitives-dashboard.js +1 -1
  57. package/dist/runtime/kernel-rebuild.d.ts +13 -0
  58. package/dist/runtime/kernel-rebuild.js +75 -0
  59. package/dist/runtime/kernel-step.d.ts +157 -8
  60. package/dist/runtime/kernel-step.js +220 -7
  61. package/dist/runtime/kernel-transaction-log.d.ts +61 -0
  62. package/dist/runtime/kernel-transaction-log.js +149 -0
  63. package/dist/runtime/large-result-spool.d.ts +3 -1
  64. package/dist/runtime/large-result-spool.js +24 -5
  65. package/dist/runtime/loop-driver.d.ts +1 -1
  66. package/dist/runtime/loop-driver.js +2 -7
  67. package/dist/runtime/mcp-proxy-plane.d.ts +1 -0
  68. package/dist/runtime/mcp-proxy-plane.js +23 -6
  69. package/dist/runtime/os-profile.d.ts +9 -10
  70. package/dist/runtime/os-profile.js +14 -10
  71. package/dist/runtime/os-snapshot.d.ts +19 -0
  72. package/dist/runtime/os-snapshot.js +33 -3
  73. package/dist/runtime/process-sandbox-plane.js +16 -11
  74. package/dist/runtime/reaction-checkpoint.d.ts +51 -0
  75. package/dist/runtime/reaction-checkpoint.js +83 -0
  76. package/dist/runtime/reactive-session.d.ts +9 -3
  77. package/dist/runtime/reactive-session.js +44 -14
  78. package/dist/runtime/reliability.d.ts +48 -0
  79. package/dist/runtime/reliability.js +86 -0
  80. package/dist/runtime/remote-vpc-plane.js +4 -3
  81. package/dist/runtime/run-group.d.ts +38 -35
  82. package/dist/runtime/run-group.js +97 -54
  83. package/dist/runtime/runner.d.ts +117 -78
  84. package/dist/runtime/runner.js +1516 -1197
  85. package/dist/runtime/session-log.d.ts +71 -12
  86. package/dist/runtime/session-log.js +192 -32
  87. package/dist/runtime/session-repair.d.ts +11 -7
  88. package/dist/runtime/session-repair.js +11 -8
  89. package/dist/runtime/sub-agent-orchestrator.d.ts +6 -2
  90. package/dist/runtime/sub-agent-orchestrator.js +45 -18
  91. package/dist/signals/gateway.d.ts +23 -10
  92. package/dist/signals/gateway.js +81 -17
  93. package/dist/signals/scheduled.js +0 -1
  94. package/dist/signals/types.d.ts +21 -13
  95. package/dist/skills/loader.js +12 -2
  96. package/dist/tools/index.d.ts +2 -0
  97. package/dist/types/agent.d.ts +40 -1
  98. package/dist/types/agent.js +61 -1
  99. package/dist/types.d.ts +6 -1
  100. package/dist/workflow/public.d.ts +2 -3
  101. package/dist/workflow/public.js +0 -1
  102. package/package.json +2 -2
@@ -1,4 +1,6 @@
1
- import { ContractDrivenHarness } from "../harness.js";
1
+ import { CreatorVerifierBody, StructuredContractJudge } from "../harness.js";
2
+ import { HandoffBus } from "../handoff.js";
3
+ import { AttemptLoop } from "../../harness/harness.js";
2
4
  /**
3
5
  * CreatorVerifierMode — the simplest multi-agent collaboration pattern.
4
6
  *
@@ -31,14 +33,48 @@ export class CreatorVerifierMode {
31
33
  async run(contract) {
32
34
  this._total++;
33
35
  this.pool.ensureCoordinator(this.options.coordinatorSessionId);
34
- const harness = new ContractDrivenHarness(this.pool, contract, {
35
- maxAttempts: this.options.maxAttempts ?? 3,
36
+ const loop = new AttemptLoop({
37
+ body: new CreatorVerifierBody(this.pool, contract),
38
+ judge: new StructuredContractJudge(this.pool, contract),
39
+ stop: { maxAttempts: this.options.maxAttempts ?? 3 },
36
40
  });
37
- const outcome = await harness.run();
38
- if (!outcome.success) {
41
+ const attempt = await loop.run({
42
+ sessionId: crypto.randomUUID(),
43
+ goal: contract.goal,
44
+ criteria: contract.acceptance.map(criterion => ({
45
+ id: criterion.id,
46
+ text: criterion.text,
47
+ required: criterion.required,
48
+ weight: criterion.weight,
49
+ machineCheckable: criterion.machineCheckable,
50
+ })),
51
+ });
52
+ const checkResults = attempt.verdict?.details.map(detail => ({
53
+ criterionId: detail.criterion,
54
+ passed: detail.passed,
55
+ evidence: detail.feedback,
56
+ })) ?? [];
57
+ const success = attempt.outcome === "passed";
58
+ if (!success) {
39
59
  this._failed++;
40
60
  }
41
- return outcome;
61
+ const blockedOn = success
62
+ ? []
63
+ : checkResults.filter(result => !result.passed).map(result => `[${result.criterionId}] ${result.evidence ?? "verification failed"}`);
64
+ return {
65
+ success,
66
+ artifact: attempt.result,
67
+ checkResults,
68
+ attemptsUsed: attempt.attempts,
69
+ totalTokensConsumed: attempt.totalTokens,
70
+ handoff: HandoffBus.fromContractOutcome({
71
+ contract,
72
+ checkResults,
73
+ artifact: attempt.result,
74
+ success,
75
+ ...(blockedOn.length ? { blockedOn } : {}),
76
+ }),
77
+ };
42
78
  }
43
79
  /** Aggregate drift metrics across all runs through this mode instance. */
44
80
  getMetrics() {
@@ -12,6 +12,12 @@ export interface CoordinatorConfig {
12
12
  opts: RuntimeOptions;
13
13
  sessionId: string;
14
14
  }
15
+ export interface RoleExecutionInput {
16
+ sessionId: string;
17
+ goal: string;
18
+ contextInput?: string;
19
+ verificationContractId?: string;
20
+ }
15
21
  export declare class AgentPool {
16
22
  private runners;
17
23
  private coordinator?;
@@ -31,6 +37,8 @@ export declare class AgentPool {
31
37
  * Maps legacy pool roles to kernel roles (executor → implement, etc.).
32
38
  */
33
39
  spawn(role: AgentRole | KernelAgentRole, goal: string, extra?: Partial<Omit<AgentRunSpec, "identity" | "role" | "goal">>): Promise<SubAgentResult>;
40
+ /** Execute a role in a caller-owned session so AttemptLoop can retain transcript across attempts. */
41
+ execute(role: AgentRole, input: RoleExecutionInput): Promise<SubAgentResult>;
34
42
  verify(ctx: IsolatedVerifierContext): Promise<string>;
35
43
  orchestrate(goal: string): Promise<string>;
36
44
  }
@@ -62,6 +62,49 @@ export class AgentPool {
62
62
  };
63
63
  return spawnStandalone(this.coordinator.opts, this.coordinator.sessionId, spec);
64
64
  }
65
+ /** Execute a role in a caller-owned session so AttemptLoop can retain transcript across attempts. */
66
+ async execute(role, input) {
67
+ if (this.coordinator) {
68
+ const kernelRole = KERNEL_ROLE_MAP[role];
69
+ const spec = {
70
+ identity: agentIdentitySub(`${kernelRole}-${input.sessionId}`, input.sessionId, this.coordinator.sessionId),
71
+ role: kernelRole,
72
+ goal: input.goal,
73
+ ...(input.verificationContractId
74
+ ? { verificationContractId: input.verificationContractId }
75
+ : {}),
76
+ };
77
+ return spawnStandalone(this.coordinator.opts, this.coordinator.sessionId, spec, undefined, input.contextInput);
78
+ }
79
+ const runner = this.get(role);
80
+ if (input.contextInput)
81
+ runner.injectNote(input.contextInput);
82
+ let finalText = "";
83
+ let turnsUsed = 0;
84
+ let totalTokensUsed = 0;
85
+ let termination = "error";
86
+ for await (const event of runner.run({ sessionId: input.sessionId, goal: input.goal })) {
87
+ if (event.type === "text_delta")
88
+ finalText += event.delta;
89
+ if (event.type === "done") {
90
+ const done = event;
91
+ turnsUsed = done.iterations;
92
+ totalTokensUsed = done.totalTokens;
93
+ termination = done.status;
94
+ }
95
+ }
96
+ return {
97
+ agentId: `${KERNEL_ROLE_MAP[role]}-${input.sessionId}`,
98
+ result: {
99
+ termination,
100
+ turnsUsed,
101
+ totalTokensUsed,
102
+ ...(finalText
103
+ ? { finalMessage: { role: "assistant", content: finalText, toolCalls: [] } }
104
+ : {}),
105
+ },
106
+ };
107
+ }
65
108
  async verify(ctx) {
66
109
  const contractBlock = formatContractForSystemPrompt(ctx.contract);
67
110
  const auditGoal = [
@@ -71,9 +114,19 @@ export class AgentPool {
71
114
  ctx.artifact, "",
72
115
  "---", "",
73
116
  "Audit the artifact against every criterion in the contract above.",
74
- "For each criterion, state whether it PASSED or FAILED and cite specific evidence.",
75
- "List any anti-patterns you detected.",
76
- "Conclude with an overall PASS or FAIL verdict.",
117
+ "Return only one JSON object with this exact shape:",
118
+ JSON.stringify({
119
+ passed: true,
120
+ overall_score: 1,
121
+ feedback: "overall verification feedback",
122
+ details: ctx.contract.acceptance.map(criterion => ({
123
+ criterion: criterion.id,
124
+ passed: true,
125
+ score: 1,
126
+ feedback: "specific evidence",
127
+ })),
128
+ }, null, 2),
129
+ "Every contract criterion id must appear exactly once in details. Do not emit prose or markdown.",
77
130
  ].join("\n");
78
131
  if (this.coordinator) {
79
132
  const result = await this.spawn("verify", auditGoal, {
@@ -1,49 +1,27 @@
1
1
  import type { RuntimeRunner } from "../runtime/runner.js";
2
- import { collectText } from "../runtime/runner.js";
3
- import type { StreamEvent } from "../types.js";
4
- export interface Criterion {
5
- text: string;
6
- required: boolean;
7
- weight?: number;
8
- /** I3.3 (A4): optional stable identifier from the host's contract layer (e.g. an
9
- * `acceptance[].id` field). The harness does not interpret it; it just threads it through to
10
- * `verdictFn` so the host can dispatch per-criterion deterministic checks by id. */
11
- id?: string;
12
- /** I3.3 (A4): host hint — when true, the host has a deterministic check for this criterion
13
- * and would short-circuit the LLM eval. The harness still defers to the host's `verdictFn`
14
- * for the actual decision; this is purely a transparency field on the request. */
15
- machineCheckable?: boolean;
16
- }
17
- export interface CriterionResult {
18
- criterion: string;
19
- passed: boolean;
20
- score: number;
21
- feedback: string;
22
- }
23
- export interface HarnessRequest {
2
+ import type { SessionEvent } from "../runtime/session-log.js";
3
+ import type { WorkflowNodeSpec } from "../types/agent.js";
4
+ import type { Criterion, Verdict } from "../runtime/eval.js";
5
+ import type { AttemptJudge, JudgeResult } from "./judge.js";
6
+ export type { Criterion, Verdict } from "../runtime/eval.js";
7
+ export interface AttemptRequest {
8
+ sessionId?: string;
24
9
  goal: string;
25
10
  criteria?: Criterion[];
26
11
  extensions?: Record<string, unknown>;
12
+ /** Parent transcript inherited by the first attempt only. */
13
+ inheritEvents?: Array<{
14
+ seq: number;
15
+ event: SessionEvent;
16
+ }>;
27
17
  }
28
- export interface HarnessOutcome {
29
- result: string;
30
- passed: boolean;
31
- iterations: number;
32
- totalTokens: number;
33
- status: string;
34
- overallScore?: number;
35
- feedback?: string;
36
- details?: CriterionResult[];
37
- /** R3-1: nodes the agent submitted via `submit_workflow_nodes` while running under the harness. */
38
- submittedNodes?: import("../types/agent.js").WorkflowNodeSpec[];
39
- }
40
- export interface Verdict {
41
- passed: boolean;
42
- overallScore: number;
43
- feedback: string;
44
- details: CriterionResult[];
18
+ export interface AttemptBodyContext extends AttemptRequest {
19
+ sessionId: string;
20
+ attempt: number;
21
+ /** Carry material delivered as context, never folded into `goal` by the default policy. */
22
+ contextInput?: string;
45
23
  }
46
- export type HarnessEvent = {
24
+ export type AttemptProgressEvent = {
47
25
  type: "token";
48
26
  text: string;
49
27
  } | {
@@ -67,72 +45,94 @@ export type HarnessEvent = {
67
45
  isError: boolean;
68
46
  } | {
69
47
  type: "workflow_nodes_submitted";
70
- nodes: import("../types/agent.js").WorkflowNodeSpec[];
71
- } | {
72
- type: "supervising";
48
+ nodes: WorkflowNodeSpec[];
73
49
  } | {
74
- type: "revising";
75
- verdict: Verdict;
76
- } | {
77
- type: "done";
78
- verdict: Verdict;
79
- iterations: number;
80
- totalTokens: number;
81
- status: string;
82
- } | {
83
- type: "max_attempts_reached";
50
+ type: "body_error";
51
+ message: string;
84
52
  };
85
- export interface QualityGate {
86
- evaluate(request: HarnessRequest, outcome: HarnessOutcome): Promise<boolean>;
53
+ export interface AttemptBodyTerminal {
54
+ type: "body_done";
55
+ runStatus: string;
56
+ result: string;
57
+ turns: number;
58
+ totalTokens: number;
59
+ submittedNodes?: WorkflowNodeSpec[];
87
60
  }
88
- export declare class SinglePassHarness {
89
- private runner;
90
- constructor(runner: RuntimeRunner);
91
- run(request: HarnessRequest): Promise<HarnessOutcome>;
92
- stream(request: HarnessRequest): AsyncIterable<StreamEvent>;
61
+ export type AttemptBodyEvent = AttemptProgressEvent | AttemptBodyTerminal;
62
+ export interface AttemptBody {
63
+ run(context: AttemptBodyContext): AsyncIterable<AttemptBodyEvent>;
93
64
  }
94
- /**
95
- * @deprecated I3.4 (A1): prefer {@link HarnessLoop} with `verdictFn` for host-defined judgment.
96
- * `EvalLoopHarness.stream()` does NOT honor the `gate` passed via `request.gate` (only `.run()`
97
- * does), which is a long-standing footgun for streaming hosts. `HarnessLoop` runs the eval loop
98
- * uniformly across both stream and run, accepts an optional `verdictFn` for short-circuiting the
99
- * built-in LLM eval, and otherwise mirrors `EvalLoopHarness`'s behavior. New code should use
100
- * `HarnessLoop`; existing call sites can migrate by switching the class + (if applicable)
101
- * passing a `verdictFn` for the same gate logic. Slated for removal in a future major. */
102
- export declare class EvalLoopHarness {
103
- private runner;
104
- private gate;
105
- private maxAttempts;
106
- constructor(runner: RuntimeRunner, gate: QualityGate, maxAttempts?: number);
107
- run(request: HarnessRequest): Promise<HarnessOutcome>;
108
- stream(request: HarnessRequest): AsyncIterable<StreamEvent>;
65
+ /** Adapts RuntimeRunner to the body slot without giving the loop knowledge of kernel events. */
66
+ export declare class RuntimeAttemptBody implements AttemptBody {
67
+ private readonly runner;
68
+ constructor(runner: RuntimeRunner);
69
+ run(context: AttemptBodyContext): AsyncIterable<AttemptBodyEvent>;
109
70
  }
110
- /** I3.2 (A2/A3): host-supplied judgment for each attempt's result. Returning a `Verdict` short-
111
- * circuits the built-in LLM eval (no `evalProvider.stream` call); returning `undefined` defers to
112
- * the built-in eval (enables hybrid judgment: machine-checkable items deterministic, subjective
113
- * items LLM). Pure addition — when not set, HarnessLoop.stream() is byte-equivalent to its prior
114
- * behavior. The closure owns its own context (doc reader, deterministic checks, etc.); the SDK
115
- * is intentionally agnostic about what it inspects. */
116
- export type VerdictFn = (ctx: {
71
+ export type VerdictFn = (context: {
117
72
  goal: string;
118
73
  criteria: Criterion[];
119
74
  attempt: number;
120
75
  result: string;
121
76
  }) => Verdict | undefined | Promise<Verdict | undefined>;
122
- export interface HarnessLoopOptions {
123
- maxAttempts?: number;
124
- skillDir?: string;
125
- verdictFn?: VerdictFn;
77
+ export interface PreparedAttempt {
78
+ sessionId: string;
79
+ goal: string;
80
+ contextInput?: string;
81
+ }
82
+ export type CarryPolicy = (context: {
83
+ rootSessionId: string;
84
+ goal: string;
85
+ attempt: number;
86
+ previousVerdict?: Verdict;
87
+ }) => PreparedAttempt | Promise<PreparedAttempt>;
88
+ /** Default: retain the transcript and deliver judge feedback through the runner's signal input. */
89
+ export declare const continueSession: CarryPolicy;
90
+ /** Explicit isolation policy preserving the old fresh-session + goal-feedback behavior. */
91
+ export declare const freshWithFeedback: CarryPolicy;
92
+ export declare function freshWithDigest(digest: (verdict: Verdict, attempt: number) => string | Promise<string>): CarryPolicy;
93
+ export interface StopPolicy {
94
+ maxAttempts: number;
95
+ maxTotalTokens?: number;
96
+ /** Useful for one-shot gates; retry loops normally leave this false. */
97
+ stopOnFailedVerdict?: boolean;
98
+ }
99
+ export type AttemptOutcomeKind = "passed" | "failed_judge" | "exhausted" | "run_error";
100
+ export interface AttemptOutcome {
101
+ outcome: AttemptOutcomeKind;
102
+ runStatus: string;
103
+ verdict?: Verdict;
104
+ result: string;
105
+ attempts: number;
106
+ turns: number;
107
+ totalTokens: number;
108
+ submittedNodes?: WorkflowNodeSpec[];
109
+ }
110
+ export type AttemptLoopEvent = AttemptProgressEvent | {
111
+ type: "judging";
112
+ attempt: number;
113
+ } | {
114
+ type: "retrying";
115
+ attempt: number;
116
+ verdict: Verdict;
117
+ } | {
118
+ type: "completed";
119
+ outcome: AttemptOutcome;
120
+ };
121
+ export interface AttemptLoopOptions {
122
+ body: AttemptBody;
123
+ judge: AttemptJudge;
124
+ carry?: CarryPolicy;
125
+ stop: StopPolicy;
126
+ onPass?: (context: {
127
+ outcome: AttemptOutcome;
128
+ judgeResult: JudgeResult;
129
+ }) => Promise<void> | void;
126
130
  }
127
- export declare class HarnessLoop {
128
- private runner;
129
- private maxAttempts;
130
- private skillDir?;
131
- /** How each attempt is judged. Hybrid (host verdictFn → LLM eval) when a verdictFn is supplied,
132
- * otherwise the built-in LLM eval. The loop just calls `this.judge.judge(...)`. */
133
- private judge;
134
- constructor(runner: RuntimeRunner, evalProvider: import("../types.js").LLMProvider, options?: HarnessLoopOptions);
135
- run(request: HarnessRequest): Promise<HarnessOutcome>;
136
- stream(request: HarnessRequest): AsyncIterable<HarnessEvent>;
131
+ /** One attempt engine. Body, judgment, carry, and stopping are independent policy slots. */
132
+ export declare class AttemptLoop {
133
+ private readonly options;
134
+ private readonly carry;
135
+ constructor(options: AttemptLoopOptions);
136
+ run(request: AttemptRequest): Promise<AttemptOutcome>;
137
+ stream(request: AttemptRequest): AsyncIterable<AttemptLoopEvent>;
137
138
  }
138
- export { collectText };