@deepstrike/sdk 0.2.37 → 0.2.38

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/index.d.ts CHANGED
@@ -31,5 +31,5 @@ export { Governance } from "./governance.js";
31
31
  export type { GovernanceVerdict, GovernancePolicy, GovernanceConstraint } from "./governance.js";
32
32
  export { AgentPool } from "./collaboration/pool.js";
33
33
  export type { RuntimeSignal, SignalSource } from "./signals/types.js";
34
- export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolChunk, ToolDeltaEvent, ToolSuspendEvent, ToolResultEvent, ToolAuditFailedEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, LLMProvider, RetryConfig, TokenUsage, } from "./types.js";
34
+ export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolChunk, ToolDeltaEvent, ToolSuspendEvent, ToolResultEvent, ToolAuditFailedEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, EntropySample, EntropySampleEvent, EntropyAlertEvent, EntropyWatchOptions, LLMProvider, RetryConfig, TokenUsage, } from "./types.js";
35
35
  export type { WorkflowSpec, WorkflowNodeSpec, } from "./types/agent.js";
@@ -88,6 +88,25 @@ export function kernelObservationToSessionEvent(obs, turn, opts = {}) {
88
88
  turn: t,
89
89
  history_len: obs.history_len ?? 0,
90
90
  };
91
+ case "entropy_sample":
92
+ return {
93
+ kind: "entropy_sample",
94
+ turn: t,
95
+ score: obs.score ?? 0,
96
+ score_version: obs.score_version ?? 0,
97
+ rho: obs.rho ?? 0,
98
+ repeat_pressure: obs.repeat_pressure ?? 0,
99
+ failure_rate: obs.failure_rate ?? 0,
100
+ rollbacks_in_window: obs.rollbacks_in_window ?? 0,
101
+ window_turns: obs.window_turns ?? 0,
102
+ };
103
+ case "entropy_alert":
104
+ return {
105
+ kind: "entropy_alert",
106
+ turn: t,
107
+ score: obs.score ?? 0,
108
+ threshold: obs.threshold ?? 0,
109
+ };
91
110
  case "agent_process_changed":
