@deepstrike/sdk 0.2.3 → 0.2.5

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 (35) hide show
  1. package/README.md +287 -70
  2. package/dist/collaboration/modes/creator-verifier.d.ts +0 -3
  3. package/dist/collaboration/modes/creator-verifier.js +2 -6
  4. package/dist/governance.d.ts +36 -0
  5. package/dist/governance.js +22 -0
  6. package/dist/index.d.ts +11 -5
  7. package/dist/index.js +5 -1
  8. package/dist/memory/agent.d.ts +111 -0
  9. package/dist/memory/agent.js +151 -0
  10. package/dist/memory/protocols.d.ts +56 -0
  11. package/dist/providers/deepseek.js +13 -1
  12. package/dist/runtime/execution-plane.d.ts +6 -9
  13. package/dist/runtime/execution-plane.js +53 -25
  14. package/dist/runtime/kernel-event-log.d.ts +26 -0
  15. package/dist/runtime/kernel-event-log.js +220 -0
  16. package/dist/runtime/kernel-primitives-dashboard.d.ts +44 -0
  17. package/dist/runtime/kernel-primitives-dashboard.js +135 -0
  18. package/dist/runtime/kernel-step.d.ts +25 -1
  19. package/dist/runtime/kernel-step.js +12 -3
  20. package/dist/runtime/large-result-spool.d.ts +84 -0
  21. package/dist/runtime/large-result-spool.js +167 -0
  22. package/dist/runtime/os-profile.d.ts +18 -0
  23. package/dist/runtime/os-profile.js +47 -0
  24. package/dist/runtime/os-snapshot.d.ts +35 -0
  25. package/dist/runtime/os-snapshot.js +128 -0
  26. package/dist/runtime/runner.d.ts +62 -9
  27. package/dist/runtime/runner.js +425 -135
  28. package/dist/runtime/session-log.d.ts +118 -4
  29. package/dist/runtime/session-log.js +15 -4
  30. package/dist/runtime/sub-agent-orchestrator.d.ts +2 -2
  31. package/dist/runtime/sub-agent-orchestrator.js +14 -23
  32. package/dist/types/agent.d.ts +12 -3
  33. package/dist/types/agent.js +18 -0
  34. package/dist/types.d.ts +22 -0
  35. package/package.json +2 -2
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Large result spool (Layer 1 of 5-layer compression pyramid).
3
+ *
4
+ * When a single tool result exceeds 50KB, write the full content to disk
5
+ * and keep only a 2KB preview in the message. Zero API overhead.
6
+ *
7
+ * Design principles:
8
+ * - Kernel defines policy (thresholds)
9
+ * - SDK performs I/O (disk write/read)
10
+ * - Model can retrieve full content via Read tool when needed
11
+ */
12
+ import * as crypto from 'crypto';
13
+ import * as fs from 'fs/promises';
14
+ import * as path from 'path';
15
+ export const DEFAULT_SPOOL_CONFIG = {
16
+ spoolThresholdBytes: 50 * 1024, // 50KB
17
+ previewTokens: 500, // ~2KB
18
+ totalMessageLimitBytes: 200 * 1024, // 200KB
19
+ };
20
+ /**
21
+ * Large result spool manager.
22
+ */
23
+ export class LargeResultSpool {
24
+ config;
25
+ spoolDir;
26
+ activeWrites = new Map();
27
+ constructor(config = {}) {
28
+ this.config = { ...DEFAULT_SPOOL_CONFIG, ...config };
29
+ this.spoolDir = config.spoolDir ?? '.spool';
30
+ }
31
+ /**
32
+ * Check if a tool result needs spooling.
33
+ */
34
+ needsSpool(result) {
35
+ return result.output.length > this.config.spoolThresholdBytes;
36
+ }
37
+ /**
38
+ * Hash content for spool reference.
39
+ */
40
+ hashContent(content) {
41
+ return crypto.createHash('sha256').update(content).digest('hex');
42
+ }
43
+ /**
44
+ * Get spool file path for a hash.
45
+ */
46
+ getSpoolPath(hash) {
47
+ return path.join(this.spoolDir, `${hash}.txt`);
48
+ }
49
+ /**
50
+ * Write large result to disk.
51
+ */
52
+ async writeToDisk(content, hash) {
53
+ const spoolPath = this.getSpoolPath(hash);
54
+ let promise = this.activeWrites.get(spoolPath);
55
+ if (!promise) {
56
+ promise = (async () => {
57
+ try {
58
+ await fs.mkdir(this.spoolDir, { recursive: true });
59
+ await fs.writeFile(spoolPath, content, 'utf-8');
60
+ return spoolPath;
61
+ }
62
+ finally {
63
+ this.activeWrites.delete(spoolPath);
64
+ }
65
+ })();
66
+ this.activeWrites.set(spoolPath, promise);
67
+ }
68
+ return promise;
69
+ }
70
+ /**
71
+ * Generate preview for a tool result.
72
+ */
73
+ generatePreview(content) {
74
+ const previewTokens = Math.min(this.config.previewTokens, content.length / 4);
75
+ const preview = content.substring(0, previewTokens);
76
+ const omitted = content.length - previewTokens;
77
+ return `[tool_result_spooled]
78
+ size: ${content.length} bytes
79
+ preview: first ${previewTokens} chars
80
+ omitted: ${omitted} chars
81
+ [full content available via Read tool]
82
+ `;
83
+ }
84
+ /**
85
+ * Process a tool result: spool if large, return spooled result.
86
+ */
87
+ async processToolResult(result) {
88
+ if (!this.needsSpool(result)) {
89
+ return {
90
+ originalOutput: result.output,
91
+ preview: result.output,
92
+ spoolRef: '',
93
+ wasSpooled: false
94
+ };
95
+ }
96
+ // Hash the content
97
+ const hash = this.hashContent(result.output);
98
+ // Write to disk
99
+ const spoolRef = await this.writeToDisk(result.output, hash);
100
+ // Generate preview
101
+ const preview = this.generatePreview(result.output);
102
+ return {
103
+ originalOutput: result.output,
104
+ preview,
105
+ spoolRef,
106
+ wasSpooled: true
107
+ };
108
+ }
109
+ /**
110
+ * Persist a kernel-spooled tool output to disk. Returns the on-disk path ref.
111
+ */
112
+ async persistOutput(callId, content) {
113
+ const hash = this.hashContent(content);
114
+ const spoolPath = this.getSpoolPath(`${callId}-${hash.slice(0, 16)}`);
115
+ let promise = this.activeWrites.get(spoolPath);
116
+ if (!promise) {
117
+ promise = (async () => {
118
+ try {
119
+ await fs.mkdir(this.spoolDir, { recursive: true });
120
+ await fs.writeFile(spoolPath, content, 'utf-8');
121
+ return spoolPath;
122
+ }
123
+ finally {
124
+ this.activeWrites.delete(spoolPath);
125
+ }
126
+ })();
127
+ this.activeWrites.set(spoolPath, promise);
128
+ }
129
+ return promise;
130
+ }
131
+ /**
132
+ * Read a spooled result back from disk.
133
+ */
134
+ async readSpooledResult(spoolRef) {
135
+ try {
136
+ const content = await fs.readFile(spoolRef, 'utf-8');
137
+ return content;
138
+ }
139
+ catch (error) {
140
+ throw new Error(`Failed to read spooled result: ${error}`);
141
+ }
142
+ }
143
+ /**
144
+ * Clean up old spool files (optional maintenance).
145
+ */
146
+ async cleanup(maxAgeMs) {
147
+ const limit = maxAgeMs ?? this.config.maxAgeMs ?? 7 * 24 * 60 * 60 * 1000;
148
+ try {
149
+ const files = await fs.readdir(this.spoolDir);
150
+ let count = 0;
151
+ const now = Date.now();
152
+ for (const file of files) {
153
+ const filePath = path.join(this.spoolDir, file);
154
+ const stats = await fs.stat(filePath);
155
+ if (now - stats.mtimeMs > limit) {
156
+ await fs.unlink(filePath);
157
+ count++;
158
+ }
159
+ }
160
+ return count;
161
+ }
162
+ catch (error) {
163
+ // Ignore if directory doesn't exist or other file error
164
+ return 0;
165
+ }
166
+ }
167
+ }
@@ -0,0 +1,18 @@
1
+ import type { GovernancePolicy } from "../governance.js";
2
+ /** Default attention policy for native profile smoke tests. */
3
+ export declare const DEFAULT_NATIVE_ATTENTION_POLICY: {
4
+ maxQueueSize: number;
5
+ };
6
+ /** Permissive governance policy for native runs that do not need AskUser. */
7
+ export declare const DEFAULT_NATIVE_GOVERNANCE_POLICY: GovernancePolicy;
8
+ /** Default restrictive sandbox policy template requiring confirmation for modification/execution. */
9
+ export declare const DEFAULT_SANDBOX_POLICY: GovernancePolicy;
10
+ /**
11
+ * Validates the declarative policies statically to prevent runtime crashes when loaded into the microkernel.
12
+ */
13
+ export declare function validateDeclarativePolicy(govPolicy?: GovernancePolicy, attentionPolicy?: {
14
+ maxQueueSize?: number;
15
+ }): {
16
+ valid: boolean;
17
+ errors: string[];
18
+ };
@@ -0,0 +1,47 @@
1
+ /** Default attention policy for native profile smoke tests. */
2
+ export const DEFAULT_NATIVE_ATTENTION_POLICY = { maxQueueSize: 64 };
3
+ /** Permissive governance policy for native runs that do not need AskUser. */
4
+ export const DEFAULT_NATIVE_GOVERNANCE_POLICY = {
5
+ rules: [{ pattern: "*", action: "allow" }],
6
+ };
7
+ /** Default restrictive sandbox policy template requiring confirmation for modification/execution. */
8
+ export const DEFAULT_SANDBOX_POLICY = {
9
+ rules: [
10
+ { pattern: "read_file", action: "allow" },
11
+ { pattern: "write_file", action: "ask_user" },
12
+ { pattern: "run_command", action: "ask_user" },
13
+ { pattern: "*", action: "deny" },
14
+ ],
15
+ };
16
+ /**
17
+ * Validates the declarative policies statically to prevent runtime crashes when loaded into the microkernel.
18
+ */
19
+ export function validateDeclarativePolicy(govPolicy, attentionPolicy) {
20
+ const errors = [];
21
+ if (govPolicy) {
22
+ if (!Array.isArray(govPolicy.rules)) {
23
+ errors.push("GovernancePolicy rules must be an array");
24
+ }
25
+ else {
26
+ govPolicy.rules.forEach((rule, idx) => {
27
+ if (!rule.pattern || typeof rule.pattern !== "string") {
28
+ errors.push(`Rule[${idx}] pattern is missing or not a string`);
29
+ }
30
+ if (!["allow", "deny", "ask_user"].includes(rule.action)) {
31
+ errors.push(`Rule[${idx}] action '${rule.action}' is invalid. Allowed: allow, deny, ask_user`);
32
+ }
33
+ });
34
+ }
35
+ }
36
+ if (attentionPolicy) {
37
+ if (attentionPolicy.maxQueueSize !== undefined) {
38
+ if (typeof attentionPolicy.maxQueueSize !== "number" || attentionPolicy.maxQueueSize <= 0) {
39
+ errors.push("AttentionPolicy maxQueueSize must be a positive integer");
40
+ }
41
+ }
42
+ }
43
+ return {
44
+ valid: errors.length === 0,
45
+ errors,
46
+ };
47
+ }
@@ -0,0 +1,35 @@
1
+ import type { SessionEvent } from "./session-log.js";
2
+ export interface OsSnapshot {
3
+ lastSuspend?: {
4
+ turn: number;
5
+ reason: string;
6
+ pending_calls: string[];
7
+ };
8
+ lastResumedTurn?: number;
9
+ processByAgent: Array<{
10
+ turn: number;
11
+ agent_id: string;
12
+ parent_session_id: string;
13
+ state: string;
14
+ }>;
15
+ budgetExceeded: Array<{
16
+ turn: number;
17
+ budget: string;
18
+ }>;
19
+ signals: Array<{
20
+ turn: number;
21
+ signal_id: string;
22
+ disposition: string;
23
+ queue_depth: number;
24
+ }>;
25
+ pageOutCount: number;
26
+ pageInCount: number;
27
+ spoolCount: number;
28
+ toolGatedCount: number;
29
+ memoryWrittenCount: number;
30
+ memoryQueriedCount: number;
31
+ memoryValidationFailedCount: number;
32
+ memoryRetrievalResultCount: number;
33
+ }
34
+ export declare function rebuildOsSnapshotFromSessionEvents(events: SessionEvent[]): OsSnapshot;
35
+ export declare function sessionLogHasRequiredCategories(events: SessionEvent[]): boolean;
@@ -0,0 +1,128 @@
1
+ import { categoryForKind, primitiveForKind } from "./kernel-event-log.js";
2
+ const KERNEL_KINDS = new Set([
3
+ "compressed",
4
+ "page_out",
5
+ "page_in",
6
+ "large_result_spooled",
7
+ "capability_changed",
8
+ "context_renewed",
9
+ "suspended",
10
+ "resumed",
11
+ "tool_gated",
12
+ "signal_disposed",
13
+ "budget_exceeded",
14
+ "checkpoint_taken",
15
+ "rollbacked",
16
+ "agent_process_changed",
17
+ "milestone_advanced",
18
+ "milestone_blocked",
19
+ "milestone_evidence",
20
+ "memory_written",
21
+ "memory_queried",
22
+ "memory_validation_failed",
23
+ ]);
24
+ export function rebuildOsSnapshotFromSessionEvents(events) {
25
+ const snap = {
26
+ processByAgent: [],
27
+ budgetExceeded: [],
28
+ signals: [],
29
+ pageOutCount: 0,
30
+ pageInCount: 0,
31
+ spoolCount: 0,
32
+ toolGatedCount: 0,
33
+ memoryWrittenCount: 0,
34
+ memoryQueriedCount: 0,
35
+ memoryValidationFailedCount: 0,
36
+ memoryRetrievalResultCount: 0,
37
+ };
38
+ const index = new Map();
39
+ for (const event of events) {
40
+ if (event.kind === "memory_retrieval_result") {
41
+ snap.memoryRetrievalResultCount += 1;
42
+ continue;
43
+ }
44
+ if (!KERNEL_KINDS.has(event.kind) && event.kind !== "suspended" && event.kind !== "resumed") {
45
+ continue;
46
+ }
47
+ switch (event.kind) {
48
+ case "suspended":
49
+ snap.lastSuspend = {
50
+ turn: event.turn,
51
+ reason: event.reason,
52
+ pending_calls: event.pending_calls ?? [],
53
+ };
54
+ break;
55
+ case "resumed":
56
+ snap.lastResumedTurn = event.turn;
57
+ break;
58
+ case "tool_gated":
59
+ snap.toolGatedCount += 1;
60
+ break;
61
+ case "agent_process_changed": {
62
+ const record = {
63
+ turn: event.turn,
64
+ agent_id: event.agent_id,
65
+ parent_session_id: event.parent_session_id,
66
+ state: event.state ?? "running",
67
+ };
68
+ const idx = index.get(event.agent_id);
69
+ if (idx !== undefined)
70
+ snap.processByAgent[idx] = record;
71
+ else {
72
+ index.set(event.agent_id, snap.processByAgent.length);
73
+ snap.processByAgent.push(record);
74
+ }
75
+ break;
76
+ }
77
+ case "budget_exceeded":
78
+ snap.budgetExceeded.push({ turn: event.turn, budget: event.budget });
79
+ break;
80
+ case "signal_disposed":
81
+ snap.signals.push({
82
+ turn: event.turn,
83
+ signal_id: event.signal_id,
84
+ disposition: event.disposition,
85
+ queue_depth: event.queue_depth,
86
+ });
87
+ break;
88
+ case "page_out":
89
+ snap.pageOutCount += 1;
90
+ break;
91
+ case "page_in":
92
+ snap.pageInCount += 1;
93
+ break;
94
+ case "large_result_spooled":
95
+ snap.spoolCount += 1;
96
+ break;
97
+ case "memory_written":
98
+ snap.memoryWrittenCount += 1;
99
+ break;
100
+ case "memory_queried":
101
+ snap.memoryQueriedCount += 1;
102
+ break;
103
+ case "memory_validation_failed":
104
+ snap.memoryValidationFailedCount += 1;
105
+ break;
106
+ default:
107
+ break;
108
+ }
109
+ }
110
+ return snap;
111
+ }
112
+ export function sessionLogHasRequiredCategories(events) {
113
+ for (const event of events) {
114
+ if (!KERNEL_KINDS.has(event.kind))
115
+ continue;
116
+ const cat = event.category;
117
+ if (!cat)
118
+ return false;
119
+ if (cat !== categoryForKind(event.kind))
120
+ return false;
121
+ const prim = event.primitive;
122
+ if (prim !== undefined) {
123
+ if (prim !== primitiveForKind(event.kind))
124
+ return false;
125
+ }
126
+ }
127
+ return true;
128
+ }
@@ -1,5 +1,5 @@
1
- import type { LLMProvider, Message, ToolSchema, StreamEvent, ToolSuspendEvent, AsyncSummarizer } from "../types.js";
2
- import type { DreamStore } from "../memory/protocols.js";
1
+ import type { LLMProvider, Message, ToolSchema, StreamEvent, ToolSuspendEvent, PermissionRequestEvent, PermissionResponse, AsyncSummarizer, DreamSummarizer } from "../types.js";
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 } from "../signals/types.js";
5
5
  import type { SessionLog, SessionEvent } from "./session-log.js";
