@deepstrike/sdk 0.1.13 → 0.1.15
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 +77 -51
- package/dist/collaboration/harness.js +6 -1
- package/dist/collaboration/modes/creator-verifier.d.ts +2 -2
- package/dist/collaboration/modes/creator-verifier.js +2 -2
- package/dist/collaboration/pool.d.ts +4 -35
- package/dist/collaboration/pool.js +18 -44
- package/dist/harness/harness.d.ts +9 -7
- package/dist/harness/harness.js +19 -22
- package/dist/index.d.ts +18 -6
- package/dist/index.js +14 -2
- package/dist/kernel.d.ts +1 -0
- package/dist/kernel.js +10 -1
- package/dist/memory/protocols.d.ts +0 -4
- package/dist/providers/anthropic.d.ts +4 -2
- package/dist/providers/anthropic.js +34 -10
- package/dist/providers/deepseek.d.ts +3 -2
- package/dist/providers/deepseek.js +9 -0
- package/dist/providers/gemini.d.ts +2 -1
- package/dist/providers/gemini.js +11 -0
- package/dist/providers/kimi.d.ts +3 -1
- package/dist/providers/kimi.js +10 -0
- package/dist/providers/minimax.d.ts +3 -1
- package/dist/providers/minimax.js +8 -0
- package/dist/providers/ollama.d.ts +2 -1
- package/dist/providers/ollama.js +22 -0
- package/dist/providers/openai-chat.d.ts +1 -1
- package/dist/providers/openai-chat.js +5 -7
- package/dist/providers/openai-responses.d.ts +1 -0
- package/dist/providers/openai-responses.js +13 -0
- package/dist/providers/openai.d.ts +4 -1
- package/dist/providers/openai.js +28 -0
- package/dist/providers/profiles.d.ts +502 -6
- package/dist/providers/profiles.js +225 -82
- package/dist/providers/qwen.d.ts +2 -1
- package/dist/providers/qwen.js +15 -0
- package/dist/runtime/credential-vault.d.ts +18 -0
- package/dist/runtime/credential-vault.js +33 -0
- package/dist/runtime/execution-plane.d.ts +38 -0
- package/dist/runtime/execution-plane.js +146 -0
- package/dist/runtime/mcp-proxy-plane.d.ts +51 -0
- package/dist/runtime/mcp-proxy-plane.js +204 -0
- package/dist/runtime/process-sandbox-plane.d.ts +32 -0
- package/dist/runtime/process-sandbox-plane.js +109 -0
- package/dist/runtime/provider-replay.d.ts +7 -0
- package/dist/runtime/provider-replay.js +18 -0
- package/dist/runtime/remote-vpc-plane.d.ts +48 -0
- package/dist/runtime/remote-vpc-plane.js +82 -0
- package/dist/runtime/runner.d.ts +49 -0
- package/dist/runtime/runner.js +368 -0
- package/dist/runtime/session-log.d.ts +68 -0
- package/dist/runtime/session-log.js +84 -0
- package/dist/types.d.ts +27 -0
- package/package.json +3 -2
- package/dist/agent.d.ts +0 -90
- package/dist/agent.js +0 -499
package/dist/agent.js
DELETED
|
@@ -1,499 +0,0 @@
|
|
|
1
|
-
import { isAsyncIterable, normalizeToolChunk, toolChunkText, validateToolArguments } 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 = [];
|
|
249
|
-
const active = regularCalls.map(call => {
|
|
250
|
-
const iterator = this.runRegularTool(call);
|
|
251
|
-
return { iterator, pending: iterator.next() };
|
|
252
|
-
});
|
|
253
|
-
while (active.length) {
|
|
254
|
-
const next = await Promise.race(active.map((task, index) => task.pending.then(result => ({ index, result }))));
|
|
255
|
-
const task = active[next.index];
|
|
256
|
-
if (next.result.done) {
|
|
257
|
-
results.push(next.result.value);
|
|
258
|
-
active.splice(next.index, 1);
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
yield next.result.value;
|
|
262
|
-
task.pending = task.iterator.next();
|
|
263
|
-
}
|
|
264
|
-
for (const r of results) {
|
|
265
|
-
const name = regularCalls.find((c) => c.id === r.callId)?.name ?? "";
|
|
266
|
-
yield { type: "tool_result", callId: r.callId, name, content: r.output, isError: r.isError };
|
|
267
|
-
}
|
|
268
|
-
action = sm.feedToolResults([
|
|
269
|
-
...deniedResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
|
|
270
|
-
...skillResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
|
|
271
|
-
...memoryResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
|
|
272
|
-
...knowledgeResults.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
|
|
273
|
-
...results.map(r => ({ callId: r.callId, output: r.output, isError: r.isError })),
|
|
274
|
-
]);
|
|
275
|
-
}
|
|
276
|
-
else if (action.kind === "done") {
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
const result = action.result;
|
|
281
|
-
this._turn = sm.turn;
|
|
282
|
-
this._pressure = sm.pressure();
|
|
283
|
-
const status = result?.termination ?? "error";
|
|
284
|
-
const iterations = result ? Math.max(1, result.turnsUsed) : 0;
|
|
285
|
-
const newMsgs = sm.drainNewMessages().map(m => this.kernelMsgToSessionMsg(m));
|
|
286
|
-
if (this.options.dreamStore && this.options.agentId && newMsgs.length > 0) {
|
|
287
|
-
try {
|
|
288
|
-
await this.options.dreamStore.saveSession({
|
|
289
|
-
sessionId: crypto.randomUUID(),
|
|
290
|
-
agentId: this.options.agentId,
|
|
291
|
-
messages: newMsgs,
|
|
292
|
-
metadata: null,
|
|
293
|
-
createdAtMs: sessionStart,
|
|
294
|
-
updatedAtMs: Date.now(),
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
catch { /* session save failure must not surface to caller */ }
|
|
298
|
-
}
|
|
299
|
-
if (sessionId) {
|
|
300
|
-
const now = Date.now();
|
|
301
|
-
await this.saveSession({
|
|
302
|
-
sessionId,
|
|
303
|
-
agentId: this.options.agentId ?? "default",
|
|
304
|
-
messages: [...previousMsgs, ...newMsgs],
|
|
305
|
-
metadata: previousSession?.metadata ?? null,
|
|
306
|
-
createdAtMs: previousSession?.createdAtMs ?? sessionStart,
|
|
307
|
-
updatedAtMs: now,
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
yield {
|
|
311
|
-
type: "done",
|
|
312
|
-
iterations,
|
|
313
|
-
totalTokens: result?.totalTokensUsed ? Number(result.totalTokensUsed) : 0,
|
|
314
|
-
status,
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
async *runRegularTool(call) {
|
|
318
|
-
const registeredTool = this.tools.get(call.name);
|
|
319
|
-
if (!registeredTool)
|
|
320
|
-
return { callId: call.id, output: `unknown tool: ${call.name}`, isError: true };
|
|
321
|
-
try {
|
|
322
|
-
const args = JSON.parse(call.arguments || "{}");
|
|
323
|
-
const validationError = validateToolArguments(registeredTool.schema.parameters, args);
|
|
324
|
-
if (validationError)
|
|
325
|
-
return { callId: call.id, output: `invalid arguments: ${validationError}`, isError: true };
|
|
326
|
-
const output = await registeredTool.execute(args);
|
|
327
|
-
if (isAsyncIterable(output)) {
|
|
328
|
-
let combined = "";
|
|
329
|
-
const iterator = output[Symbol.asyncIterator]();
|
|
330
|
-
let resumeValue;
|
|
331
|
-
while (true) {
|
|
332
|
-
const next = await iterator.next(resumeValue);
|
|
333
|
-
resumeValue = undefined;
|
|
334
|
-
if (next.done)
|
|
335
|
-
break;
|
|
336
|
-
const rawChunk = next.value;
|
|
337
|
-
const chunk = normalizeToolChunk(rawChunk);
|
|
338
|
-
if (chunk.type === "suspend") {
|
|
339
|
-
const event = {
|
|
340
|
-
type: "tool_suspend",
|
|
341
|
-
callId: call.id,
|
|
342
|
-
name: call.name,
|
|
343
|
-
suspensionId: chunk.suspensionId,
|
|
344
|
-
...(chunk.payload ? { payload: chunk.payload } : {}),
|
|
345
|
-
};
|
|
346
|
-
yield event;
|
|
347
|
-
if (!this.options.onToolSuspend) {
|
|
348
|
-
return { callId: call.id, output: `tool suspended without resume handler: ${chunk.suspensionId}`, isError: true };
|
|
349
|
-
}
|
|
350
|
-
resumeValue = await this.options.onToolSuspend(event);
|
|
351
|
-
continue;
|
|
352
|
-
}
|
|
353
|
-
const delta = toolChunkText(rawChunk);
|
|
354
|
-
combined += delta;
|
|
355
|
-
yield {
|
|
356
|
-
type: "tool_delta",
|
|
357
|
-
callId: call.id,
|
|
358
|
-
name: call.name,
|
|
359
|
-
...(delta ? { delta } : {}),
|
|
360
|
-
...(typeof rawChunk === "string" ? {} : { chunk }),
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
return { callId: call.id, output: combined, isError: false };
|
|
364
|
-
}
|
|
365
|
-
return { callId: call.id, output, isError: false };
|
|
366
|
-
}
|
|
367
|
-
catch (err) {
|
|
368
|
-
return { callId: call.id, output: String(err), isError: true };
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
async loadSession(sessionId) {
|
|
372
|
-
return this.options.sessionStore
|
|
373
|
-
? this.options.sessionStore.loadSession(sessionId)
|
|
374
|
-
: this.inMemorySessions.get(sessionId);
|
|
375
|
-
}
|
|
376
|
-
async saveSession(data) {
|
|
377
|
-
if (this.options.sessionStore) {
|
|
378
|
-
await this.options.sessionStore.saveSession(data);
|
|
379
|
-
return;
|
|
380
|
-
}
|
|
381
|
-
this.inMemorySessions.set(data.sessionId, data);
|
|
382
|
-
}
|
|
383
|
-
toMessage(message) {
|
|
384
|
-
return {
|
|
385
|
-
role: message.role,
|
|
386
|
-
content: message.content,
|
|
387
|
-
contentParts: message.contentParts,
|
|
388
|
-
tokenCount: message.tokenCount,
|
|
389
|
-
toolCalls: message.toolCalls ?? [],
|
|
390
|
-
};
|
|
391
|
-
}
|
|
392
|
-
kernelMsgToSessionMsg(msg) {
|
|
393
|
-
return {
|
|
394
|
-
role: msg.role,
|
|
395
|
-
content: msg.content,
|
|
396
|
-
contentParts: msg.contentParts,
|
|
397
|
-
tokenCount: msg.tokenCount,
|
|
398
|
-
toolCalls: msg.toolCalls?.length ? msg.toolCalls : undefined,
|
|
399
|
-
};
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* Trigger the idle dreaming cycle for this agent.
|
|
403
|
-
* Requires `dreamStore` and `agentId` to be configured.
|
|
404
|
-
*
|
|
405
|
-
* Phase 1 — kernel rule-based analysis + LLM prompt assembly
|
|
406
|
-
* Phase 2 — LLM synthesis call (I/O)
|
|
407
|
-
* Phase 3 — kernel parses + curates results
|
|
408
|
-
* Phase 4 — commit delta to DreamStore (I/O)
|
|
409
|
-
*/
|
|
410
|
-
async dream(agentId, nowMs = Date.now()) {
|
|
411
|
-
if (!this.dreamStore)
|
|
412
|
-
throw new Error("dreamStore not configured on AgentOptions");
|
|
413
|
-
const kernel = getKernel();
|
|
414
|
-
const sessions = await this.dreamStore.loadSessions(agentId);
|
|
415
|
-
const existingMemories = await this.dreamStore.loadMemories(agentId);
|
|
416
|
-
if (!sessions.length) {
|
|
417
|
-
return { sessionsProcessed: 0, insightsExtracted: 0, entriesAdded: 0, entriesRemoved: 0 };
|
|
418
|
-
}
|
|
419
|
-
const kernelSessions = sessions.map(s => ({
|
|
420
|
-
sessionId: s.sessionId,
|
|
421
|
-
agentId: s.agentId,
|
|
422
|
-
messages: s.messages.map(m => ({
|
|
423
|
-
role: m.role,
|
|
424
|
-
content: m.content,
|
|
425
|
-
tokenCount: m.tokenCount,
|
|
426
|
-
toolCalls: (m.toolCalls ?? []).map(tc => ({ id: tc.id, name: tc.name, arguments: tc.arguments })),
|
|
427
|
-
})),
|
|
428
|
-
metadata: JSON.stringify(s.metadata ?? null),
|
|
429
|
-
createdAtMs: s.createdAtMs,
|
|
430
|
-
updatedAtMs: s.updatedAtMs,
|
|
431
|
-
}));
|
|
432
|
-
const kernelMemories = existingMemories.map(e => ({
|
|
433
|
-
text: e.text,
|
|
434
|
-
score: e.score,
|
|
435
|
-
metadata: JSON.stringify(e.metadata ?? null),
|
|
436
|
-
}));
|
|
437
|
-
const pipeline = new kernel.IdlePipeline(agentId);
|
|
438
|
-
const action1 = pipeline.feedTrigger(kernelSessions, kernelMemories, nowMs);
|
|
439
|
-
if (action1.kind === "noop" || action1.kind === "aborted") {
|
|
440
|
-
return { sessionsProcessed: 0, insightsExtracted: 0, entriesAdded: 0, entriesRemoved: 0 };
|
|
441
|
-
}
|
|
442
|
-
if (action1.kind !== "synthesize_insights") {
|
|
443
|
-
throw new Error(`unexpected action after feedTrigger: ${action1.kind}`);
|
|
444
|
-
}
|
|
445
|
-
let synthesisText = "";
|
|
446
|
-
const providerState = this.provider.createRunState?.();
|
|
447
|
-
// IdlePipeline produces raw messages for synthesis; wrap them in a RenderedContext.
|
|
448
|
-
// The first system message (if any) becomes systemText; the rest are turns.
|
|
449
|
-
const synthMsgs = (action1.messages ?? []);
|
|
450
|
-
const synthSystemMsgs = synthMsgs.filter(m => m.role === "system");
|
|
451
|
-
const synthTurns = synthMsgs.filter(m => m.role !== "system");
|
|
452
|
-
const synthContext = {
|
|
453
|
-
systemText: synthSystemMsgs.map(m => m.content).join("\n\n"),
|
|
454
|
-
turns: synthTurns,
|
|
455
|
-
};
|
|
456
|
-
for await (const evt of this.provider.stream(synthContext, [], undefined, providerState)) {
|
|
457
|
-
if (evt.type === "text_delta")
|
|
458
|
-
synthesisText += evt.delta;
|
|
459
|
-
}
|
|
460
|
-
const action2 = pipeline.feedSynthesisResult(synthesisText);
|
|
461
|
-
if (action2.kind !== "commit_memories") {
|
|
462
|
-
throw new Error(`unexpected action after feedSynthesisResult: ${action2.kind}`);
|
|
463
|
-
}
|
|
464
|
-
const cr = action2.curationResult;
|
|
465
|
-
const rr = action2.runResult;
|
|
466
|
-
const dsResult = {
|
|
467
|
-
toAdd: (cr.toAdd ?? []).map((e) => ({
|
|
468
|
-
text: e.text,
|
|
469
|
-
score: e.score,
|
|
470
|
-
metadata: tryParseJson(e.metadata),
|
|
471
|
-
})),
|
|
472
|
-
toRemoveIndices: (cr.toRemoveIndices ?? []).map(Number),
|
|
473
|
-
stats: {
|
|
474
|
-
insightsProcessed: cr.stats?.insightsProcessed ?? 0,
|
|
475
|
-
duplicatesRemoved: cr.stats?.duplicatesRemoved ?? 0,
|
|
476
|
-
conflictsResolved: cr.stats?.conflictsResolved ?? 0,
|
|
477
|
-
entriesAdded: cr.stats?.entriesAdded ?? 0,
|
|
478
|
-
},
|
|
479
|
-
};
|
|
480
|
-
await this.dreamStore.commit(agentId, dsResult, existingMemories);
|
|
481
|
-
return {
|
|
482
|
-
sessionsProcessed: rr.sessionsProcessed,
|
|
483
|
-
insightsExtracted: rr.insightsExtracted,
|
|
484
|
-
entriesAdded: cr.stats?.entriesAdded ?? 0,
|
|
485
|
-
entriesRemoved: (cr.toRemoveIndices ?? []).length,
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
function tryParseJson(s) {
|
|
490
|
-
try {
|
|
491
|
-
return JSON.parse(s);
|
|
492
|
-
}
|
|
493
|
-
catch {
|
|
494
|
-
return null;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
function normalizeSignalUrgency(sig) {
|
|
498
|
-
return sig.urgency;
|
|
499
|
-
}
|