@deepstrike/wasm 0.1.11 → 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.
@@ -1,3 +1,4 @@
1
+ import { collectStreamMessage, toOpenAIMessages } from "./base.js";
1
2
  const DEEPSEEK_REASONERS = new Set(["deepseek-reasoner", "deepseek-r1"]);
2
3
  const MINIMAX_REASONERS = new Set(["MiniMax-M1", "minimax-m1"]);
3
4
  // OpenAI-compatible provider — works for OpenAI, Qwen (DashScope), DeepSeek, MiniMax, Kimi
@@ -13,11 +14,13 @@ export class OpenAIProvider {
13
14
  buildTools(tools) {
14
15
  return tools.map(t => ({ type: "function", function: { name: t.name, description: t.description, parameters: JSON.parse(t.parameters) } }));
15
16
  }
16
- async *streamInner(messages, tools, extraBody, exposeReasoning = false) {
17
- const msgs = messages.map(m => ({ role: m.role, content: m.content }));
17
+ async complete(context, tools, extensions) {
18
+ return collectStreamMessage(this.stream(context, tools, extensions));
19
+ }
20
+ async *streamInner(context, tools, extraBody, exposeReasoning = false) {
18
21
  const body = {
19
22
  model: this.model,
20
- messages: msgs,
23
+ messages: toOpenAIMessages(context),
21
24
  stream: true,
22
25
  ...(tools.length ? { tools: this.buildTools(tools) } : {}),
23
26
  ...extraBody,
@@ -76,16 +79,16 @@ export class OpenAIProvider {
76
79
  yield { type: "tool_call", id: tb.id, name: tb.name, arguments: args };
77
80
  }
78
81
  }
79
- async *stream(messages, tools, extensions) {
82
+ async *stream(context, tools, extensions) {
80
83
  const { expose_reasoning: _, exposeReasoning: __, ...passthrough } = extensions ?? {};
81
- yield* this.streamInner(messages, tools, passthrough);
84
+ yield* this.streamInner(context, tools, passthrough);
82
85
  }
83
86
  }
84
87
  export class QwenProvider extends OpenAIProvider {
85
88
  constructor(apiKey, model = "qwen-max") {
86
89
  super(apiKey, model, "https://dashscope.aliyuncs.com/compatible-mode/v1");
87
90
  }
88
- async *stream(messages, tools, extensions) {
91
+ async *stream(context, tools, extensions) {
89
92
  const enableThinking = Boolean(extensions?.enableThinking);
90
93
  const thinkingBudget = extensions?.thinkingBudget;
91
94
  const { enableThinking: _, thinkingBudget: __, expose_reasoning: ___, exposeReasoning: ____, ...passthrough } = extensions ?? {};
@@ -93,31 +96,31 @@ export class QwenProvider extends OpenAIProvider {
93
96
  ...passthrough,
94
97
  ...(enableThinking ? { enable_thinking: true, ...(thinkingBudget ? { thinking_budget: thinkingBudget } : {}) } : {}),
95
98
  };
96
- yield* this.streamInner(messages, tools, extra, enableThinking);
99
+ yield* this.streamInner(context, tools, extra, enableThinking);
97
100
  }
98
101
  }
99
102
  export class DeepSeekProvider extends OpenAIProvider {
100
103
  constructor(apiKey, model = "deepseek-chat") {
101
104
  super(apiKey, model, "https://api.deepseek.com/v1");
102
105
  }
103
- async *stream(messages, tools, extensions) {
106
+ async *stream(context, tools, extensions) {
104
107
  const exposeReasoning = Boolean(extensions?.exposeReasoning);
105
108
  const isReasoner = DEEPSEEK_REASONERS.has(this.model);
106
109
  const filteredTools = isReasoner ? [] : tools;
107
110
  const { exposeReasoning: _, expose_reasoning: __, ...passthrough } = extensions ?? {};
108
- yield* this.streamInner(messages, filteredTools, passthrough, exposeReasoning);
111
+ yield* this.streamInner(context, filteredTools, passthrough, exposeReasoning);
109
112
  }
110
113
  }
111
114
  export class MiniMaxProvider extends OpenAIProvider {
112
115
  constructor(apiKey, model = "MiniMax-Text-01") {
113
116
  super(apiKey, model, "https://api.minimax.chat/v1");
114
117
  }
115
- async *stream(messages, tools, extensions) {
118
+ async *stream(context, tools, extensions) {
116
119
  const exposeReasoning = Boolean(extensions?.exposeReasoning);
117
120
  const isReasoner = MINIMAX_REASONERS.has(this.model);
118
121
  const filteredTools = isReasoner ? [] : tools;
119
122
  const { exposeReasoning: _, expose_reasoning: __, ...passthrough } = extensions ?? {};
120
- yield* this.streamInner(messages, filteredTools, passthrough, exposeReasoning);
123
+ yield* this.streamInner(context, filteredTools, passthrough, exposeReasoning);
121
124
  }
122
125
  }
123
126
  export class KimiProvider extends OpenAIProvider {
@@ -0,0 +1,33 @@
1
+ import type { ToolCall, ToolSchema, StreamEvent } from "../types.js";
2
+ import type { RegisteredTool } from "../tools/index.js";
3
+ import type { DreamStore } from "../memory/index.js";
4
+ import type { KnowledgeSource } from "../knowledge/index.js";
5
+ import type { Governance } from "../governance.js";
6
+ export interface ToolSuspendEvent {
7
+ type: "tool_suspend";
8
+ callId: string;
9
+ name: string;
10
+ suspensionId: string;
11
+ payload?: unknown;
12
+ }
13
+ export interface RunContext {
14
+ agentId?: string;
15
+ skillContentMap?: Map<string, string>;
16
+ dreamStore?: DreamStore;
17
+ knowledgeSource?: KnowledgeSource;
18
+ governance?: Governance;
19
+ onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
20
+ }
21
+ export interface ExecutionPlane {
22
+ register(...tools: RegisteredTool[]): this;
23
+ unregister(name: string): this;
24
+ schemas(): ToolSchema[];
25
+ executeAll(calls: ToolCall[], ctx: RunContext): AsyncIterable<StreamEvent>;
26
+ }
27
+ export declare class LocalExecutionPlane implements ExecutionPlane {
28
+ private tools;
29
+ register(...tools: RegisteredTool[]): this;
30
+ unregister(name: string): this;
31
+ schemas(): ToolSchema[];
32
+ executeAll(calls: ToolCall[], ctx: RunContext): AsyncIterable<StreamEvent>;
33
+ }
@@ -0,0 +1,108 @@
1
+ function stripFrontmatter(content) {
2
+ const s = content.trimStart();
3
+ if (!s.startsWith("---"))
4
+ return s;
5
+ const rest = s.slice(3);
6
+ const end = rest.indexOf("\n---");
7
+ return end >= 0 ? rest.slice(end + 4).trimStart() : s;
8
+ }
9
+ export class LocalExecutionPlane {
10
+ tools = new Map();
11
+ register(...tools) {
12
+ for (const t of tools)
13
+ this.tools.set(t.schema.name, t);
14
+ return this;
15
+ }
16
+ unregister(name) {
17
+ this.tools.delete(name);
18
+ return this;
19
+ }
20
+ schemas() {
21
+ return Array.from(this.tools.values()).map(t => t.schema);
22
+ }
23
+ async *executeAll(calls, ctx) {
24
+ const permitted = [];
25
+ for (const c of calls) {
26
+ if (ctx.governance) {
27
+ ctx.governance.setTime(Date.now());
28
+ const v = ctx.governance.evaluate(c.name, c.arguments);
29
+ if (v.kind === "deny") {
30
+ yield { type: "error", message: `permission denied: ${c.name} — ${v.reason ?? ""}` };
31
+ yield { type: "tool_result", callId: c.id, name: c.name, content: `permission denied: ${v.reason ?? ""}`, isError: true };
32
+ continue;
33
+ }
34
+ if (v.kind === "rate_limited") {
35
+ yield { type: "error", message: `rate limited: ${c.name}` };
36
+ yield { type: "tool_result", callId: c.id, name: c.name, content: "rate limited", isError: true };
37
+ continue;
38
+ }
39
+ if (v.kind === "ask_user") {
40
+ yield { type: "permission_request", callId: c.id, toolName: c.name, arguments: c.arguments, reason: v.reason ?? "" };
41
+ yield { type: "tool_result", callId: c.id, name: c.name, content: "awaiting user approval", isError: true };
42
+ continue;
43
+ }
44
+ }
45
+ permitted.push(c);
46
+ }
47
+ const skillCalls = permitted.filter(c => c.name === "skill");
48
+ const memoryCalls = permitted.filter(c => c.name === "memory");
49
+ const knowledgeCalls = permitted.filter(c => c.name === "knowledge");
50
+ const regularCalls = permitted.filter(c => !["skill", "memory", "knowledge"].includes(c.name));
51
+ for (const c of skillCalls) {
52
+ const args = tryParseJson(c.arguments);
53
+ const name = String(args?.name ?? "");
54
+ const raw = ctx.skillContentMap?.get(name);
55
+ const content = raw != null ? stripFrontmatter(raw) : null;
56
+ yield {
57
+ type: "tool_result",
58
+ callId: c.id,
59
+ name: c.name,
60
+ content: content ?? `Skill "${name}" not found.`,
61
+ isError: content == null,
62
+ };
63
+ }
64
+ for (const c of memoryCalls) {
65
+ const args = tryParseJson(c.arguments);
66
+ const topK = typeof args?.top_k === "number" ? args.top_k : 5;
67
+ const entries = (ctx.dreamStore && ctx.agentId)
68
+ ? await ctx.dreamStore.search(ctx.agentId, String(args?.query ?? ""), topK)
69
+ : [];
70
+ const content = entries.length
71
+ ? entries.map((e) => `[score=${e.score.toFixed(3)}] ${e.text}`).join("\n---\n")
72
+ : "No relevant memories found.";
73
+ yield { type: "tool_result", callId: c.id, name: c.name, content, isError: false };
74
+ }
75
+ for (const c of knowledgeCalls) {
76
+ const args = tryParseJson(c.arguments);
77
+ const topK = typeof args?.top_k === "number" ? args.top_k : 5;
78
+ const snippets = ctx.knowledgeSource
79
+ ? await ctx.knowledgeSource.retrieve(String(args?.query ?? ""), topK)
80
+ : [];
81
+ const content = snippets.length ? snippets.join("\n---\n") : "No relevant knowledge found.";
82
+ yield { type: "tool_result", callId: c.id, name: c.name, content, isError: false };
83
+ }
84
+ for (const call of regularCalls) {
85
+ const registered = this.tools.get(call.name);
86
+ if (!registered) {
87
+ yield { type: "tool_result", callId: call.id, name: call.name, content: `unknown tool: ${call.name}`, isError: true };
88
+ continue;
89
+ }
90
+ try {
91
+ const args = JSON.parse(call.arguments || "{}");
92
+ const output = await registered.execute(args);
93
+ yield { type: "tool_result", callId: call.id, name: call.name, content: String(output), isError: false };
94
+ }
95
+ catch (err) {
96
+ yield { type: "tool_result", callId: call.id, name: call.name, content: String(err), isError: true };
97
+ }
98
+ }
99
+ }
100
+ }
101
+ function tryParseJson(s) {
102
+ try {
103
+ return JSON.parse(s);
104
+ }
105
+ catch {
106
+ return null;
107
+ }
108
+ }
@@ -0,0 +1,7 @@
1
+ export type { SessionEvent, SessionLog } from "./session-log.js";
2
+ export { InMemorySessionLog } from "./session-log.js";
3
+ export type { RunContext, ExecutionPlane } from "./execution-plane.js";
4
+ export { LocalExecutionPlane } from "./execution-plane.js";
5
+ export type { RuntimeOptions } from "./runner.js";
6
+ export { RuntimeRunner, collectText } from "./runner.js";
7
+ export { getKernel } from "./kernel.js";
@@ -0,0 +1,4 @@
1
+ export { InMemorySessionLog } from "./session-log.js";
2
+ export { LocalExecutionPlane } from "./execution-plane.js";
3
+ export { RuntimeRunner, collectText } from "./runner.js";
4
+ export { getKernel } from "./kernel.js";
@@ -0,0 +1,4 @@
1
+ type WasmKernel = typeof import("@deepstrike/wasm-kernel");
2
+ /** Lazily load the WASM kernel (browser / worker safe). */
3
+ export declare function getKernel(): Promise<WasmKernel>;
4
+ export {};
@@ -0,0 +1,8 @@
1
+ let kernelMod = null;
2
+ /** Lazily load the WASM kernel (browser / worker safe). */
3
+ export async function getKernel() {
4
+ if (!kernelMod) {
5
+ kernelMod = await import("@deepstrike/wasm-kernel");
6
+ }
7
+ return kernelMod;
8
+ }
@@ -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
+ }
@@ -0,0 +1,44 @@
1
+ import type { LLMProvider, StreamEvent } from "../types.js";
2
+ import type { ToolSuspendEvent } from "./execution-plane.js";
3
+ import type { DreamStore, DreamResult } from "../memory/index.js";
4
+ import type { KnowledgeSource } from "../knowledge/index.js";
5
+ import type { SignalSource } from "../signals/index.js";
6
+ import type { SessionLog } from "./session-log.js";
7
+ import type { ExecutionPlane } from "./execution-plane.js";
8
+ import type { Governance } from "../governance.js";
9
+ export interface RuntimeOptions {
10
+ provider: LLMProvider;
11
+ sessionLog: SessionLog;
12
+ executionPlane: ExecutionPlane;
13
+ maxTokens: number;
14
+ maxTurns?: number;
15
+ timeoutMs?: number;
16
+ agentId?: string;
17
+ systemPrompt?: string;
18
+ initialMemory?: string[];
19
+ /** Skill name → markdown body (WASM has no filesystem). */
20
+ skillContentMap?: Map<string, string>;
21
+ dreamStore?: DreamStore;
22
+ knowledgeSource?: KnowledgeSource;
23
+ signalSource?: SignalSource;
24
+ extensions?: Record<string, unknown>;
25
+ governance?: Governance;
26
+ onToolSuspend?: (event: ToolSuspendEvent) => Promise<unknown> | unknown;
27
+ }
28
+ export declare class RuntimeRunner {
29
+ private readonly opts;
30
+ private interrupted;
31
+ constructor(opts: RuntimeOptions);
32
+ interrupt(): void;
33
+ run(req: {
34
+ sessionId: string;
35
+ goal: string;
36
+ criteria?: string[];
37
+ extensions?: Record<string, unknown>;
38
+ }): AsyncIterable<StreamEvent>;
39
+ wake(sessionId: string, extensions?: Record<string, unknown>): AsyncIterable<StreamEvent>;
40
+ dream(agentId: string, nowMs?: number): Promise<DreamResult>;
41
+ private execute;
42
+ private appendObservations;
43
+ }
44
+ export declare function collectText(stream: AsyncIterable<StreamEvent>): Promise<string>;