@@ -7,6 +7,8 @@ import type { ArchiveStore } from "./archive.js";
7
7
  import type { ExecutionPlane } from "./execution-plane.js";
8
8
  import type { AgentRunSpec, MilestoneCheckResult, MilestoneContract, MilestonePolicy } from "../types/agent.js";
9
9
  import { type SubAgentOrchestrator } from "./sub-agent-orchestrator.js";
10
+ import { type GovernancePolicy } from "../governance.js";
11
+ import { LargeResultSpool } from "./large-result-spool.js";
10
12
  export interface RuntimeOptions {
11
13
  provider: LLMProvider;
12
14
  sessionLog: SessionLog;
@@ -22,18 +24,39 @@ export interface RuntimeOptions {
22
24
  knowledgeSource?: KnowledgeSource;
23
25
  signalSource?: SignalSource;
24
26
  extensions?: Record<string, unknown>;
25
- governance?: {
26
- setTime?(nowMs: bigint): void;
27
- evaluate(name: string, argsJson: string): {
28
- kind: string;
29
- reason?: string;
30
- retryAfterMs?: number;
31
- };
27
+ /**
28
+ * Declarative governance policy loaded into the kernel (`load_governance_policy`).
29
+ * The kernel enforces deny/veto/rate-limit/param-constraint before tools execute;
30
+ * AskUser calls surface as `tool_gated` and run through `onPermissionRequest`.
31
+ */
32
+ governancePolicy?: GovernancePolicy;
33
+ /**
34
+ * Enable in-kernel signal routing (`set_attention_policy`). When set, inbound
35
+ * signals are dispatched through the kernel attention policy (dedup + disposition
36
+ * + queue) and surface as `signal_disposed` observations, instead of the legacy
37
+ * SDK-side router. `maxQueueSize` defaults to 64.
38
+ */
39
+ attentionPolicy?: {
40
+ maxQueueSize?: number;
41
+ };
42
+ /**
43
+ * Optional scheduler budget overrides. `maxWallMs` is the wall-clock run budget
44
+ * in milliseconds; when set, the kernel terminates the run when exceeded.
45
+ * Other axes (maxTurns, maxTokens) are set via RuntimeOptions directly.
46
+ */
47
+ schedulerBudget?: {
48
+ maxWallMs?: number;
32
49
  };
33
50
  tokenizer?: string;
34
51
  enablePlanTool?: boolean;
52
+ /**
53
+ * Persist full tool outputs when the kernel emits `large_result_spooled`.
54
+ * Defaults to `.spool/` under the process cwd.
55
+ */
56
+ resultSpool?: LargeResultSpool;
35
57
  compressionStore?: ArchiveStore;
36
58
  onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
59
+ onPermissionRequest?: (event: PermissionRequestEvent) => Promise<PermissionResponse | boolean> | PermissionResponse | boolean;
37
60
  /** Default: terminate — stop with milestone_pending when a phase needs evaluation. */
38
61
  milestonePolicy?: MilestonePolicy;
39
62
  /** Optional external verifier when milestonePolicy is not auto_pass. */
@@ -59,6 +82,13 @@ export interface RuntimeOptions {
59
82
  };
60
83
  /** Optional system prompt injected into the dream synthesis call. */
61
84
  dreamSystemPrompt?: string;
85
+ /** Custom LLM provider used for background memory consolidation (dream loop). */
86
+ dreamProvider?: LLMProvider;
87
+ /**
88
+ * Optional LLM summarizer for semantic page_out events. When unset, `dreamProvider`
89
+ * (or the runtime provider) is used to produce long-term summaries for DreamStore.
90
+ */
91
+ dreamSummarizer?: DreamSummarizer;
62
92
  /**
63
93
  * Optional async LLM summarizer. When provided, a background call is fired
64
94
  * after each compression event to produce a richer semantic summary.
@@ -66,6 +96,8 @@ export interface RuntimeOptions {
66
96
  * on the next wake() in place of the rule-based summary.
67
97
  */
68
98
  asyncSummarizer?: AsyncSummarizer;
99
+ /** Enable real-time CLI diagnostics dashboard grouped by the three kernel primitives (Syscall, Sched, Mm) */
100
+ enableDiagnosticsDashboard?: boolean;
69
101
  }
70
102
  export declare class RuntimeRunner {
71
103
  private readonly opts;
@@ -74,9 +106,25 @@ export declare class RuntimeRunner {
74
106
  private pendingObservations;
75
107
  private currentSessionId;
76
108
  private nextArchiveStart;
109
+ /** Full tool outputs keyed by call_id until Layer-1 spool observations are logged. */
110
+ private pendingSpoolOutputs;
111
+ /** Local cache of paged-out/archived messages for priority memory retrieval. */
112
+ private localPageOutCache;
113
+ private dashboard;
77
114
  constructor(opts: RuntimeOptions);
78
115
  /** Host configuration (for coordinator / sub-agent spawn). */
79
116
  get hostOptions(): RuntimeOptions;
117
+ writeMemory(memory: MemoryWriteRequest, opts?: {
118
+ sessionId?: string;
119
+ agentId?: string;
120
+ }): Promise<void>;
121
+ queryMemory(query: MemoryQuery, opts?: {
122
+ sessionId?: string;
123
+ agentId?: string;
124
+ }): Promise<MemoryEntry[]>;
125
+ private logMemoryRetrievalResult;
126
+ private createSyscallRuntime;
127
+ private appendMemorySyscallObservations;
80
128
  /** Mount a tool capability on the currently-running kernel runtime. No-op if not running. */
81
129
  mountTool(schema: ToolSchema): void;
82
130
  /** Mount a skill capability on the currently-running kernel runtime. No-op if not running. */
@@ -85,6 +133,8 @@ export declare class RuntimeRunner {
85
133
  mountMarker(kind: string, id: string, description: string): void;
86
134
  /** Unmount a capability by kind + id from the active run. No-op if not running. */
87
135
  unmountCapability(kind: string, id: string): void;
136
+ /** Phase 4: satisfy kernel page-in requests before meta-tool execution. */
137
+ private applyKernelPageIn;
88
138
  /** Push content into the Knowledge slot (memory retrievals, skill definitions, artifacts). */
89
139
  pushKnowledge(message: Message, tokens?: number): void;
90
140
  /**
@@ -106,8 +156,11 @@ export declare class RuntimeRunner {
106
156
  }): AsyncIterable<StreamEvent>;
107
157
  wake(sessionId: string, extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
108
158
  dream(agentId: string, nowMs?: number): AsyncIterable<StreamEvent>;
159
+ /** Resolve in-kernel AskUser suspend; returns resume lists and stream events to yield. */
160
+ private resolveKernelSuspend;
109
161
  private execute;
110
162
  private appendObservations;
163
+ private archiveSemanticPageOut;
111
164
  private upgradeCompressedSummary;
112
165
  }
113
166
  export declare function replayMessages(events: Array<{