@deepstrike/sdk 0.1.11 → 0.1.13
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 +30 -1
- package/dist/agent.d.ts +13 -10
- package/dist/agent.js +135 -14
- package/dist/harness/harness.d.ts +10 -0
- package/dist/harness/harness.js +15 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/kernel.d.ts +5 -2
- package/dist/memory/protocols.d.ts +8 -1
- package/dist/providers/anthropic.d.ts +7 -3
- package/dist/providers/anthropic.js +36 -15
- package/dist/providers/base.d.ts +8 -4
- package/dist/providers/base.js +47 -38
- package/dist/providers/deepseek.d.ts +3 -2
- package/dist/providers/deepseek.js +42 -3
- package/dist/providers/gemini.d.ts +4 -3
- package/dist/providers/gemini.js +20 -17
- package/dist/providers/ollama.d.ts +5 -3
- package/dist/providers/ollama.js +50 -12
- package/dist/providers/openai-chat.d.ts +2 -2
- package/dist/providers/openai-chat.js +6 -4
- package/dist/providers/openai-responses.d.ts +6 -5
- package/dist/providers/openai-responses.js +21 -20
- package/dist/providers/openai.d.ts +4 -3
- package/dist/providers/openai.js +30 -6
- package/dist/providers/qwen.d.ts +5 -3
- package/dist/providers/qwen.js +47 -14
- package/dist/tools/index.d.ts +7 -2
- package/dist/tools/index.js +83 -0
- package/dist/types.d.ts +47 -2
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -50,6 +50,15 @@ const result = await agent.run("What is 17 + 28?")
|
|
|
50
50
|
console.log(result)
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
+
Same-session conversation continuity is explicit via `sessionId`:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
await agent.run("My name is Ada.", undefined, undefined, "chat-1")
|
|
57
|
+
const reply = await agent.run("What is my name?", undefined, undefined, "chat-1")
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
By default, the agent keeps session transcripts in memory for the lifetime of that `Agent` instance. Provide a `sessionStore` when the transcript must survive process restarts or be shared across workers.
|
|
61
|
+
|
|
53
62
|
Streaming:
|
|
54
63
|
|
|
55
64
|
```typescript
|
|
@@ -79,6 +88,8 @@ for await (const event of agent.runStreaming("Summarize README.md")) {
|
|
|
79
88
|
|
|
80
89
|
All providers accept `RetryConfig` for exponential backoff and share a `CircuitBreaker`.
|
|
81
90
|
|
|
91
|
+
`extensions` are forwarded by every provider in both `complete()` and `stream()` while SDK-owned structural fields such as `model`, `messages`, `tools`, and streaming flags remain protected. Provider-specific controls still keep their native spellings: for example Anthropic `thinking` / `betas`, OpenAI Responses `reasoning`, Gemini `generationConfig`, Ollama `think` / `options`, DeepSeek `thinking` + `reasoningEffort`, and Qwen `enableThinking` + `thinkingBudget`.
|
|
92
|
+
|
|
82
93
|
OpenAI can also be selected through the provider catalog:
|
|
83
94
|
|
|
84
95
|
```typescript
|
|
@@ -99,7 +110,7 @@ const agent = new Agent(provider, {
|
|
|
99
110
|
maxTokens: 4096, // context window size
|
|
100
111
|
maxTurns: 25, // max turns (default 25)
|
|
101
112
|
timeoutMs: 60_000, // timeout in ms
|
|
102
|
-
extensions: { temperature: 0.1 }, //
|
|
113
|
+
extensions: { temperature: 0.1 }, // provider-native controls, passed through to the LLM
|
|
103
114
|
skillDir: "./skills", // skill .md files directory
|
|
104
115
|
knowledgeSource: myKS, // KnowledgeSource implementation
|
|
105
116
|
signalSource: rx, // SignalSource for external signals
|
|
@@ -196,6 +207,22 @@ const agent = new Agent(provider, {
|
|
|
196
207
|
const result = await agent.dream("my-agent", Date.now())
|
|
197
208
|
```
|
|
198
209
|
|
|
210
|
+
### SessionStore (same-session transcript continuity)
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
import type { SessionStore } from "@deepstrike/sdk"
|
|
214
|
+
|
|
215
|
+
class MySessionStore implements SessionStore {
|
|
216
|
+
async loadSession(sessionId) { return db.sessions.get(sessionId) }
|
|
217
|
+
async saveSession(session) { await db.sessions.put(session.sessionId, session) }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const agent = new Agent(provider, {
|
|
221
|
+
maxTokens: 4096,
|
|
222
|
+
sessionStore: new MySessionStore(),
|
|
223
|
+
})
|
|
224
|
+
```
|
|
225
|
+
|
|
199
226
|
---
|
|
200
227
|
|
|
201
228
|
## Governance
|
|
@@ -282,6 +309,8 @@ console.log(out.passed, out.feedback)
|
|
|
282
309
|
| `text_delta` | `delta` |
|
|
283
310
|
| `thinking_delta` | `delta` |
|
|
284
311
|
| `tool_call` | `id`, `name`, `arguments` |
|
|
312
|
+
| `tool_delta` | `callId`, `delta?`, `chunk?` |
|
|
313
|
+
| `tool_suspend` | `callId`, `suspensionId`, `payload?` |
|
|
285
314
|
| `tool_result` | `callId`, `content`, `isError` |
|
|
286
315
|
| `permission_request` | `toolName`, `reason` |
|
|
287
316
|
| `done` | `iterations`, `totalTokens`, `status` |
|
package/dist/agent.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { LLMProvider, StreamEvent } from "./types.js";
|
|
1
|
+
import type { LLMProvider, StreamEvent, ToolSuspendEvent } from "./types.js";
|
|
2
2
|
import type { RegisteredTool } from "./tools/index.js";
|
|
3
|
-
import type { DreamStore, DreamResult } from "./memory/protocols.js";
|
|
3
|
+
import type { DreamStore, DreamResult, SessionStore } from "./memory/protocols.js";
|
|
4
4
|
import type { KnowledgeSource } from "./knowledge/source.js";
|
|
5
5
|
import type { SignalSource } from "./signals/types.js";
|
|
6
6
|
export interface AgentOptions {
|
|
@@ -13,12 +13,6 @@ export interface AgentOptions {
|
|
|
13
13
|
* Passed to the kernel's `system` partition before the first LLM call.
|
|
14
14
|
*/
|
|
15
15
|
systemPrompt?: string;
|
|
16
|
-
/**
|
|
17
|
-
* Long-term memory snippets pre-seeded into the context before the first LLM call.
|
|
18
|
-
* Each string is pushed to the kernel's `memory` partition (highest-priority context
|
|
19
|
-
* after system). Use to inject memories retrieved from a DreamStore before a run.
|
|
20
|
-
*/
|
|
21
|
-
initialMemory?: string[];
|
|
22
16
|
/**
|
|
23
17
|
* Directory containing skill `.md` files. The kernel auto-injects a `skill`
|
|
24
18
|
* meta-tool so the model can load any skill by name on demand.
|
|
@@ -28,6 +22,8 @@ export interface AgentOptions {
|
|
|
28
22
|
signalSource?: SignalSource;
|
|
29
23
|
/** Backing store for the idle dreaming pipeline. Required to call `Agent.dream()`. */
|
|
30
24
|
dreamStore?: DreamStore;
|
|
25
|
+
/** Optional durable transcript store for same-session conversational continuity. */
|
|
26
|
+
sessionStore?: SessionStore;
|
|
31
27
|
/**
|
|
32
28
|
* Stable identifier for this agent. Required to enable in-session memory retrieval
|
|
33
29
|
* when `dreamStore` is configured.
|
|
@@ -38,6 +34,7 @@ export interface AgentOptions {
|
|
|
38
34
|
* `evaluate(toolName: string, argsJson: string): { kind: string; reason?: string; retryAfterMs?: number }`.
|
|
39
35
|
* When provided, every tool call is evaluated through the full pipeline.
|
|
40
36
|
*/
|
|
37
|
+
onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
|
|
41
38
|
governance?: {
|
|
42
39
|
setTime?(nowMs: bigint): void;
|
|
43
40
|
evaluate(toolName: string, argsJson: string): {
|
|
@@ -56,6 +53,7 @@ export declare class Agent {
|
|
|
56
53
|
private knowledgeSource?;
|
|
57
54
|
private signalSource?;
|
|
58
55
|
private dreamStore?;
|
|
56
|
+
private readonly inMemorySessions;
|
|
59
57
|
private interrupted;
|
|
60
58
|
private pendingInterrupt;
|
|
61
59
|
private _turn;
|
|
@@ -72,8 +70,13 @@ export declare class Agent {
|
|
|
72
70
|
* Collect the full text response and return it.
|
|
73
71
|
* For richer control (streaming, tool events, token counts) use `runStreaming`.
|
|
74
72
|
*/
|
|
75
|
-
run(goal: string, criteria?: string[], extensions?: Record<string, unknown
|
|
76
|
-
runStreaming(goal: string, criteria?: string[], extensions?: Record<string, unknown
|
|
73
|
+
run(goal: string, criteria?: string[], extensions?: Record<string, unknown>, sessionId?: string): Promise<string>;
|
|
74
|
+
runStreaming(goal: string, criteria?: string[], extensions?: Record<string, unknown>, sessionId?: string): AsyncIterable<StreamEvent>;
|
|
75
|
+
private runRegularTool;
|
|
76
|
+
private loadSession;
|
|
77
|
+
private saveSession;
|
|
78
|
+
private toMessage;
|
|
79
|
+
private kernelMsgToSessionMsg;
|
|
77
80
|
/**
|
|
78
81
|
* Trigger the idle dreaming cycle for this agent.
|
|
79
82
|
* Requires `dreamStore` and `agentId` to be configured.
|
package/dist/agent.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isAsyncIterable, normalizeToolChunk, toolChunkText, validateToolArguments } from "./tools/index.js";
|
|
2
2
|
import { readSkillFile, scanSkillDir } from "./skills/loader.js";
|
|
3
3
|
import { getKernel } from "./kernel.js";
|
|
4
4
|
export class Agent {
|
|
@@ -10,6 +10,7 @@ export class Agent {
|
|
|
10
10
|
knowledgeSource;
|
|
11
11
|
signalSource;
|
|
12
12
|
dreamStore;
|
|
13
|
+
inMemorySessions = new Map();
|
|
13
14
|
interrupted = false;
|
|
14
15
|
pendingInterrupt = false;
|
|
15
16
|
// Live telemetry — updated each runStreaming call
|
|
@@ -44,15 +45,15 @@ export class Agent {
|
|
|
44
45
|
* Collect the full text response and return it.
|
|
45
46
|
* For richer control (streaming, tool events, token counts) use `runStreaming`.
|
|
46
47
|
*/
|
|
47
|
-
async run(goal, criteria, extensions) {
|
|
48
|
+
async run(goal, criteria, extensions, sessionId) {
|
|
48
49
|
let content = "";
|
|
49
|
-
for await (const evt of this.runStreaming(goal, criteria, extensions)) {
|
|
50
|
+
for await (const evt of this.runStreaming(goal, criteria, extensions, sessionId)) {
|
|
50
51
|
if (evt.type === "text_delta")
|
|
51
52
|
content += evt.delta;
|
|
52
53
|
}
|
|
53
54
|
return content;
|
|
54
55
|
}
|
|
55
|
-
async *runStreaming(goal, criteria, extensions) {
|
|
56
|
+
async *runStreaming(goal, criteria, extensions, sessionId) {
|
|
56
57
|
this.interrupted = false;
|
|
57
58
|
this.pendingInterrupt = false;
|
|
58
59
|
this._turn = 0;
|
|
@@ -76,8 +77,10 @@ export class Agent {
|
|
|
76
77
|
const tokens = Math.max(1, Math.ceil(this.options.systemPrompt.length / 4));
|
|
77
78
|
sm.addSystemMessage(this.options.systemPrompt, tokens);
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
-
|
|
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)));
|
|
81
84
|
}
|
|
82
85
|
if (this.skillDir) {
|
|
83
86
|
const skillMetas = await scanSkillDir(this.skillDir);
|
|
@@ -97,7 +100,6 @@ export class Agent {
|
|
|
97
100
|
}
|
|
98
101
|
let action = sm.start({ goal, criteria: criteria ?? [] });
|
|
99
102
|
const sessionStart = Date.now();
|
|
100
|
-
const sessionMsgs = [{ role: "user", content: goal }];
|
|
101
103
|
while (!sm.isTerminal()) {
|
|
102
104
|
// Update telemetry
|
|
103
105
|
this._turn = sm.turn;
|
|
@@ -153,11 +155,11 @@ export class Agent {
|
|
|
153
155
|
if (action.kind === "call_llm") {
|
|
154
156
|
const finalToolCalls = [];
|
|
155
157
|
let finalText = "";
|
|
156
|
-
const
|
|
158
|
+
const context = action.context;
|
|
157
159
|
const tools = (action.tools ?? []);
|
|
158
160
|
let turnTokens = 0;
|
|
159
161
|
try {
|
|
160
|
-
for await (const evt of this.provider.stream(
|
|
162
|
+
for await (const evt of this.provider.stream(context, tools, Object.keys(ext).length ? ext : undefined, providerState)) {
|
|
161
163
|
if (evt.type === "usage") {
|
|
162
164
|
turnTokens = evt.totalTokens;
|
|
163
165
|
continue;
|
|
@@ -177,7 +179,6 @@ export class Agent {
|
|
|
177
179
|
break;
|
|
178
180
|
}
|
|
179
181
|
action = sm.feedLlmResponse({ role: "assistant", content: finalText, toolCalls: finalToolCalls, tokenCount: turnTokens || undefined });
|
|
180
|
-
sessionMsgs.push({ role: "assistant", content: finalText, toolCalls: finalToolCalls });
|
|
181
182
|
}
|
|
182
183
|
else if (action.kind === "execute_tools") {
|
|
183
184
|
const allCalls = action.calls ?? [];
|
|
@@ -244,7 +245,22 @@ export class Agent {
|
|
|
244
245
|
: knowledgeCalls.map((c) => ({ callId: c.id, name: c.name, output: "Knowledge source not configured.", isError: true }));
|
|
245
246
|
for (const r of [...skillResults, ...memoryResults, ...knowledgeResults])
|
|
246
247
|
yield { type: "tool_result", callId: r.callId, name: r.name, content: r.output, isError: r.isError };
|
|
247
|
-
const results =
|
|
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
|
+
}
|
|
248
264
|
for (const r of results) {
|
|
249
265
|
const name = regularCalls.find((c) => c.id === r.callId)?.name ?? "";
|
|
250
266
|
yield { type: "tool_result", callId: r.callId, name, content: r.output, isError: r.isError };
|
|
@@ -266,12 +282,13 @@ export class Agent {
|
|
|
266
282
|
this._pressure = sm.pressure();
|
|
267
283
|
const status = result?.termination ?? "error";
|
|
268
284
|
const iterations = result ? Math.max(1, result.turnsUsed) : 0;
|
|
269
|
-
|
|
285
|
+
const newMsgs = sm.drainNewMessages().map(m => this.kernelMsgToSessionMsg(m));
|
|
286
|
+
if (this.options.dreamStore && this.options.agentId && newMsgs.length > 0) {
|
|
270
287
|
try {
|
|
271
288
|
await this.options.dreamStore.saveSession({
|
|
272
289
|
sessionId: crypto.randomUUID(),
|
|
273
290
|
agentId: this.options.agentId,
|
|
274
|
-
messages:
|
|
291
|
+
messages: newMsgs,
|
|
275
292
|
metadata: null,
|
|
276
293
|
createdAtMs: sessionStart,
|
|
277
294
|
updatedAtMs: Date.now(),
|
|
@@ -279,6 +296,17 @@ export class Agent {
|
|
|
279
296
|
}
|
|
280
297
|
catch { /* session save failure must not surface to caller */ }
|
|
281
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
|
+
}
|
|
282
310
|
yield {
|
|
283
311
|
type: "done",
|
|
284
312
|
iterations,
|
|
@@ -286,6 +314,90 @@ export class Agent {
|
|
|
286
314
|
status,
|
|
287
315
|
};
|
|
288
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
|
+
}
|
|
289
401
|
/**
|
|
290
402
|
* Trigger the idle dreaming cycle for this agent.
|
|
291
403
|
* Requires `dreamStore` and `agentId` to be configured.
|
|
@@ -332,7 +444,16 @@ export class Agent {
|
|
|
332
444
|
}
|
|
333
445
|
let synthesisText = "";
|
|
334
446
|
const providerState = this.provider.createRunState?.();
|
|
335
|
-
|
|
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)) {
|
|
336
457
|
if (evt.type === "text_delta")
|
|
337
458
|
synthesisText += evt.delta;
|
|
338
459
|
}
|
|
@@ -38,6 +38,16 @@ export type HarnessEvent = {
|
|
|
38
38
|
type: "tool_call";
|
|
39
39
|
id: string;
|
|
40
40
|
name: string;
|
|
41
|
+
} | {
|
|
42
|
+
type: "tool_delta";
|
|
43
|
+
callId: string;
|
|
44
|
+
delta?: string;
|
|
45
|
+
chunk?: Record<string, unknown>;
|
|
46
|
+
} | {
|
|
47
|
+
type: "tool_suspend";
|
|
48
|
+
callId: string;
|
|
49
|
+
suspensionId: string;
|
|
50
|
+
payload?: Record<string, unknown>;
|
|
41
51
|
} | {
|
|
42
52
|
type: "tool_result";
|
|
43
53
|
callId: string;
|
package/dist/harness/harness.js
CHANGED
|
@@ -74,6 +74,14 @@ export class HarnessLoop {
|
|
|
74
74
|
const tc = evt;
|
|
75
75
|
yield { type: "tool_call", id: tc.id, name: tc.name };
|
|
76
76
|
}
|
|
77
|
+
else if (evt.type === "tool_delta") {
|
|
78
|
+
const td = evt;
|
|
79
|
+
yield { type: "tool_delta", callId: td.callId, ...(td.delta ? { delta: td.delta } : {}), ...(td.chunk ? { chunk: td.chunk } : {}) };
|
|
80
|
+
}
|
|
81
|
+
else if (evt.type === "tool_suspend") {
|
|
82
|
+
const ts = evt;
|
|
83
|
+
yield { type: "tool_suspend", callId: ts.callId, suspensionId: ts.suspensionId, ...(ts.payload ? { payload: ts.payload } : {}) };
|
|
84
|
+
}
|
|
77
85
|
else if (evt.type === "tool_result") {
|
|
78
86
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
79
87
|
const tr = evt;
|
|
@@ -92,7 +100,13 @@ export class HarnessLoop {
|
|
|
92
100
|
if (evalAction.kind !== "evaluate")
|
|
93
101
|
break;
|
|
94
102
|
let evalText = "";
|
|
95
|
-
|
|
103
|
+
// Wrap harness eval messages in a RenderedContext (system messages → systemText, rest → turns).
|
|
104
|
+
const evalMsgs = evalAction.messages ?? [];
|
|
105
|
+
const evalContext = {
|
|
106
|
+
systemText: evalMsgs.filter((m) => m.role === "system").map((m) => m.content).join("\n\n"),
|
|
107
|
+
turns: evalMsgs.filter((m) => m.role !== "system"),
|
|
108
|
+
};
|
|
109
|
+
for await (const evt of this.evalProvider.stream(evalContext, [], undefined)) {
|
|
96
110
|
if (evt.type === "text_delta")
|
|
97
111
|
evalText += evt.delta;
|
|
98
112
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,12 +15,12 @@ export type { OpenAIResponsesRunState } from "./providers/openai-responses.js";
|
|
|
15
15
|
export { endpointProfiles, modelProfiles, getModelProfile } from "./providers/profiles.js";
|
|
16
16
|
export { createProvider } from "./providers/catalog.js";
|
|
17
17
|
export type { CreateProviderOptions, EndpointProfileId } from "./providers/catalog.js";
|
|
18
|
-
export { tool, executeTools, readFile } from "./tools/index.js";
|
|
18
|
+
export { tool, streamingTool, executeTools, readFile, validateToolArguments } from "./tools/index.js";
|
|
19
19
|
export type { RegisteredTool } from "./tools/index.js";
|
|
20
20
|
export { scanSkillDir, readSkillFile } from "./skills/loader.js";
|
|
21
21
|
export type { SkillMetadata } from "./skills/loader.js";
|
|
22
22
|
export { WorkingMemory } from "./memory/working.js";
|
|
23
|
-
export type { DreamStore, DreamResult, SessionData, SessionMessage, MemoryEntry, CurationResult, CurationStats, } from "./memory/protocols.js";
|
|
23
|
+
export type { DreamStore, DreamResult, SessionStore, SessionData, SessionMessage, MemoryEntry, CurationResult, CurationStats, } from "./memory/protocols.js";
|
|
24
24
|
export type { KnowledgeSource } from "./knowledge/source.js";
|
|
25
25
|
export { SinglePassHarness, EvalLoopHarness, HarnessLoop } from "./harness/harness.js";
|
|
26
26
|
export type { HarnessRequest, HarnessOutcome, HarnessLoopOptions, QualityGate } from "./harness/harness.js";
|
|
@@ -31,7 +31,7 @@ export { PermissionManager, PermissionMode } from "./safety/permissions.js";
|
|
|
31
31
|
export type { PermissionDecision, Permission } from "./safety/permissions.js";
|
|
32
32
|
export { Governance } from "./governance.js";
|
|
33
33
|
export type { GovernanceVerdict } from "./governance.js";
|
|
34
|
-
export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, LLMProvider, RetryConfig, TokenUsage, ProviderToolSpec, ProviderRunState, } from "./types.js";
|
|
34
|
+
export type { Message, ToolCall, ToolResult, ToolSchema, ContentPart, TextPart, ImagePart, AudioPart, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolChunk, ToolDeltaEvent, ToolSuspendEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, LLMProvider, RetryConfig, TokenUsage, ProviderToolSpec, ProviderRunState, RenderedContext, } from "./types.js";
|
|
35
35
|
export type { AcceptanceCriterion, VerificationContract, ContractCheckResult, } from "./collaboration/contract.js";
|
|
36
36
|
export { ContractBuilder, formatContractForSystemPrompt, contractToCriteriaStrings, } from "./collaboration/contract.js";
|
|
37
37
|
export { AgentPool } from "./collaboration/pool.js";
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ export { OpenAIChatAdapter } from "./providers/openai-chat.js";
|
|
|
12
12
|
export { OpenAIResponsesAdapter, OpenAIResponsesProvider } from "./providers/openai-responses.js";
|
|
13
13
|
export { endpointProfiles, modelProfiles, getModelProfile } from "./providers/profiles.js";
|
|
14
14
|
export { createProvider } from "./providers/catalog.js";
|
|
15
|
-
export { tool, executeTools, readFile } from "./tools/index.js";
|
|
15
|
+
export { tool, streamingTool, executeTools, readFile, validateToolArguments } from "./tools/index.js";
|
|
16
16
|
export { scanSkillDir, readSkillFile } from "./skills/loader.js";
|
|
17
17
|
export { WorkingMemory } from "./memory/working.js";
|
|
18
18
|
export { SinglePassHarness, EvalLoopHarness, HarnessLoop } from "./harness/harness.js";
|
package/dist/kernel.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Message, ToolCall, ToolResult, ToolSchema } from "./types.js";
|
|
1
|
+
import type { Message, RenderedContext, ToolCall, ToolResult, ToolSchema } from "./types.js";
|
|
2
2
|
import type { SkillMetadata } from "./skills/loader.js";
|
|
3
3
|
export interface GovernanceVerdict {
|
|
4
4
|
kind: "allow" | "deny" | "rate_limited" | "ask_user";
|
|
@@ -28,7 +28,7 @@ export interface RuntimeSignal {
|
|
|
28
28
|
}
|
|
29
29
|
export interface LoopAction {
|
|
30
30
|
kind: "call_llm" | "execute_tools" | "done";
|
|
31
|
-
|
|
31
|
+
context?: RenderedContext;
|
|
32
32
|
tools?: ToolSchema[];
|
|
33
33
|
calls?: ToolCall[];
|
|
34
34
|
result?: {
|
|
@@ -48,6 +48,7 @@ interface LoopStateMachineInstance {
|
|
|
48
48
|
setKnowledgeEnabled(enabled: boolean): void;
|
|
49
49
|
addSystemMessage(content: string, tokens: number): void;
|
|
50
50
|
addMemoryMessage(content: string, tokens: number): void;
|
|
51
|
+
addHistoryMessage(message: Message, tokens: number): void;
|
|
51
52
|
setTools(tools: ToolSchema[]): void;
|
|
52
53
|
start(task: {
|
|
53
54
|
goal: string;
|
|
@@ -57,6 +58,8 @@ interface LoopStateMachineInstance {
|
|
|
57
58
|
feedToolResults(results: ToolResult[]): LoopAction;
|
|
58
59
|
feedTimeout(): LoopAction;
|
|
59
60
|
isTerminal(): boolean;
|
|
61
|
+
preloadHistory(messages: Message[]): void;
|
|
62
|
+
drainNewMessages(): Message[];
|
|
60
63
|
readonly turn: number;
|
|
61
64
|
pressure(): number;
|
|
62
65
|
takeObservations(): LoopObservation[];
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import type { Message } from "../types.js";
|
|
1
|
+
import type { Message, ContentPart } from "../types.js";
|
|
2
2
|
export interface SessionMessage {
|
|
3
3
|
role: Message["role"];
|
|
4
4
|
content: string;
|
|
5
|
+
/** Structured multimodal parts. Preserved for round-trip fidelity (e.g. tool result messages). */
|
|
6
|
+
contentParts?: ContentPart[];
|
|
5
7
|
tokenCount?: number;
|
|
6
8
|
toolCalls?: Array<{
|
|
7
9
|
id: string;
|
|
@@ -43,6 +45,11 @@ export interface DreamStore {
|
|
|
43
45
|
/** Persist a completed session for future consolidation via `Agent.dream()`. */
|
|
44
46
|
saveSession(data: SessionData): Promise<void>;
|
|
45
47
|
}
|
|
48
|
+
/** Durable transcript storage for same-session conversational continuity. */
|
|
49
|
+
export interface SessionStore {
|
|
50
|
+
loadSession(sessionId: string): Promise<SessionData | undefined>;
|
|
51
|
+
saveSession(data: SessionData): Promise<void>;
|
|
52
|
+
}
|
|
46
53
|
export interface DreamResult {
|
|
47
54
|
sessionsProcessed: number;
|
|
48
55
|
insightsExtracted: number;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Message, ToolSchema, StreamEvent, LLMProvider } from "../types.js";
|
|
1
|
+
import type { Message, RenderedContext, ToolSchema, StreamEvent, LLMProvider } from "../types.js";
|
|
2
2
|
interface AnthropicProviderOptions {
|
|
3
3
|
baseURL?: string;
|
|
4
4
|
authMode?: "api-key" | "bearer";
|
|
@@ -15,8 +15,12 @@ export declare class AnthropicProvider implements LLMProvider {
|
|
|
15
15
|
baseDelay: number;
|
|
16
16
|
}, options?: AnthropicProviderOptions);
|
|
17
17
|
private buildTools;
|
|
18
|
-
complete(
|
|
19
|
-
stream(
|
|
18
|
+
complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
|
|
19
|
+
stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
|
|
20
|
+
private requestExtensions;
|
|
21
|
+
private hasBetas;
|
|
22
|
+
private createMessage;
|
|
23
|
+
private streamMessage;
|
|
20
24
|
private buildMessages;
|
|
21
25
|
private rememberNativeBlocks;
|
|
22
26
|
private assistantReplayKey;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { withServerRuntimeGuard } from "../runtime/server.js";
|
|
3
|
-
import { CircuitBreaker, normalizeToolCall,
|
|
3
|
+
import { CircuitBreaker, normalizeToolCall, omitExtensionKeys, toAnthropicMessages } from "./base.js";
|
|
4
4
|
export class AnthropicProvider {
|
|
5
5
|
model;
|
|
6
6
|
client;
|
|
@@ -25,21 +25,23 @@ export class AnthropicProvider {
|
|
|
25
25
|
input_schema: JSON.parse(t.parameters),
|
|
26
26
|
}));
|
|
27
27
|
}
|
|
28
|
-
async complete(
|
|
28
|
+
async complete(context, tools, extensions) {
|
|
29
29
|
if (this.circuit.isOpen())
|
|
30
30
|
throw new Error("Circuit breaker open");
|
|
31
|
-
const system =
|
|
32
|
-
const msgs = this.buildMessages(
|
|
31
|
+
const system = context.systemText || undefined;
|
|
32
|
+
const msgs = this.buildMessages(context);
|
|
33
|
+
const requestExtensions = this.requestExtensions(extensions);
|
|
33
34
|
let lastErr;
|
|
34
35
|
for (let i = 0; i < this.maxRetries; i++) {
|
|
35
36
|
try {
|
|
36
|
-
const resp = await this.
|
|
37
|
+
const resp = await this.createMessage({
|
|
38
|
+
...requestExtensions,
|
|
37
39
|
model: this.model,
|
|
38
|
-
max_tokens: 8096,
|
|
40
|
+
max_tokens: typeof extensions?.max_tokens === "number" ? extensions.max_tokens : 8096,
|
|
39
41
|
...(system ? { system } : {}),
|
|
40
42
|
messages: msgs,
|
|
41
43
|
...(tools.length ? { tools: this.buildTools(tools) } : {}),
|
|
42
|
-
});
|
|
44
|
+
}, extensions);
|
|
43
45
|
this.circuit.recordSuccess();
|
|
44
46
|
let content = "";
|
|
45
47
|
const toolCalls = [];
|
|
@@ -65,20 +67,22 @@ export class AnthropicProvider {
|
|
|
65
67
|
}
|
|
66
68
|
throw lastErr;
|
|
67
69
|
}
|
|
68
|
-
async *stream(
|
|
69
|
-
const system =
|
|
70
|
-
const msgs = this.buildMessages(
|
|
70
|
+
async *stream(context, tools, extensions) {
|
|
71
|
+
const system = context.systemText || undefined;
|
|
72
|
+
const msgs = this.buildMessages(context);
|
|
73
|
+
const requestExtensions = this.requestExtensions(extensions);
|
|
71
74
|
const toolBlocks = {};
|
|
72
75
|
const nativeBlocks = {};
|
|
73
76
|
let finalText = "";
|
|
74
77
|
const finalToolCalls = [];
|
|
75
|
-
const stream = this.
|
|
78
|
+
const stream = this.streamMessage({
|
|
79
|
+
...requestExtensions,
|
|
76
80
|
model: this.model,
|
|
77
|
-
max_tokens: 8096,
|
|
81
|
+
max_tokens: typeof extensions?.max_tokens === "number" ? extensions.max_tokens : 8096,
|
|
78
82
|
...(system ? { system } : {}),
|
|
79
83
|
messages: msgs,
|
|
80
84
|
...(tools.length ? { tools: this.buildTools(tools) } : {}),
|
|
81
|
-
});
|
|
85
|
+
}, extensions);
|
|
82
86
|
for await (const evt of stream) {
|
|
83
87
|
if (evt.type === "content_block_start") {
|
|
84
88
|
nativeBlocks[evt.index] = { ...evt.content_block };
|
|
@@ -121,8 +125,25 @@ export class AnthropicProvider {
|
|
|
121
125
|
}
|
|
122
126
|
this.rememberNativeBlocks({ content: finalText, toolCalls: finalToolCalls }, Object.keys(nativeBlocks).map(Number).sort((a, b) => a - b).map(index => nativeBlocks[index]));
|
|
123
127
|
}
|
|
124
|
-
|
|
125
|
-
return
|
|
128
|
+
requestExtensions(extensions) {
|
|
129
|
+
return omitExtensionKeys(extensions, ["model", "messages", "system", "tools", "max_tokens", "stream"]);
|
|
130
|
+
}
|
|
131
|
+
hasBetas(extensions) {
|
|
132
|
+
const betas = extensions?.betas;
|
|
133
|
+
return Array.isArray(betas) && betas.length > 0;
|
|
134
|
+
}
|
|
135
|
+
createMessage(params, extensions) {
|
|
136
|
+
return this.hasBetas(extensions)
|
|
137
|
+
? this.client.beta.messages.create(params)
|
|
138
|
+
: this.client.messages.create(params);
|
|
139
|
+
}
|
|
140
|
+
streamMessage(params, extensions) {
|
|
141
|
+
return (this.hasBetas(extensions)
|
|
142
|
+
? this.client.beta.messages.stream(params)
|
|
143
|
+
: this.client.messages.stream(params));
|
|
144
|
+
}
|
|
145
|
+
buildMessages(context) {
|
|
146
|
+
return toAnthropicMessages(context.turns, message => this.nativeAssistantBlocks.get(this.assistantReplayKey(message)));
|
|
126
147
|
}
|
|
127
148
|
rememberNativeBlocks(message, blocks) {
|
|
128
149
|
if (!message.toolCalls?.length)
|
package/dist/providers/base.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Message, RenderedContext } from "../types.js";
|
|
1
2
|
export declare class CircuitBreaker {
|
|
2
3
|
private readonly openAfter;
|
|
3
4
|
private readonly resetAfter;
|
|
@@ -8,14 +9,17 @@ export declare class CircuitBreaker {
|
|
|
8
9
|
recordSuccess(): void;
|
|
9
10
|
recordFailure(): void;
|
|
10
11
|
}
|
|
12
|
+
export declare function omitExtensionKeys(extensions: Record<string, unknown> | undefined, keys: readonly string[]): Record<string, unknown>;
|
|
11
13
|
export declare function normalizeToolCall(id: string, name: string, args: unknown): {
|
|
12
14
|
id: string;
|
|
13
15
|
name: string;
|
|
14
16
|
arguments: string;
|
|
15
17
|
} | null;
|
|
16
|
-
import type { Message } from "../types.js";
|
|
17
18
|
export declare function toAnthropicContent(msg: Message): string | Array<Record<string, unknown>>;
|
|
19
|
+
/** Convert RenderedContext.turns to Anthropic messages array.
|
|
20
|
+
* `turns` contains only user / assistant / tool roles — no system filtering needed. */
|
|
21
|
+
export declare function toAnthropicMessages(turns: Message[], nativeReplay?: (message: Message) => Array<Record<string, unknown>> | undefined): Array<Record<string, unknown>>;
|
|
18
22
|
export declare function toOpenAIContent(msg: Message): string | Array<Record<string, unknown>>;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
export declare function toOpenAIMessageParams(
|
|
23
|
+
/** Build the full OpenAI messages array from a RenderedContext.
|
|
24
|
+
* Prepends systemText as the first system message, then converts turns. */
|
|
25
|
+
export declare function toOpenAIMessageParams(context: RenderedContext): Array<Record<string, unknown>>;
|