@deepstrike/sdk 0.1.12 → 0.1.14

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 (55) hide show
  1. package/README.md +82 -52
  2. package/dist/collaboration/harness.js +6 -1
  3. package/dist/collaboration/modes/creator-verifier.d.ts +2 -2
  4. package/dist/collaboration/modes/creator-verifier.js +2 -2
  5. package/dist/collaboration/pool.d.ts +4 -35
  6. package/dist/collaboration/pool.js +18 -44
  7. package/dist/harness/harness.d.ts +19 -7
  8. package/dist/harness/harness.js +27 -22
  9. package/dist/index.d.ts +19 -7
  10. package/dist/index.js +15 -3
  11. package/dist/kernel.d.ts +1 -0
  12. package/dist/kernel.js +10 -1
  13. package/dist/memory/protocols.d.ts +0 -4
  14. package/dist/providers/anthropic.d.ts +7 -2
  15. package/dist/providers/anthropic.js +48 -9
  16. package/dist/providers/base.d.ts +1 -0
  17. package/dist/providers/base.js +6 -0
  18. package/dist/providers/deepseek.d.ts +4 -2
  19. package/dist/providers/deepseek.js +49 -1
  20. package/dist/providers/gemini.d.ts +4 -2
  21. package/dist/providers/gemini.js +24 -5
  22. package/dist/providers/kimi.d.ts +3 -1
  23. package/dist/providers/kimi.js +10 -0
  24. package/dist/providers/minimax.d.ts +3 -1
  25. package/dist/providers/minimax.js +8 -0
  26. package/dist/providers/ollama.d.ts +5 -2
  27. package/dist/providers/ollama.js +63 -7
  28. package/dist/providers/openai-responses.d.ts +4 -2
  29. package/dist/providers/openai-responses.js +23 -3
  30. package/dist/providers/openai.d.ts +4 -2
  31. package/dist/providers/openai.js +44 -3
  32. package/dist/providers/profiles.d.ts +502 -6
  33. package/dist/providers/profiles.js +225 -82
  34. package/dist/providers/qwen.d.ts +5 -2
  35. package/dist/providers/qwen.js +59 -11
  36. package/dist/runtime/credential-vault.d.ts +18 -0
  37. package/dist/runtime/credential-vault.js +33 -0
  38. package/dist/runtime/execution-plane.d.ts +38 -0
  39. package/dist/runtime/execution-plane.js +146 -0
  40. package/dist/runtime/mcp-proxy-plane.d.ts +51 -0
  41. package/dist/runtime/mcp-proxy-plane.js +204 -0
  42. package/dist/runtime/process-sandbox-plane.d.ts +32 -0
  43. package/dist/runtime/process-sandbox-plane.js +109 -0
  44. package/dist/runtime/remote-vpc-plane.d.ts +48 -0
  45. package/dist/runtime/remote-vpc-plane.js +82 -0
  46. package/dist/runtime/runner.d.ts +49 -0
  47. package/dist/runtime/runner.js +364 -0
  48. package/dist/runtime/session-log.d.ts +67 -0
  49. package/dist/runtime/session-log.js +84 -0
  50. package/dist/tools/index.d.ts +7 -2
  51. package/dist/tools/index.js +83 -0
  52. package/dist/types.d.ts +52 -1
  53. package/package.json +3 -2
  54. package/dist/agent.d.ts +0 -88
  55. package/dist/agent.js +0 -430
package/dist/types.d.ts CHANGED
@@ -69,6 +69,41 @@ export interface ToolCallEvent extends StreamEvent {
69
69
  name: string;
70
70
  arguments: Record<string, unknown>;
71
71
  }