92
111
  return {
93
112
  kind: "agent_process_changed",
@@ -1,4 +1,4 @@
1
- import type { Message, RenderedContext, TaskUpdate, ToolCall, ToolResult, ToolSchema } from "../types.js";
1
+ import type { EntropySample, Message, RenderedContext, TaskUpdate, ToolCall, ToolResult, ToolSchema } from "../types.js";
2
2
  import type { SkillMetadata } from "../skills/loader.js";
3
3
  import type { RollbackReason } from "./session-log.js";
4
4
  export declare const KERNEL_ABI_VERSION = 1;
@@ -114,6 +114,14 @@ export interface KernelObservation {
114
114
  /** workflow_completed. */
115
115
  completed?: string[];
116
116
  failed?: string[];
117
+ score?: number;
118
+ score_version?: number;
119
+ rho?: number;
120
+ repeat_pressure?: number;
121
+ failure_rate?: number;
122
+ rollbacks_in_window?: number;
123
+ window_turns?: number;
124
+ threshold?: number;
117
125
  }
118
126
  export declare function toolSchemaToKernel(schema: ToolSchema): Record<string, unknown>;
119
127
  export declare function skillMetadataToKernel(skill: SkillMetadata): Record<string, unknown>;
@@ -125,6 +133,8 @@ export declare function capabilitySkill(skill: SkillMetadata): Record<string, un
125
133
  export declare function capabilityMarker(kind: string, id: string, description: string): Record<string, unknown>;
126
134
  export declare function capabilityCommandMount(capability: Record<string, unknown>, mountedBy?: string, mountReason?: string): Record<string, unknown>;
127
135
  export declare function capabilityCommandUnmount(capabilityKind: string, id: string): Record<string, unknown>;
136
+ /** Camel-case an `entropy_sample` kernel observation into the SDK's `EntropySample`. */
137
+ export declare function entropySampleFromObservation(obs: KernelObservation): EntropySample;
128
138
  export declare function kernelApply(runtime: KernelRuntimeHandle, pending: KernelObservation[], event: Record<string, unknown>): KernelObservation[];
129
139
  export declare function kernelAction(runtime: KernelRuntimeHandle, pending: KernelObservation[], event: Record<string, unknown>): KernelRunnerAction;
130
140
  /**
@@ -135,6 +135,19 @@ export function capabilityCommandUnmount(capabilityKind, id) {
135
135
  function parseStep(raw) {
136
136
  return JSON.parse(raw);
137
137
  }
138
+ /** Camel-case an `entropy_sample` kernel observation into the SDK's `EntropySample`. */
139
+ export function entropySampleFromObservation(obs) {
140
+ return {
141
+ turn: obs.turn ?? 0,
142
+ score: obs.score ?? 0,
143
+ scoreVersion: obs.score_version ?? 0,
144
+ rho: obs.rho ?? 0,
145
+ repeatPressure: obs.repeat_pressure ?? 0,
146
+ failureRate: obs.failure_rate ?? 0,
147
+ rollbacksInWindow: obs.rollbacks_in_window ?? 0,
148
+ windowTurns: obs.window_turns ?? 0,
149
+ };
150
+ }
138
151
  function kernelMessageToSdk(raw) {
139
152
  const content = raw.content;
140
153
  const message = {
@@ -1,4 +1,4 @@
1
- import type { LLMProvider, Message, ContentPart, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse, AsyncSummarizer, DreamSummarizer } from "../types.js";
1
+ import type { LLMProvider, Message, ContentPart, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse, AsyncSummarizer, DreamSummarizer, EntropySample, EntropyWatchOptions } from "../types.js";
2
2
  import type { DreamStore, MemoryEntry, MemoryQuery, MemoryWriteRequest } from "../memory/protocols.js";
3
3
  import type { KnowledgeSource } from "../knowledge/source.js";
4
4
  import type { SignalSource, RuntimeSignalUrgency } from "../signals/types.js";
@@ -161,6 +161,14 @@ export interface RuntimeOptions {
161
161
  * entries and skill pins are never budget-evicted. `0` disables. Default: kernel's 0.25.
162
162
  */
163
163
  knowledgeBudgetRatio?: number;
164
+ /**
165
+ * Opt-in kernel entropy watch: threshold alerting over the per-turn session-entropy score
166
+ * (`entropy_sample` events stream unconditionally regardless). When the score crosses
167
+ * `threshold` — armed via hysteresis and past the cooldown — the run emits an `entropy_alert`
168
+ * stream event (and session-log record); with `notifyModel` the kernel also feeds the model a
169
+ * durable `[SIGNAL]` directive. Absent ⇒ disabled (kernel default).
170
+ */
171
+ entropyWatch?: EntropyWatchOptions;
164
172
  /**
165
173
  * K3: default lease (in turns) for every skill activation. After that many turns the kernel
166
174
  * auto-deactivates the skill — toolset re-widens, knowledge pin boundary-swept — exactly like
@@ -307,6 +315,8 @@ export declare class RuntimeRunner {
307
315
  * at the next safe point (after the tool turn resolves, kernel back in Reason — not suspended). */
308
316
  private pendingAuthoredWorkflows;
309
317
  private dashboard;
318
+ /** Most recent kernel entropy sample of the active/last run (see `latestEntropy`). */
319
+ private lastEntropySample;
310
320
  constructor(opts: RuntimeOptions);
311
321
  /** Host configuration (for coordinator / sub-agent spawn). */
312
322
  get hostOptions(): RuntimeOptions;
@@ -468,6 +478,10 @@ export declare class RuntimeRunner {
468
478
  * without wiring a full `SignalSource`. `urgency` maps to the kernel disposition ladder: `"normal"`
469
479
  * queues for the next boundary (default), `"high"` soft-interrupts, `"critical"` preempts. */
470
480
  injectNote(text: string, urgency?: RuntimeSignalUrgency): void;
481
+ /** The most recent kernel session-entropy sample (one per completed turn), or `null` before the
482
+ * first boundary. A pull companion to the streamed `entropy_sample` events — hosts polling from
483
+ * outside the stream (e.g. a heartbeat supervisor) read the latest measurement here. */
484
+ latestEntropy(): EntropySample | null;
471
485
  /** Injected-note drain shared by the main loop's per-turn poll: injected notes first (FIFO), then
472
486
  * the configured `signalSource`. Keeps the two inbound channels on one code path so they never drift. */
473
487
  private nextInboundSignal;
@@ -5,7 +5,7 @@ import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-rep
5
5
  import { sanitizeReplayText } from "./replay-sanitize.js";
6
6
  import { buildLlmCompletedEvent, buildRunTerminalEvent, buildWorkflowNodeCompletedEvent, buildWorkflowNodesSubmittedEvent, recoverCompletedWorkflowNodes, recoverSubmittedWorkflowNodes, repairEventsForRecovery, } from "./session-repair.js";
7
7
  import { KernelPrimitivesDashboard } from "./kernel-primitives-dashboard.js";
8
- import { capabilityMarker, capabilitySkill, capabilityTool, capabilityCommandMount, capabilityCommandUnmount, kernelAction, kernelApply, kernelMaybeAction, messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
8
+ import { capabilityMarker, capabilitySkill, capabilityTool, capabilityCommandMount, capabilityCommandUnmount, entropySampleFromObservation, kernelAction, kernelApply, kernelMaybeAction, messageToKernelMessage, skillMetadataToKernel, taskUpdateToKernel, toolResultToKernel, toolSchemaToKernel, } from "./kernel-step.js";
9
9
  import { agentRunSpecToKernel, findSpawnProcessObservation, milestoneCheckPass, milestoneCheckResultToKernel, spawnObservationToManifest, subAgentResultToKernel, submitWorkflowNodesToKernel, submitWorkflowToKernel, workflowBudgetNote, workflowNodeToManifest, workflowNodeToSpec, workflowSpecToKernel, } from "../types/agent.js";
10
10
  import { defaultSubAgentOrchestrator } from "./sub-agent-orchestrator.js";
11
11
  import { extractJsonValue, schemaInstruction, schemaRetryInstruction, validateAgainstSchema, } from "./output-schema.js";
@@ -40,6 +40,8 @@ export class RuntimeRunner {
40
40
  * at the next safe point (after the tool turn resolves, kernel back in Reason — not suspended). */
41
41
  pendingAuthoredWorkflows = [];
42
42
  dashboard = null;
43
+ /** Most recent kernel entropy sample of the active/last run (see `latestEntropy`). */
44
+ lastEntropySample = null;
43
45
  constructor(opts) {
44
46
  this.opts = opts;
45
47
  if (opts.enableDiagnosticsDashboard) {
@@ -209,6 +211,18 @@ export class RuntimeRunner {
209
211
  if (this.opts.knowledgeBudgetRatio !== undefined) {
210
212
  config.knowledge_budget_ratio = this.opts.knowledgeBudgetRatio;
211
213
  }
214
+ // Entropy watch (opt-in): threshold alerting over the per-turn session-entropy score.
215
+ // Absent fields keep kernel defaults (threshold 0.65 / hysteresis 0.1 / cooldown 4).
216
+ if (this.opts.entropyWatch !== undefined) {
217
+ const ew = this.opts.entropyWatch;
218
+ config.entropy_watch = {
219
+ enabled: ew.enabled ?? true,
220
+ ...(ew.threshold !== undefined ? { threshold: ew.threshold } : {}),
221
+ ...(ew.hysteresis !== undefined ? { hysteresis: ew.hysteresis } : {}),
222
+ ...(ew.cooldownTurns !== undefined ? { cooldown_turns: ew.cooldownTurns } : {}),
223
+ ...(ew.notifyModel !== undefined ? { notify_model: ew.notifyModel } : {}),
224
+ };
225
+ }
212
226
  kernelApply(runtime, this.pendingObservations, { kind: "configure_run", config });
213
227
  }
214
228
  async appendMemorySyscallObservations(sessionId, observations) {
@@ -805,6 +819,12 @@ export class RuntimeRunner {
805
819
  payload: { goal: text },
806
820
  });
807
821
  }
822
+ /** The most recent kernel session-entropy sample (one per completed turn), or `null` before the
823
+ * first boundary. A pull companion to the streamed `entropy_sample` events — hosts polling from
824
+ * outside the stream (e.g. a heartbeat supervisor) read the latest measurement here. */
825
+ latestEntropy() {
826
+ return this.lastEntropySample;
827
+ }
808
828
  /** Injected-note drain shared by the main loop's per-turn poll: injected notes first (FIFO), then
809
829
  * the configured `signalSource`. Keeps the two inbound channels on one code path so they never drift. */
810
830
  async nextInboundSignal() {
@@ -1711,10 +1731,27 @@ export class RuntimeRunner {
1711
1731
  }
1712
1732
  catch { /* malformed skill args — skip activation */ }
1713
1733
  }
1734
+ const entropyObsStart = this.pendingObservations.length;
1714
1735
  action = kernelAction(runtime, this.pendingObservations, {
1715
1736
  kind: "tool_results",
1716
1737
  results: toolResults.map(toolResultToKernel),
1717
1738
  });
1739
+ // Surface the boundary's entropy measurement live (the heartbeat watch source) —
1740
+ // the session-log record lands via the normal appendObservations path.
1741
+ for (const obs of this.pendingObservations.slice(entropyObsStart)) {
1742
+ if (obs.kind === "entropy_sample") {
1743
+ this.lastEntropySample = entropySampleFromObservation(obs);
1744
+ yield { type: "entropy_sample", sample: this.lastEntropySample };
1745
+ }
1746
+ else if (obs.kind === "entropy_alert") {
1747
+ yield {
1748
+ type: "entropy_alert",
1749
+ turn: obs.turn ?? 0,
1750
+ score: obs.score ?? 0,
1751
+ threshold: obs.threshold ?? 0,
1752
+ };
1753
+ }
1754
+ }
1718
1755
  }
1719
1756
  else if (action.kind === "evaluate_milestone") {
1720
1757
  const milestonePolicy = this.opts.milestonePolicy ?? "require_verifier";
@@ -160,6 +160,21 @@ export type SessionEvent = {
160
160
  kind: "checkpoint_taken";
161
161
  turn: number;
162
162
  history_len: number;
163
+ } | {
164
+ kind: "entropy_sample";
165
+ turn: number;
166
+ score: number;
167
+ score_version: number;
168
+ rho: number;
169
+ repeat_pressure: number;
170
+ failure_rate: number;
171
+ rollbacks_in_window: number;
172
+ window_turns: number;
173
+ } | {
174
+ kind: "entropy_alert";
175
+ turn: number;
176
+ score: number;
177
+ threshold: number;
163
178
  } | {
164
179
  kind: "agent_process_changed";
165
180
  turn: number;
package/dist/types.d.ts CHANGED
@@ -205,6 +205,54 @@ export interface ToolAuditFailedEvent extends StreamEvent {
205
205
  label: string;
206
206
  error: string;
207
207
  }
208
+ /** Kernel session-entropy measurement at a completed turn boundary. "Entropy" = session
209
+ * disorder: repetition, tool failures, rollbacks, context pressure. The component vector is
210
+ * the contract; `score` is a versioned default fold (`scoreVersion`). All normalized
211
+ * components are in [0, 1]. */
212
+ export interface EntropySample {
213
+ turn: number;
214
+ score: number;
215
+ scoreVersion: number;
216
+ /** Context pressure after this boundary's eviction pass. */
217
+ rho: number;
218
+ /** Consecutive-identical-turn streak, normalized against the RepeatFuse deny rung. */
219
+ repeatPressure: number;
220
+ /** Errored tool results / total tool results over the sliding window. */
221
+ failureRate: number;
222
+ /** Raw rollback count inside the window (normalize with `windowTurns`). */
223
+ rollbacksInWindow: number;
224
+ /** Effective window size in completed turns. */
225
+ windowTurns: number;
226
+ }
227
+ /** One kernel entropy sample, emitted once per completed turn (a heartbeat watch source:
228
+ * subscribe to drive an external supervisor without tailing the audit log). */
229
+ export interface EntropySampleEvent extends StreamEvent {
230
+ type: "entropy_sample";
231
+ sample: EntropySample;
232
+ }
233
+ /** The opt-in kernel entropy watch tripped: `score` crossed `threshold` while armed and
234
+ * cooled down (see `RunnerOptions.entropyWatch`). Correlate components via the same-turn
235
+ * `entropy_sample` event. */
236
+ export interface EntropyAlertEvent extends StreamEvent {
237
+ type: "entropy_alert";
238
+ turn: number;
239
+ score: number;
240
+ threshold: number;
241
+ }
242
+ /** Opt-in kernel-side threshold watch over the per-turn entropy score. Sampling itself is
243
+ * unconditional; this only controls alerting. `notifyModel` additionally routes the alert
244
+ * into the model's own signal channel (durable `[SIGNAL]` directive at the next boundary) —
245
+ * leave it off when a host supervisor injects task-aware guidance itself. */
246
+ export interface EntropyWatchOptions {
247
+ enabled?: boolean;
248
+ /** Alert when `score >= threshold` (kernel default 0.65). */
249
+ threshold?: number;
250
+ /** Re-arm only after the score falls below `threshold - hysteresis` (default 0.1). */
251
+ hysteresis?: number;
252
+ /** Minimum completed turns between two alerts (default 4). */
253
+ cooldownTurns?: number;
254
+ notifyModel?: boolean;
255
+ }
208
256
  export interface TokenUsage {
209
257
  /** Full prompt size: uncached input + cache reads + cache writes. */
210
258
  inputTokens: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.2.37",
3
+ "version": "0.2.38",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@anthropic-ai/sdk": "^0.99.0",
75
- "@deepstrike/core": "0.2.37",
75
+ "@deepstrike/core": "0.2.38",
76
76
  "@google/generative-ai": "^0.24.1",
77
77
  "openai": "^5.23.2"
78
78
  },