@deepstrike/wasm 0.1.14 → 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/dist/providers/anthropic.d.ts +5 -1
- package/dist/providers/anthropic.js +53 -16
- package/dist/providers/base.d.ts +3 -5
- package/dist/providers/base.js +38 -5
- package/dist/runtime/provider-replay.d.ts +7 -0
- package/dist/runtime/provider-replay.js +18 -0
- package/dist/runtime/runner.js +4 -0
- package/dist/runtime/session-log.d.ts +2 -1
- package/dist/types.d.ts +6 -0
- package/package.json +2 -2
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import type { RenderedContext, ToolSchema, StreamEvent, LLMProvider, Message } from "../types.js";
|
|
1
|
+
import type { RenderedContext, ToolSchema, StreamEvent, LLMProvider, Message, ProviderReplay } from "../types.js";
|
|
2
2
|
export declare class AnthropicProvider implements LLMProvider {
|
|
3
3
|
private readonly apiKey;
|
|
4
4
|
private readonly model;
|
|
5
5
|
private readonly maxTokens;
|
|
6
|
+
private nativeAssistantBlocks;
|
|
6
7
|
constructor(apiKey: string, model?: string, maxTokens?: number);
|
|
8
|
+
peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
|
|
9
|
+
seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
|
|
7
10
|
complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
|
|
8
11
|
stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
|
|
12
|
+
private rememberNativeBlocks;
|
|
9
13
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { collectStreamMessage, toAnthropicMessages } from "./base.js";
|
|
1
|
+
import { assistantReplayKey, collectStreamMessage, toAnthropicMessages } from "./base.js";
|
|
2
2
|
function buildAnthropicTools(tools) {
|
|
3
3
|
return tools.map(t => ({ name: t.name, description: t.description, input_schema: JSON.parse(t.parameters) }));
|
|
4
4
|
}
|
|
@@ -6,17 +6,27 @@ export class AnthropicProvider {
|
|
|
6
6
|
apiKey;
|
|
7
7
|
model;
|
|
8
8
|
maxTokens;
|
|
9
|
+
nativeAssistantBlocks = new Map();
|
|
9
10
|
constructor(apiKey, model = "claude-sonnet-4-6", maxTokens = 8096) {
|
|
10
11
|
this.apiKey = apiKey;
|
|
11
12
|
this.model = model;
|
|
12
13
|
this.maxTokens = maxTokens;
|
|
13
14
|
}
|
|
15
|
+
peekProviderReplay(message) {
|
|
16
|
+
const blocks = this.nativeAssistantBlocks.get(assistantReplayKey(message));
|
|
17
|
+
return blocks?.length ? { native_blocks: blocks } : undefined;
|
|
18
|
+
}
|
|
19
|
+
seedProviderReplay(message, replay) {
|
|
20
|
+
if (replay.native_blocks?.length) {
|
|
21
|
+
this.nativeAssistantBlocks.set(assistantReplayKey(message), replay.native_blocks);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
14
24
|
async complete(context, tools, extensions) {
|
|
15
25
|
return collectStreamMessage(this.stream(context, tools, extensions));
|
|
16
26
|
}
|
|
17
27
|
async *stream(context, tools, extensions) {
|
|
18
28
|
const system = context.systemText || undefined;
|
|
19
|
-
const msgs = toAnthropicMessages(context);
|
|
29
|
+
const msgs = toAnthropicMessages(context, message => this.nativeAssistantBlocks.get(assistantReplayKey(message)));
|
|
20
30
|
const body = {
|
|
21
31
|
model: this.model,
|
|
22
32
|
max_tokens: this.maxTokens,
|
|
@@ -40,6 +50,9 @@ export class AnthropicProvider {
|
|
|
40
50
|
if (!resp.ok)
|
|
41
51
|
throw new Error(`Anthropic ${resp.status}: ${await resp.text()}`);
|
|
42
52
|
const toolBlocks = {};
|
|
53
|
+
const nativeBlocks = {};
|
|
54
|
+
let finalText = "";
|
|
55
|
+
const finalToolCalls = [];
|
|
43
56
|
const reader = resp.body.getReader();
|
|
44
57
|
const decoder = new TextDecoder();
|
|
45
58
|
let buf = "";
|
|
@@ -68,35 +81,59 @@ export class AnthropicProvider {
|
|
|
68
81
|
}
|
|
69
82
|
}
|
|
70
83
|
else if (evt.type === "content_block_start") {
|
|
84
|
+
const idx = evt.index;
|
|
85
|
+
nativeBlocks[idx] = { ...evt.content_block };
|
|
71
86
|
const cb = evt.content_block;
|
|
72
87
|
if (cb.type === "tool_use")
|
|
73
|
-
toolBlocks[
|
|
88
|
+
toolBlocks[idx] = { id: cb.id, name: cb.name, argsBuf: "" };
|
|
74
89
|
}
|
|
75
90
|
else if (evt.type === "content_block_delta") {
|
|
76
91
|
const d = evt.delta;
|
|
77
92
|
const idx = evt.index;
|
|
78
|
-
if (d.type === "text_delta")
|
|
93
|
+
if (d.type === "text_delta") {
|
|
94
|
+
finalText += String(d.text);
|
|
95
|
+
nativeBlocks[idx] = { ...nativeBlocks[idx], text: String(nativeBlocks[idx]?.text ?? "") + d.text };
|
|
79
96
|
yield { type: "text_delta", delta: d.text };
|
|
80
|
-
|
|
97
|
+
}
|
|
98
|
+
else if (d.type === "thinking_delta") {
|
|
99
|
+
nativeBlocks[idx] = { ...nativeBlocks[idx], thinking: String(nativeBlocks[idx]?.thinking ?? "") + d.thinking };
|
|
81
100
|
yield { type: "thinking_delta", delta: d.thinking };
|
|
82
|
-
|
|
101
|
+
}
|
|
102
|
+
else if (d.type === "signature_delta") {
|
|
103
|
+
nativeBlocks[idx] = { ...nativeBlocks[idx], signature: String(nativeBlocks[idx]?.signature ?? "") + d.signature };
|
|
104
|
+
}
|
|
105
|
+
else if (d.type === "input_json_delta" && toolBlocks[idx]) {
|
|
83
106
|
toolBlocks[idx].argsBuf += d.partial_json;
|
|
84
|
-
}
|
|
85
|
-
else if (evt.type === "content_block_stop" && toolBlocks[evt.index]) {
|
|
86
|
-
const tb = toolBlocks[evt.index];
|
|
87
|
-
delete toolBlocks[evt.index];
|
|
88
|
-
let args = {};
|
|
89
|
-
try {
|
|
90
|
-
args = JSON.parse(tb.argsBuf || "{}");
|
|
91
107
|
}
|
|
92
|
-
|
|
93
|
-
|
|
108
|
+
}
|
|
109
|
+
else if (evt.type === "content_block_stop") {
|
|
110
|
+
const idx = evt.index;
|
|
111
|
+
if (toolBlocks[idx]) {
|
|
112
|
+
const tb = toolBlocks[idx];
|
|
113
|
+
delete toolBlocks[idx];
|
|
114
|
+
let args = {};
|
|
115
|
+
try {
|
|
116
|
+
args = JSON.parse(tb.argsBuf || "{}");
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
args = {};
|
|
120
|
+
}
|
|
121
|
+
nativeBlocks[idx] = { ...nativeBlocks[idx], input: args };
|
|
122
|
+
finalToolCalls.push({ id: tb.id, name: tb.name, arguments: JSON.stringify(args) });
|
|
123
|
+
yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
|
|
94
124
|
}
|
|
95
|
-
yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
|
|
96
125
|
}
|
|
97
126
|
}
|
|
98
127
|
catch { /* skip malformed */ }
|
|
99
128
|
}
|
|
100
129
|
}
|
|
130
|
+
this.rememberNativeBlocks({ content: finalText, toolCalls: finalToolCalls }, Object.keys(nativeBlocks).map(Number).sort((a, b) => a - b).map(index => nativeBlocks[index]));
|
|
131
|
+
}
|
|
132
|
+
rememberNativeBlocks(message, blocks) {
|
|
133
|
+
if (!blocks.length)
|
|
134
|
+
return;
|
|
135
|
+
if (!message.toolCalls?.length && !blocks.some(b => b.type === "thinking"))
|
|
136
|
+
return;
|
|
137
|
+
this.nativeAssistantBlocks.set(assistantReplayKey(message), blocks);
|
|
101
138
|
}
|
|
102
139
|
}
|
package/dist/providers/base.d.ts
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type { Message, RenderedContext } from "../types.js";
|
|
2
|
+
import { assistantReplayKey } from "../runtime/provider-replay.js";
|
|
2
3
|
/** Build OpenAI-compatible chat messages from a RenderedContext. */
|
|
3
4
|
export declare function toOpenAIMessages(context: RenderedContext): Array<Record<string, unknown>>;
|
|
4
|
-
|
|
5
|
-
export declare function toAnthropicMessages(context: RenderedContext): Array<{
|
|
6
|
-
role: string;
|
|
7
|
-
content: string;
|
|
8
|
-
}>;
|
|
5
|
+
export declare function toAnthropicMessages(context: RenderedContext, nativeReplay?: (message: Message) => Array<Record<string, unknown>> | undefined): Array<Record<string, unknown>>;
|
|
9
6
|
/** Collect a non-streaming assistant Message from stream events. */
|
|
10
7
|
export declare function collectStreamMessage(stream: AsyncIterable<{
|
|
11
8
|
type: string;
|
|
@@ -14,3 +11,4 @@ export declare function collectStreamMessage(stream: AsyncIterable<{
|
|
|
14
11
|
name?: string;
|
|
15
12
|
arguments?: Record<string, unknown>;
|
|
16
13
|
}>): Promise<Message>;
|
|
14
|
+
export { assistantReplayKey };
|
package/dist/providers/base.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
import { assistantReplayKey } from "../runtime/provider-replay.js";
|
|
2
|
+
function parseToolArguments(args) {
|
|
3
|
+
try {
|
|
4
|
+
return JSON.parse(args || "{}");
|
|
5
|
+
}
|
|
6
|
+
catch {
|
|
7
|
+
return {};
|
|
8
|
+
}
|
|
9
|
+
}
|
|
1
10
|
/** Build OpenAI-compatible chat messages from a RenderedContext. */
|
|
2
11
|
export function toOpenAIMessages(context) {
|
|
3
12
|
const messages = [];
|
|
@@ -21,11 +30,34 @@ export function toOpenAIMessages(context) {
|
|
|
21
30
|
}
|
|
22
31
|
return messages;
|
|
23
32
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
export function toAnthropicMessages(context, nativeReplay) {
|
|
34
|
+
const result = [];
|
|
35
|
+
for (const msg of context.turns) {
|
|
36
|
+
if (msg.role === "tool") {
|
|
37
|
+
result.push({ role: "user", content: [{ type: "tool_result", tool_use_id: msg.content ? undefined : "", content: msg.content, is_error: false }] });
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (msg.role === "assistant" && msg.toolCalls?.length) {
|
|
41
|
+
const replay = nativeReplay?.(msg);
|
|
42
|
+
if (replay) {
|
|
43
|
+
result.push({ role: "assistant", content: replay });
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const blocks = [];
|
|
47
|
+
if (msg.content)
|
|
48
|
+
blocks.push({ type: "text", text: msg.content });
|
|
49
|
+
blocks.push(...msg.toolCalls.map(tc => ({
|
|
50
|
+
type: "tool_use",
|
|
51
|
+
id: tc.id,
|
|
52
|
+
name: tc.name,
|
|
53
|
+
input: parseToolArguments(tc.arguments),
|
|
54
|
+
})));
|
|
55
|
+
result.push({ role: "assistant", content: blocks });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
result.push({ role: msg.role, content: msg.content });
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
29
61
|
}
|
|
30
62
|
/** Collect a non-streaming assistant Message from stream events. */
|
|
31
63
|
export async function collectStreamMessage(stream) {
|
|
@@ -40,3 +72,4 @@ export async function collectStreamMessage(stream) {
|
|
|
40
72
|
}
|
|
41
73
|
return { role: "assistant", content, ...(toolCalls.length ? { toolCalls } : {}) };
|
|
42
74
|
}
|
|
75
|
+
export { assistantReplayKey };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { LLMProvider, Message, ProviderReplay, ToolCall } from "../types.js";
|
|
2
|
+
import type { SessionEvent } from "./session-log.js";
|
|
3
|
+
export declare function assistantReplayKey(message: Pick<Message, "content" | "toolCalls">): string;
|
|
4
|
+
export declare function seedProviderReplayFromEvents(provider: LLMProvider, events: Array<{
|
|
5
|
+
event: SessionEvent;
|
|
6
|
+
}>): void;
|
|
7
|
+
export declare function peekProviderReplay(provider: LLMProvider, content: string, toolCalls: ToolCall[]): ProviderReplay | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function assistantReplayKey(message) {
|
|
2
|
+
return JSON.stringify({
|
|
3
|
+
content: message.content,
|
|
4
|
+
toolCalls: message.toolCalls ?? [],
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
export function seedProviderReplayFromEvents(provider, events) {
|
|
8
|
+
if (!provider.seedProviderReplay)
|
|
9
|
+
return;
|
|
10
|
+
for (const { event } of events) {
|
|
11
|
+
if (event.kind !== "llm_completed" || !event.provider_replay)
|
|
12
|
+
continue;
|
|
13
|
+
provider.seedProviderReplay({ content: event.content, toolCalls: event.tool_calls ?? [] }, event.provider_replay);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function peekProviderReplay(provider, content, toolCalls) {
|
|
17
|
+
return provider.peekProviderReplay?.({ content, toolCalls });
|
|
18
|
+
}
|
package/dist/runtime/runner.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getKernel } from "./kernel.js";
|
|
2
|
+
import { peekProviderReplay, seedProviderReplayFromEvents } from "./provider-replay.js";
|
|
2
3
|
export class RuntimeRunner {
|
|
3
4
|
opts;
|
|
4
5
|
interrupted = false;
|
|
@@ -129,6 +130,7 @@ export class RuntimeRunner {
|
|
|
129
130
|
if (this.opts.knowledgeSource)
|
|
130
131
|
sm.setKnowledgeEnabled(true);
|
|
131
132
|
if (priorEvents && priorEvents.length > 0) {
|
|
133
|
+
seedProviderReplayFromEvents(this.opts.provider, priorEvents);
|
|
132
134
|
sm.preloadHistory(replayMessages(priorEvents));
|
|
133
135
|
}
|
|
134
136
|
const sessionStart = Date.now();
|
|
@@ -203,12 +205,14 @@ export class RuntimeRunner {
|
|
|
203
205
|
toolCalls: finalToolCalls,
|
|
204
206
|
tokenCount: turnTokens || undefined,
|
|
205
207
|
});
|
|
208
|
+
const providerReplay = peekProviderReplay(this.opts.provider, finalText, finalToolCalls);
|
|
206
209
|
await this.opts.sessionLog.append(sessionId, {
|
|
207
210
|
kind: "llm_completed",
|
|
208
211
|
turn: sm.turn,
|
|
209
212
|
content: finalText,
|
|
210
213
|
token_count: turnTokens || undefined,
|
|
211
214
|
tool_calls: finalToolCalls,
|
|
215
|
+
...(providerReplay ? { provider_replay: providerReplay } : {}),
|
|
212
216
|
});
|
|
213
217
|
}
|
|
214
218
|
else if (action.kind === "execute_tools") {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ToolCall } from "../types.js";
|
|
1
|
+
import type { ProviderReplay, ToolCall } from "../types.js";
|
|
2
2
|
export type SessionEvent = {
|
|
3
3
|
kind: "run_started";
|
|
4
4
|
run_id: string;
|
|
@@ -12,6 +12,7 @@ export type SessionEvent = {
|
|
|
12
12
|
content: string;
|
|
13
13
|
token_count?: number;
|
|
14
14
|
tool_calls: ToolCall[];
|
|
15
|
+
provider_replay?: ProviderReplay;
|
|
15
16
|
} | {
|
|
16
17
|
kind: "tool_requested";
|
|
17
18
|
turn: number;
|
package/dist/types.d.ts
CHANGED
|
@@ -75,12 +75,18 @@ export interface PermissionRequestEvent extends StreamEvent {
|
|
|
75
75
|
* The framework creates and threads this object; providers may read/write it.
|
|
76
76
|
*/
|
|
77
77
|
export type ProviderRunState = Record<string, unknown>;
|
|
78
|
+
export interface ProviderReplay {
|
|
79
|
+
native_blocks?: Array<Record<string, unknown>>;
|
|
80
|
+
reasoning_content?: string;
|
|
81
|
+
}
|
|
78
82
|
export interface LLMProvider {
|
|
79
83
|
createRunState?(): ProviderRunState;
|
|
80
84
|
runtimePolicy?(): {
|
|
81
85
|
maxTurns?: number;
|
|
82
86
|
timeoutMs?: number;
|
|
83
87
|
};
|
|
88
|
+
peekProviderReplay?(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
|
|
89
|
+
seedProviderReplay?(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
|
|
84
90
|
complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
|
|
85
91
|
stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, state?: ProviderRunState): AsyncIterable<StreamEvent>;
|
|
86
92
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepstrike/wasm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "DeepStrike WASM SDK — browser, Cloudflare Workers, Deno Deploy",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"test": "node --experimental-vm-modules node_modules/.bin/jest"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@deepstrike/wasm-kernel": "0.1.
|
|
18
|
+
"@deepstrike/wasm-kernel": "0.1.15"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@types/jest": "^30.0.0",
|