@deepstrike/wasm 0.2.20 → 0.2.22

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/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export { OpenAIProvider, QwenProvider, DeepSeekProvider, MiniMaxProvider, KimiPr
14
14
  export { tool, executeTools } from "./tools/index.js";
15
15
  export type { RegisteredTool } from "./tools/index.js";
16
16
  export { WorkingMemory } from "./memory/index.js";
17
+ export { InMemoryDreamStore } from "./memory/in-memory-store.js";
17
18
  export type { DreamStore, DreamResult, SessionStore, SessionData, SessionMessage, MemoryEntry, CurationResult, CurationStats, } from "./memory/index.js";
18
19
  export type { KnowledgeSource } from "./knowledge/index.js";
19
20
  export { SinglePassHarness, HarnessLoop } from "./harness/index.js";
@@ -22,4 +23,4 @@ export { ScheduledPrompt } from "./signals/index.js";
22
23
  export type { RuntimeSignal, SignalSource } from "./signals/index.js";
23
24
  export { PermissionManager, PermissionMode } from "./safety/index.js";
24
25
  export type { PermissionDecision } from "./safety/index.js";
25
- export type { Message, ToolCall, ToolResult, ToolSchema, RenderedContext, ProviderRunState, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, LLMProvider, } from "./types.js";
26
+ export type { Message, ToolCall, ToolResult, ToolSchema, RenderedContext, ProviderRunState, StreamEvent, TextDelta, ThinkingDelta, ToolCallEvent, ToolResultEvent, DoneEvent, ErrorEvent, PermissionRequestEvent, PermissionResolvedEvent, PermissionResponse, LLMProvider, CacheBreakpointStrategy, } from "./types.js";
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ export { AnthropicProvider } from "./providers/anthropic.js";
8
8
  export { OpenAIProvider, QwenProvider, DeepSeekProvider, MiniMaxProvider, KimiProvider } from "./providers/openai.js";
9
9
  export { tool, executeTools } from "./tools/index.js";
10
10
  export { WorkingMemory } from "./memory/index.js";
11
+ export { InMemoryDreamStore } from "./memory/in-memory-store.js";
11
12
  export { SinglePassHarness, HarnessLoop } from "./harness/index.js";
12
13
  export { ScheduledPrompt } from "./signals/index.js";
13
14
  export { PermissionManager, PermissionMode } from "./safety/index.js";
@@ -0,0 +1,19 @@
1
+ /**
2
+ * `InMemoryDreamStore` — a lightweight `DreamStore` implementation backed by per-agent `Map`s.
3
+ * WASM port of node/src/memory/in-memory-store.ts. See that file for the full design.
4
+ */
5
+ import type { CurationResult, DreamStore, MemoryEntry, SessionData } from "./index.js";
6
+ export declare class InMemoryDreamStore implements DreamStore {
7
+ private readonly initialMemories;
8
+ private sessions;
9
+ private memories;
10
+ readonly savedSessions: SessionData[];
11
+ constructor(initialMemories?: MemoryEntry[]);
12
+ addSession(agentId: string, session: SessionData): void;
13
+ addMemories(agentId: string, entries: MemoryEntry[]): void;
14
+ loadSessions(agentId: string): Promise<SessionData[]>;
15
+ loadMemories(agentId: string): Promise<MemoryEntry[]>;
16
+ commit(agentId: string, result: CurationResult, existing: MemoryEntry[]): Promise<void>;
17
+ search(agentId: string, _query: string, topK?: number): Promise<MemoryEntry[]>;
18
+ saveSession(data: SessionData): Promise<void>;
19
+ }
@@ -0,0 +1,43 @@
1
+ export class InMemoryDreamStore {
2
+ initialMemories;
3
+ sessions = new Map();
4
+ memories = new Map();
5
+ savedSessions = [];
6
+ constructor(initialMemories = []) {
7
+ this.initialMemories = initialMemories;
8
+ }
9
+ addSession(agentId, session) {
10
+ const list = this.sessions.get(agentId) ?? [];
11
+ list.push(session);
12
+ this.sessions.set(agentId, list);
13
+ }
14
+ addMemories(agentId, entries) {
15
+ this.memories.set(agentId, [...(this.memories.get(agentId) ?? []), ...entries]);
16
+ }
17
+ async loadSessions(agentId) {
18
+ return this.sessions.get(agentId) ?? [];
19
+ }
20
+ async loadMemories(agentId) {
21
+ if (this.memories.has(agentId))
22
+ return this.memories.get(agentId);
23
+ if (this.initialMemories.length > 0) {
24
+ this.memories.set(agentId, [...this.initialMemories]);
25
+ return this.memories.get(agentId);
26
+ }
27
+ return [];
28
+ }
29
+ async commit(agentId, result, existing) {
30
+ const kept = existing.filter((_, i) => !result.toRemoveIndices.includes(i));
31
+ this.memories.set(agentId, [...kept, ...result.toAdd]);
32
+ }
33
+ async search(agentId, _query, topK = 5) {
34
+ const all = await this.loadMemories(agentId);
35
+ return all.slice(0, topK);
36
+ }
37
+ async saveSession(data) {
38
+ this.savedSessions.push(data);
39
+ const list = this.sessions.get(data.agentId) ?? [];
40
+ list.push(data);
41
+ this.sessions.set(data.agentId, list);
42
+ }
43
+ }
@@ -3,18 +3,26 @@ import { assistantReplayKey, collectStreamMessage, toAnthropicMessages } from ".
3
3
  const MAX_CACHE_BREAKPOINTS = 4;
4
4
  /** Rolling cache breakpoints reserved for the message history (system uses ≤2). */
5
5
  const MESSAGE_CACHE_BREAKPOINTS = 2;
6
- function buildAnthropicTools(tools, anchorCache) {
6
+ function buildAnthropicTools(tools, anchorCache, strategy) {
7
+ const emitOnLastTool = anchorCache && (strategy === "default" || strategy === "tools-only");
7
8
  return tools.map((t, i) => ({
8
9
  name: t.name,
9
10
  description: t.description,
10
11
  input_schema: JSON.parse(t.parameters),
11
- // Anchor a tool breakpoint only when the system blocks won't carry one;
12
- // otherwise systemStable already caches the tools prefix (tools render
13
- // first), and a redundant tool breakpoint would burn a slot the message
14
- // history needs to stay within the 4-breakpoint budget.
15
- ...(anchorCache && i === tools.length - 1 ? { cache_control: { type: "ephemeral" } } : {}),
12
+ ...(emitOnLastTool && i === tools.length - 1 ? { cache_control: { type: "ephemeral" } } : {}),
16
13
  }));
17
14
  }
15
+ /** Recognised values for the `cacheBreakpointStrategy` extension; unknown → "default". */
16
+ const CACHE_BREAKPOINT_STRATEGIES = new Set([
17
+ "default", "tools-only", "system-only", "frozen-prefix", "none",
18
+ ]);
19
+ function resolveCacheBreakpointStrategy(extensions) {
20
+ const raw = extensions?.cacheBreakpointStrategy;
21
+ if (typeof raw === "string" && CACHE_BREAKPOINT_STRATEGIES.has(raw)) {
22
+ return raw;
23
+ }
24
+ return "default";
25
+ }
18
26
  /**
19
27
  * Roll cache breakpoints across the conversation tail so the message-history
20
28
  * prefix is written once and re-read on later turns (without this the cached
@@ -27,14 +35,16 @@ function buildAnthropicTools(tools, anchorCache) {
27
35
  * only the incremental `[frozen..tail]`. Otherwise fall back to the rolling
28
36
  * pair: final message + nearest preceding user turn.
29
37
  */
30
- function applyMessageCacheControl(msgs, frozenPrefixLen) {
38
+ function applyMessageCacheControl(msgs, frozenPrefixLen, strategy) {
31
39
  if (!msgs.length)
32
40
  return;
41
+ if (strategy === "tools-only" || strategy === "system-only" || strategy === "none")
42
+ return;
33
43
  const targets = new Set([msgs.length - 1]);
34
44
  if (typeof frozenPrefixLen === "number" && frozenPrefixLen >= 1 && frozenPrefixLen < msgs.length) {
35
45
  targets.add(frozenPrefixLen - 1);
36
46
  }
37
- else {
47
+ else if (strategy === "default") {
38
48
  for (let i = msgs.length - 2; i >= 0 && targets.size < MESSAGE_CACHE_BREAKPOINTS; i--) {
39
49
  if (msgs[i].role === "user")
40
50
  targets.add(i);
@@ -110,16 +120,19 @@ export class AnthropicProvider {
110
120
  return collectStreamMessage(this.stream(context, tools, extensions));
111
121
  }
112
122
  async *stream(context, tools, extensions, _state, signal) {
123
+ const strategy = resolveCacheBreakpointStrategy(extensions);
124
+ const emitOnSystemBlocks = strategy === "default" || strategy === "system-only";
125
+ const cc = { type: "ephemeral" };
113
126
  const systemBlocks = [];
114
127
  if (context.systemStable) {
115
- systemBlocks.push({ type: "text", text: context.systemStable, cache_control: { type: "ephemeral" } });
128
+ systemBlocks.push({ type: "text", text: context.systemStable, ...(emitOnSystemBlocks ? { cache_control: cc } : {}) });
116
129
  }
117
130
  if (context.systemKnowledge) {
118
- systemBlocks.push({ type: "text", text: context.systemKnowledge, cache_control: { type: "ephemeral" } });
131
+ systemBlocks.push({ type: "text", text: context.systemKnowledge, ...(emitOnSystemBlocks ? { cache_control: cc } : {}) });
119
132
  }
120
133
  const system = systemBlocks.length ? systemBlocks : (context.systemText || undefined);
121
134
  const msgs = toAnthropicMessages(context, message => this.nativeAssistantBlocks.get(assistantReplayKey(message)));
122
- applyMessageCacheControl(msgs, context.frozenPrefixLen);
135
+ applyMessageCacheControl(msgs, context.frozenPrefixLen, strategy);
123
136
  // Append the volatile State turn AFTER the cache breakpoints (uncached tail);
124
137
  // absent on un-rebuilt bindings, where the state is already inside `turns`.
125
138
  // Render through toAnthropicMessages so assistant tool_use blocks are
@@ -136,7 +149,7 @@ export class AnthropicProvider {
136
149
  messages: msgs,
137
150
  stream: true,
138
151
  ...(system ? { system } : {}),
139
- ...(tools.length ? { tools: buildAnthropicTools(tools, !Array.isArray(system)) } : {}),
152
+ ...(tools.length ? { tools: buildAnthropicTools(tools, !Array.isArray(system), strategy) } : {}),
140
153
  };
141
154
  if (extensions?.enable_thinking) {
142
155
  body.thinking = { type: "enabled", budget_tokens: 8000 };
package/dist/types.d.ts CHANGED
@@ -144,6 +144,13 @@ export interface ToolArgumentRepairedEvent extends StreamEvent {
144
144
  */
145
145
  export type ProviderRunState = Record<string, unknown>;
146
146
  export type ProviderProtocol = "anthropic-messages" | "openai-chat" | "openai-responses" | "gemini";
147
+ /**
148
+ * Cache_control placement strategy for the Anthropic protocol. Pass via
149
+ * `extensions.cacheBreakpointStrategy` on any provider call (the runner threads
150
+ * `RuntimeOptions.extensions` through automatically). See the Node SDK's
151
+ * `CacheBreakpointStrategy` for the canonical documentation; this is the WASM mirror.
152
+ */
153
+ export type CacheBreakpointStrategy = "default" | "tools-only" | "system-only" | "frozen-prefix" | "none";
147
154
  export interface ProviderDescriptor {
148
155
  provider: string;
149
156
  protocol: ProviderProtocol;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deepstrike/wasm",
3
- "version": "0.2.20",
3
+ "version": "0.2.22",
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.2.20"
18
+ "@deepstrike/wasm-kernel": "0.2.22"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/jest": "^30.0.0",