72
+ export type ToolChunk = string | {
73
+ type: "text";
74
+ text: string;
75
+ } | {
76
+ type: "progress";
77
+ progress: number;
78
+ message?: string;
79
+ } | {
80
+ type: "artifact";
81
+ artifactId: string;
82
+ mimeType?: string;
83
+ label?: string;
84
+ } | {
85
+ type: "json_patch";
86
+ patch: Record<string, unknown>;
87
+ } | {
88
+ type: "suspend";
89
+ suspensionId: string;
90
+ payload?: Record<string, unknown>;
91
+ };
92
+ export interface ToolDeltaEvent extends StreamEvent {
93
+ type: "tool_delta";
94
+ callId: string;
95
+ name: string;
96
+ /** Backward-compatible text projection when the chunk carries text. */
97
+ delta?: string;
98
+ chunk: Exclude<ToolChunk, string>;
99
+ }
100
+ export interface ToolSuspendEvent extends StreamEvent {
101
+ type: "tool_suspend";
102
+ callId: string;
103
+ name: string;
104
+ suspensionId: string;
105
+ payload?: Record<string, unknown>;
106
+ }
72
107
  export interface ToolResultEvent extends StreamEvent {
73
108
  type: "tool_result";
74
109
  callId: string;
@@ -127,8 +162,24 @@ export interface RenderedContext {
127
162
  * Working-partition signals are already folded into the first user turn. */
128
163
  turns: Message[];
129
164
  }
165
+ /**
166
+ * Runtime execution policy advertised by a provider.
167
+ * RuntimeRunner merges these with RuntimeOptions — explicit options always win.
168
+ */
169
+ export interface RuntimePolicy {
170
+ /** Maximum agent turns before termination. */
171
+ maxTurns?: number;
172
+ /** Per-run wall-clock timeout in ms. */
173
+ timeoutMs?: number;
174
+ }
130
175
  export interface LLMProvider {
131
176
  createRunState?(): ProviderRunState;
132
- complete(context: RenderedContext, tools: ToolSchema[]): Promise<Message>;
177
+ /**
178
+ * Optional: return the recommended runtime policy for this provider's model.
179
+ * RuntimeRunner uses this as a fallback when the caller has not specified
180
+ * maxTurns / timeoutMs in RuntimeOptions.
181
+ */
182
+ runtimePolicy?(): RuntimePolicy;
183
+ complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
133
184
  stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState): AsyncIterable<StreamEvent>;
134
185
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/sdk",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "DeepStrike Node.js SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,11 +12,12 @@
12
12
  "scripts": {
13
13
  "build": "tsc",
14
14
  "test": "node --experimental-vm-modules node_modules/.bin/jest",
15
+ "test:local-core": "cd ../crates/deepstrike-node && napi build --platform && cd ../../node && npm test",
15
16
  "smoke:providers": "node ../scripts/smoke-node-provider-loops.mjs"
16
17
  },
17
18
  "dependencies": {
18
19
  "@anthropic-ai/sdk": "^0.39.0",
19
- "@deepstrike/core": "0.1.12",
20
+ "@deepstrike/core": "0.1.14",
20
21
  "@google/generative-ai": "^0.24.1",
21
22
  "openai": "^4.77.0"
22
23
  },
package/dist/agent.d.ts DELETED
@@ -1,88 +0,0 @@
1
- import type { LLMProvider, StreamEvent } from "./types.js";
2
- import type { RegisteredTool } from "./tools/index.js";
3
- import type { DreamStore, DreamResult, SessionStore } from "./memory/protocols.js";
4
- import type { KnowledgeSource } from "./knowledge/source.js";
5
- import type { SignalSource } from "./signals/types.js";
6
- export interface AgentOptions {
7
- maxTokens: number;
8
- maxTurns?: number;
9
- timeoutMs?: number;
10
- extensions?: Record<string, unknown>;
11
- /**
12
- * System-level instructions prepended to every context render.
13
- * Passed to the kernel's `system` partition before the first LLM call.
14
- */
15
- systemPrompt?: string;
16
- /**
17
- * Directory containing skill `.md` files. The kernel auto-injects a `skill`
18
- * meta-tool so the model can load any skill by name on demand.
19
- */
20
- skillDir?: string;
21
- knowledgeSource?: KnowledgeSource;
22
- signalSource?: SignalSource;
23
- /** Backing store for the idle dreaming pipeline. Required to call `Agent.dream()`. */
24
- dreamStore?: DreamStore;
25
- /** Optional durable transcript store for same-session conversational continuity. */
26
- sessionStore?: SessionStore;
27
- /**
28
- * Stable identifier for this agent. Required to enable in-session memory retrieval
29
- * when `dreamStore` is configured.
30
- */
31
- agentId?: string;
32
- /**
33
- * SDK Governance instance or any object implementing
34
- * `evaluate(toolName: string, argsJson: string): { kind: string; reason?: string; retryAfterMs?: number }`.
35
- * When provided, every tool call is evaluated through the full pipeline.
36
- */
37
- governance?: {
38
- setTime?(nowMs: bigint): void;
39
- evaluate(toolName: string, argsJson: string): {
40
- kind: string;
41
- reason?: string;
42
- retryAfterMs?: number;
43
- };
44
- };
45
- }
46
- export declare class Agent {
47
- private readonly provider;
48
- private readonly options;
49
- private tools;
50
- private extensions;
51
- private skillDir?;
52
- private knowledgeSource?;
53
- private signalSource?;
54
- private dreamStore?;
55
- private readonly inMemorySessions;
56
- private interrupted;
57
- private pendingInterrupt;
58
- private _turn;
59
- private _pressure;
60
- constructor(provider: LLMProvider, options: AgentOptions);
61
- /** Current turn index within the active run (0 before a run starts). */
62
- get turn(): number;
63
- /** Context pressure ratio [0–1] from the kernel. Values > 0.8 trigger compression. */
64
- get pressure(): number;
65
- interrupt(): void;
66
- register(...tools: RegisteredTool[]): this;
67
- unregister(name: string): this;
68
- /**
69
- * Collect the full text response and return it.
70
- * For richer control (streaming, tool events, token counts) use `runStreaming`.
71
- */
72
- run(goal: string, criteria?: string[], extensions?: Record<string, unknown>, sessionId?: string): Promise<string>;
73
- runStreaming(goal: string, criteria?: string[], extensions?: Record<string, unknown>, sessionId?: string): AsyncIterable<StreamEvent>;
74
- private loadSession;
75
- private saveSession;
76
- private toMessage;
77
- private kernelMsgToSessionMsg;
78
- /**
79
- * Trigger the idle dreaming cycle for this agent.
80
- * Requires `dreamStore` and `agentId` to be configured.
81
- *
82
- * Phase 1 — kernel rule-based analysis + LLM prompt assembly
83
- * Phase 2 — LLM synthesis call (I/O)
84
- * Phase 3 — kernel parses + curates results
85
- * Phase 4 — commit delta to DreamStore (I/O)
86
- */
87
- dream(agentId: string, nowMs?: number): Promise<DreamResult>;
88
- }
package/dist/agent.js DELETED
@@ -1,430 +0,0 @@
1
- import { executeTools } from "./tools/index.js";
2
- import { readSkillFile, scanSkillDir } from "./skills/loader.js";
3
- import { getKernel } from "./kernel.js";
4
- export class Agent {
5
- provider;
6
- options;
7
- tools = new Map();
8
- extensions;
9
- skillDir;
10
- knowledgeSource;
11
- signalSource;
12
- dreamStore;
13
- inMemorySessions = new Map();
14
- interrupted = false;
15
- pendingInterrupt = false;
16
- // Live telemetry — updated each runStreaming call
17
- _turn = 0;
18
- _pressure = 0;
19
- constructor(provider, options) {
20
- this.provider = provider;
21
- this.options = options;
22
- this.extensions = options.extensions ?? {};
23
- this.skillDir = options.skillDir;
24
- this.knowledgeSource = options.knowledgeSource;
25
- this.signalSource = options.signalSource;
26
- this.dreamStore = options.dreamStore;
27
- }
28
- /** Current turn index within the active run (0 before a run starts). */
29
- get turn() { return this._turn; }
30
- /** Context pressure ratio [0–1] from the kernel. Values > 0.8 trigger compression. */
31
- get pressure() { return this._pressure; }
32
- interrupt() {
33
- this.interrupted = true;
34
- }
35
- register(...tools) {
36
- for (const t of tools)
37
- this.tools.set(t.schema.name, t);
38
- return this;
39
- }
40
- unregister(name) {
41
- this.tools.delete(name);
42
- return this;
43
- }
44
- /**
45
- * Collect the full text response and return it.
46
- * For richer control (streaming, tool events, token counts) use `runStreaming`.
47
- */
48
- async run(goal, criteria, extensions, sessionId) {
49
- let content = "";
50
- for await (const evt of this.runStreaming(goal, criteria, extensions, sessionId)) {
51
- if (evt.type === "text_delta")
52
- content += evt.delta;
53
- }
54
- return content;
55
- }
56
- async *runStreaming(goal, criteria, extensions, sessionId) {
57
- this.interrupted = false;
58
- this.pendingInterrupt = false;
59
- this._turn = 0;
60
- this._pressure = 0;
61
- if (this.knowledgeSource) {
62
- await this.knowledgeSource.init();
63
- }
64
- const kernel = getKernel();
65
- const ext = { ...this.extensions, ...(extensions ?? {}) };
66
- const providerState = this.provider.createRunState?.();
67
- const sm = new kernel.LoopStateMachine({
68
- maxTokens: this.options.maxTokens,
69
- maxTurns: this.options.maxTurns ?? 25,
70
- timeoutMs: this.options.timeoutMs === undefined ? undefined : BigInt(this.options.timeoutMs),
71
- });
72
- // Per-run SignalRouter — dedup state never leaks between runs.
73
- const router = new kernel.SignalRouter(256);
74
- const toolSchemas = Array.from(this.tools.values()).map(t => t.schema);
75
- sm.setTools(toolSchemas);
76
- if (this.options.systemPrompt) {
77
- const tokens = Math.max(1, Math.ceil(this.options.systemPrompt.length / 4));
78
- sm.addSystemMessage(this.options.systemPrompt, tokens);
79
- }
80
- const previousSession = sessionId ? await this.loadSession(sessionId) : undefined;
81
- const previousMsgs = previousSession?.messages ?? [];
82
- if (previousMsgs.length > 0) {
83
- sm.preloadHistory(previousMsgs.map(m => this.toMessage(m)));
84
- }
85
- if (this.skillDir) {
86
- const skillMetas = await scanSkillDir(this.skillDir);
87
- sm.setAvailableSkills(skillMetas.map((m) => ({
88
- name: m.name,
89
- description: m.description,
90
- whenToUse: m.whenToUse,
91
- effort: m.effort,
92
- estimatedTokens: m.estimatedTokens ?? 0,
93
- })));
94
- }
95
- if (this.dreamStore && this.options.agentId) {
96
- sm.setMemoryEnabled(true);
97
- }
98
- if (this.knowledgeSource) {
99
- sm.setKnowledgeEnabled(true);
100
- }
101
- let action = sm.start({ goal, criteria: criteria ?? [] });
102
- const sessionStart = Date.now();
103
- while (!sm.isTerminal()) {
104
- // Update telemetry
105
- this._turn = sm.turn;
106
- this._pressure = sm.pressure();
107
- // Hard interrupt
108
- if (this.interrupted) {
109
- action = sm.feedTimeout();
110
- break;
111
- }
112
- if (this.pendingInterrupt) {
113
- this.pendingInterrupt = false;
114
- action = sm.feedTimeout();
115
- break;
116
- }
117
- // Drain context-compression observations
118
- sm.takeObservations();
119
- // Poll signal source and route through kernel SignalRouter
120
- if (this.signalSource) {
121
- const sig = await this.signalSource.nextSignal();
122
- if (sig) {
123
- const kernelSig = {
124
- id: crypto.randomUUID(),
125
- source: sig.source ?? "custom",
126
- signalType: sig.signalType ?? "event",
127
- urgency: normalizeSignalUrgency(sig),
128
- summary: String(sig.payload?.goal ?? sig.kind ?? "signal"),
129
- payload: JSON.stringify(sig.payload ?? {}),
130
- dedupeKey: sig.dedupeKey,
131
- timestampMs: Date.now(),
132
- };
133
- const disposition = router.ingest(kernelSig, action.kind === "execute_tools");
134
- if (disposition === "interrupt_now") {
135
- action = sm.feedTimeout();
136
- break;
137
- }
138
- if (disposition === "interrupt")
139
- this.pendingInterrupt = true;
140
- }
141
- }
142
- // Drain previously queued signals — apply any high-urgency ones
143
- let queued = router.next();
144
- while (queued) {
145
- if (queued.urgency === "critical") {
146
- action = sm.feedTimeout();
147
- break;
148
- }
149
- if (queued.urgency === "high")
150
- this.pendingInterrupt = true;
151
- queued = router.next();
152
- }
153
- if (this.interrupted || (sm.isTerminal()))
154
- break;
155
- if (action.kind === "call_llm") {
156
- const finalToolCalls = [];
157
- let finalText = "";
158
- const context = action.context;
159
- const tools = (action.tools ?? []);
160
- let turnTokens = 0;
161
- try {
162
- for await (const evt of this.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState)) {
163
- if (evt.type === "usage") {
164
- turnTokens = evt.totalTokens;
165
- continue;
166
- }
167
- yield evt;
168
- if (evt.type === "text_delta")
169
- finalText += evt.delta;
170
- else if (evt.type === "tool_call") {
171
- const tc = evt;
172
- finalToolCalls.push({ id: tc.id, name: tc.name, arguments: JSON.stringify(tc.arguments) });
173
- }
174
- }
175
- }
176
- catch (err) {
177
- yield { type: "error", message: String(err) };
178
- action = sm.feedTimeout();
179
- break;
180
- }
181
- action = sm.feedLlmResponse({ role: "assistant", content: finalText, toolCalls: finalToolCalls, tokenCount: turnTokens || undefined });
182
- }
183
- else if (action.kind === "execute_tools") {
184
- const allCalls = action.calls ?? [];
185
- // Governance evaluation
186
- const permittedCalls = [];
187
- const deniedResults = [];
188
- for (const c of allCalls) {
189
- if (this.options.governance) {
190
- this.options.governance.setTime?.(BigInt(Date.now()));
191
- const verdict = this.options.governance.evaluate(c.name, c.arguments);
192
- if (verdict.kind === "deny") {
193
- const msg = `permission denied: ${c.name} — ${verdict.reason ?? ""}`;
194
- yield { type: "error", message: msg };
195
- deniedResults.push({ callId: c.id, name: c.name, output: msg, isError: true });
196
- continue;
197
- }
198
- if (verdict.kind === "rate_limited") {
199
- const msg = `rate limited: ${c.name} — retry after ${verdict.retryAfterMs ?? 0}ms`;
200
- yield { type: "error", message: msg };
201
- deniedResults.push({ callId: c.id, name: c.name, output: msg, isError: true });
202
- continue;
203
- }
204
- if (verdict.kind === "ask_user") {
205
- yield { type: "permission_request", callId: c.id, toolName: c.name, arguments: c.arguments, reason: verdict.reason ?? "" };
206
- deniedResults.push({ callId: c.id, name: c.name, output: `awaiting user approval: ${c.name}`, isError: true });
207
- continue;
208
- }
209
- }
210
- permittedCalls.push(c);
211
- }
212
- const skillCalls = permittedCalls.filter((c) => c.name === "skill");
213
- const memoryCalls = permittedCalls.filter((c) => c.name === "memory");
214
- const knowledgeCalls = permittedCalls.filter((c) => c.name === "knowledge");
215
- const regularCalls = permittedCalls.filter((c) => c.name !== "skill" && c.name !== "memory" && c.name !== "knowledge");
216
- const skillResults = this.skillDir
217
- ? await Promise.all(skillCalls.map(async (c) => {
218
- const args = tryParseJson(c.arguments);
219
- const name = String(args?.name ?? "");
220
- const content = await readSkillFile(this.skillDir, name);
221
- return { callId: c.id, name: c.name, output: content ?? `Skill "${name}" not found.`, isError: !content };
222
- }))
223
- : skillCalls.map((c) => ({ callId: c.id, name: c.name, output: "No skill directory configured.", isError: true }));
224
- const memoryResults = (this.dreamStore && this.options.agentId)
225
- ? await Promise.all(memoryCalls.map(async (c) => {
226
- const args = tryParseJson(c.arguments);
227
- const query = String(args?.query ?? "");
228
- const topK = typeof args?.top_k === "number" ? args.top_k : 5;
229
- const entries = await this.dreamStore.search(this.options.agentId, query, topK);
230
- const output = entries.length
231
- ? entries.map((e) => `[score=${e.score.toFixed(3)}] ${e.text}`).join("\n---\n")
232
- : "No relevant memories found.";
233
- return { callId: c.id, name: c.name, output, isError: false };
234
- }))
235
- : memoryCalls.map((c) => ({ callId: c.id, name: c.name, output: "Memory retrieval not configured.", isError: true }));
236
- const knowledgeResults = this.knowledgeSource
237
- ? await Promise.all(knowledgeCalls.map(async (c) => {
238
- const args = tryParseJson(c.arguments);
239
- const query = String(args?.query ?? "");
240
- const topK = typeof args?.top_k === "number" ? args.top_k : 5;
241
- const snippets = await this.knowledgeSource.retrieve(query, topK);
242
- const output = snippets.length ? snippets.join("\n---\n") : "No relevant knowledge found.";
243
- return { callId: c.id, name: c.name, output, isError: false };
244
- }))
245
- : knowledgeCalls.map((c) => ({ callId: c.id, name: c.name, output: "Knowledge source not configured.", isError: true }));
246
- for (const r of [...skillResults, ...memoryResults, ...knowledgeResults])
247
- yield { type: "tool_result", callId: r.callId, name: r.name, content: r.output, isError: r.isError };
248
- const results = await executeTools(regularCalls, this.tools);
249
- for (const r of results) {
250
- const name = regularCalls.find((c) => c.id === r.callId)?.name ?? "";
251
- yield { type: "tool_result", callId: r.callId, name, content: r.output, isError: r.isError };
252
- }
253
- action = sm.feedToolResults([
254
- ...deniedResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
255
- ...skillResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
256
- ...memoryResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
257
- ...knowledgeResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
258
- ...results.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
259
- ]);
260
- }
261
- else if (action.kind === "done") {
262
- break;
263
- }
264
- }
265
- const result = action.result;
266
- this._turn = sm.turn;
267
- this._pressure = sm.pressure();
268
- const status = result?.termination ?? "error";
269
- const iterations = result ? Math.max(1, result.turnsUsed) : 0;
270
- const newMsgs = sm.drainNewMessages().map(m => this.kernelMsgToSessionMsg(m));
271
- if (this.options.dreamStore && this.options.agentId && newMsgs.length > 0) {
272
- try {
273
- await this.options.dreamStore.saveSession({
274
- sessionId: crypto.randomUUID(),
275
- agentId: this.options.agentId,
276
- messages: newMsgs,
277
- metadata: null,
278
- createdAtMs: sessionStart,
279
- updatedAtMs: Date.now(),
280
- });
281
- }
282
- catch { /* session save failure must not surface to caller */ }
283
- }
284
- if (sessionId) {
285
- const now = Date.now();
286
- await this.saveSession({
287
- sessionId,
288
- agentId: this.options.agentId ?? "default",
289
- messages: [...previousMsgs, ...newMsgs],
290
- metadata: previousSession?.metadata ?? null,
291
- createdAtMs: previousSession?.createdAtMs ?? sessionStart,
292
- updatedAtMs: now,
293
- });
294
- }
295
- yield {
296
- type: "done",
297
- iterations,
298
- totalTokens: result?.totalTokensUsed ? Number(result.totalTokensUsed) : 0,
299
- status,
300
- };
301
- }
302
- async loadSession(sessionId) {
303
- return this.options.sessionStore
304
- ? this.options.sessionStore.loadSession(sessionId)
305
- : this.inMemorySessions.get(sessionId);
306
- }
307
- async saveSession(data) {
308
- if (this.options.sessionStore) {
309
- await this.options.sessionStore.saveSession(data);
310
- return;
311
- }
312
- this.inMemorySessions.set(data.sessionId, data);
313
- }
314
- toMessage(message) {
315
- return {
316
- role: message.role,
317
- content: message.content,
318
- contentParts: message.contentParts,
319
- tokenCount: message.tokenCount,
320
- toolCalls: message.toolCalls ?? [],
321
- };
322
- }
323
- kernelMsgToSessionMsg(msg) {
324
- return {
325
- role: msg.role,
326
- content: msg.content,
327
- contentParts: msg.contentParts,
328
- tokenCount: msg.tokenCount,
329
- toolCalls: msg.toolCalls?.length ? msg.toolCalls : undefined,
330
- };
331
- }
332
- /**
333
- * Trigger the idle dreaming cycle for this agent.
334
- * Requires `dreamStore` and `agentId` to be configured.
335
- *
336
- * Phase 1 — kernel rule-based analysis + LLM prompt assembly
337
- * Phase 2 — LLM synthesis call (I/O)
338
- * Phase 3 — kernel parses + curates results
339
- * Phase 4 — commit delta to DreamStore (I/O)
340
- */
341
- async dream(agentId, nowMs = Date.now()) {
342
- if (!this.dreamStore)
343
- throw new Error("dreamStore not configured on AgentOptions");
344
- const kernel = getKernel();
345
- const sessions = await this.dreamStore.loadSessions(agentId);
346
- const existingMemories = await this.dreamStore.loadMemories(agentId);
347
- if (!sessions.length) {
348
- return { sessionsProcessed: 0, insightsExtracted: 0, entriesAdded: 0, entriesRemoved: 0 };
349
- }
350
- const kernelSessions = sessions.map(s => ({
351
- sessionId: s.sessionId,
352
- agentId: s.agentId,
353
- messages: s.messages.map(m => ({
354
- role: m.role,
355
- content: m.content,
356
- tokenCount: m.tokenCount,
357
- toolCalls: (m.toolCalls ?? []).map(tc => ({ id: tc.id, name: tc.name, arguments: tc.arguments })),
358
- })),
359
- metadata: JSON.stringify(s.metadata ?? null),
360
- createdAtMs: s.createdAtMs,
361
- updatedAtMs: s.updatedAtMs,
362
- }));
363
- const kernelMemories = existingMemories.map(e => ({
364
- text: e.text,
365
- score: e.score,
366
- metadata: JSON.stringify(e.metadata ?? null),
367
- }));
368
- const pipeline = new kernel.IdlePipeline(agentId);
369
- const action1 = pipeline.feedTrigger(kernelSessions, kernelMemories, nowMs);
370
- if (action1.kind === "noop" || action1.kind === "aborted") {
371
- return { sessionsProcessed: 0, insightsExtracted: 0, entriesAdded: 0, entriesRemoved: 0 };
372
- }
373
- if (action1.kind !== "synthesize_insights") {
374
- throw new Error(`unexpected action after feedTrigger: ${action1.kind}`);
375
- }
376
- let synthesisText = "";
377
- const providerState = this.provider.createRunState?.();
378
- // IdlePipeline produces raw messages for synthesis; wrap them in a RenderedContext.
379
- // The first system message (if any) becomes systemText; the rest are turns.
380
- const synthMsgs = (action1.messages ?? []);
381
- const synthSystemMsgs = synthMsgs.filter(m => m.role === "system");
382
- const synthTurns = synthMsgs.filter(m => m.role !== "system");
383
- const synthContext = {
384
- systemText: synthSystemMsgs.map(m => m.content).join("\n\n"),
385
- turns: synthTurns,
386
- };
387
- for await (const evt of this.provider.stream(synthContext, [], undefined, providerState)) {
388
- if (evt.type === "text_delta")
389
- synthesisText += evt.delta;
390
- }
391
- const action2 = pipeline.feedSynthesisResult(synthesisText);
392
- if (action2.kind !== "commit_memories") {
393
- throw new Error(`unexpected action after feedSynthesisResult: ${action2.kind}`);
394
- }
395
- const cr = action2.curationResult;
396
- const rr = action2.runResult;
397
- const dsResult = {
398
- toAdd: (cr.toAdd ?? []).map((e) => ({
399
- text: e.text,
400
- score: e.score,
401
- metadata: tryParseJson(e.metadata),
402
- })),
403
- toRemoveIndices: (cr.toRemoveIndices ?? []).map(Number),
404
- stats: {
405
- insightsProcessed: cr.stats?.insightsProcessed ?? 0,
406
- duplicatesRemoved: cr.stats?.duplicatesRemoved ?? 0,
407
- conflictsResolved: cr.stats?.conflictsResolved ?? 0,
408
- entriesAdded: cr.stats?.entriesAdded ?? 0,
409
- },
410
- };
411
- await this.dreamStore.commit(agentId, dsResult, existingMemories);
412
- return {
413
- sessionsProcessed: rr.sessionsProcessed,
414
- insightsExtracted: rr.insightsExtracted,
415
- entriesAdded: cr.stats?.entriesAdded ?? 0,
416
- entriesRemoved: (cr.toRemoveIndices ?? []).length,
417
- };
418
- }
419
- }
420
- function tryParseJson(s) {
421
- try {
422
- return JSON.parse(s);
423
- }
424
- catch {
425
- return null;
426
- }
427
- }
428
- function normalizeSignalUrgency(sig) {
429
- return sig.urgency;
430
- }