@deepstrike/sdk 0.2.52 → 0.2.60

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.
Files changed (148) hide show
  1. package/README.md +28 -28
  2. package/dist/agent-ir.d.ts +103 -0
  3. package/dist/agent-ir.js +134 -0
  4. package/dist/agent.d.ts +67 -0
  5. package/dist/agent.js +36 -0
  6. package/dist/collaboration/harness.js +1 -1
  7. package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
  8. package/dist/collaboration/modes/creator-verifier.js +4 -6
  9. package/dist/collaboration/pool.d.ts +8 -20
  10. package/dist/collaboration/pool.js +27 -97
  11. package/dist/compat/anthropic/mcp.d.ts +15 -0
  12. package/dist/compat/anthropic/mcp.js +10 -0
  13. package/dist/compat/openai/agent.d.ts +34 -0
  14. package/dist/compat/openai/agent.js +24 -0
  15. package/dist/governance.d.ts +1 -17
  16. package/dist/governance.js +1 -34
  17. package/dist/guardrail.d.ts +6 -0
  18. package/dist/guardrail.js +1 -0
  19. package/dist/handoff-target.d.ts +12 -0
  20. package/dist/handoff-target.js +1 -0
  21. package/dist/harness/manifest.js +0 -4
  22. package/dist/index.d.ts +19 -7
  23. package/dist/index.js +8 -5
  24. package/dist/kernel.d.ts +2 -20
  25. package/dist/knowledge/public.d.ts +29 -0
  26. package/dist/knowledge/public.js +1 -0
  27. package/dist/mcp-server.d.ts +28 -0
  28. package/dist/mcp-server.js +1 -0
  29. package/dist/memory/agent.d.ts +2 -2
  30. package/dist/memory/agent.js +2 -2
  31. package/dist/memory/durable.d.ts +16 -0
  32. package/dist/memory/durable.js +46 -0
  33. package/dist/memory/in-memory-store.d.ts +9 -7
  34. package/dist/memory/in-memory-store.js +8 -2
  35. package/dist/memory/protocols.d.ts +22 -4
  36. package/dist/memory/public.d.ts +4 -3
  37. package/dist/memory/public.js +3 -2
  38. package/dist/providers/anthropic-adapter.d.ts +47 -0
  39. package/dist/providers/anthropic-adapter.js +444 -0
  40. package/dist/providers/anthropic-compatible.d.ts +2 -3
  41. package/dist/providers/anthropic-compatible.js +8 -5
  42. package/dist/providers/anthropic.d.ts +19 -23
  43. package/dist/providers/anthropic.js +169 -395
  44. package/dist/providers/base.js +43 -3
  45. package/dist/providers/capability-router.d.ts +29 -0
  46. package/dist/providers/capability-router.js +43 -0
  47. package/dist/providers/catalog.d.ts +16 -4
  48. package/dist/providers/catalog.js +112 -21
  49. package/dist/providers/content-normalization.d.ts +57 -0
  50. package/dist/providers/content-normalization.js +238 -0
  51. package/dist/providers/content-policy.d.ts +16 -0
  52. package/dist/providers/content-policy.js +39 -0
  53. package/dist/providers/credentials.d.ts +83 -0
  54. package/dist/providers/credentials.js +190 -0
  55. package/dist/providers/endpoints.d.ts +137 -0
  56. package/dist/providers/endpoints.js +128 -0
  57. package/dist/providers/factories.js +9 -3
  58. package/dist/providers/gemini-adapter.d.ts +33 -0
  59. package/dist/providers/gemini-adapter.js +272 -0
  60. package/dist/providers/gemini.d.ts +16 -3
  61. package/dist/providers/gemini.js +97 -195
  62. package/dist/providers/model-catalog.d.ts +37 -0
  63. package/dist/providers/model-catalog.js +62 -0
  64. package/dist/providers/model-registry.d.ts +98 -0
  65. package/dist/providers/model-registry.js +315 -0
  66. package/dist/providers/ollama-adapter.d.ts +65 -0
  67. package/dist/providers/ollama-adapter.js +188 -0
  68. package/dist/providers/ollama.d.ts +9 -4
  69. package/dist/providers/ollama.js +96 -109
  70. package/dist/providers/openai-chat-dialects.d.ts +154 -0
  71. package/dist/providers/openai-chat-dialects.js +179 -0
  72. package/dist/providers/openai-chat.d.ts +46 -18
  73. package/dist/providers/openai-chat.js +418 -51
  74. package/dist/providers/openai-responses-adapter.d.ts +42 -0
  75. package/dist/providers/openai-responses-adapter.js +341 -0
  76. package/dist/providers/openai-responses.d.ts +14 -33
  77. package/dist/providers/openai-responses.js +131 -264
  78. package/dist/providers/openai.d.ts +29 -76
  79. package/dist/providers/openai.js +195 -292
  80. package/dist/providers/protocol-adapter.d.ts +34 -0
  81. package/dist/providers/protocol-adapter.js +9 -0
  82. package/dist/providers/protocol-capabilities.d.ts +34 -0
  83. package/dist/providers/protocol-capabilities.js +44 -0
  84. package/dist/providers/provider-error.d.ts +31 -0
  85. package/dist/providers/provider-error.js +149 -0
  86. package/dist/providers/public.d.ts +26 -3
  87. package/dist/providers/public.js +13 -1
  88. package/dist/providers/registry.d.ts +7 -6
  89. package/dist/providers/registry.js +47 -20
  90. package/dist/providers/request-plan.d.ts +86 -0
  91. package/dist/providers/request-plan.js +175 -0
  92. package/dist/providers/usage-normalizer.d.ts +48 -0
  93. package/dist/providers/usage-normalizer.js +96 -0
  94. package/dist/providers/vendor-profiles.d.ts +2 -15
  95. package/dist/providers/vendor-profiles.js +14 -60
  96. package/dist/runtime/canonical-kernel-step.d.ts +1 -2
  97. package/dist/runtime/canonical-kernel-step.js +47 -12
  98. package/dist/runtime/context-policy.d.ts +10 -12
  99. package/dist/runtime/context-policy.js +6 -8
  100. package/dist/runtime/durable-content.d.ts +50 -0
  101. package/dist/runtime/durable-content.js +159 -0
  102. package/dist/runtime/execution-plane.d.ts +2 -2
  103. package/dist/runtime/execution-plane.js +2 -2
  104. package/dist/runtime/kernel-event-log.js +0 -1
  105. package/dist/runtime/kernel-step.d.ts +0 -1
  106. package/dist/runtime/kernel-step.js +4 -2
  107. package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
  108. package/dist/runtime/mcp-proxy-plane.js +44 -6
  109. package/dist/runtime/output-schema.d.ts +1 -2
  110. package/dist/runtime/provider-replay.d.ts +1 -1
  111. package/dist/runtime/provider-replay.js +12 -27
  112. package/dist/runtime/reactive-session.d.ts +1 -1
  113. package/dist/runtime/reactive-session.js +2 -3
  114. package/dist/runtime/run-group.d.ts +1 -1
  115. package/dist/runtime/runner.d.ts +26 -40
  116. package/dist/runtime/runner.js +145 -63
  117. package/dist/runtime/session-log.d.ts +8 -1
  118. package/dist/runtime/session-log.js +42 -2
  119. package/dist/runtime/session-repair.d.ts +1 -1
  120. package/dist/runtime/session-repair.js +1 -1
  121. package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
  122. package/dist/runtime/sub-agent-orchestrator.js +8 -11
  123. package/dist/runtime/workflow-control-flow.d.ts +0 -4
  124. package/dist/runtime/workflow-control-flow.js +0 -16
  125. package/dist/session.d.ts +11 -0
  126. package/dist/session.js +1 -0
  127. package/dist/skill.d.ts +17 -0
  128. package/dist/skill.js +16 -0
  129. package/dist/skills/loader.d.ts +3 -0
  130. package/dist/tools/errors.d.ts +1 -3
  131. package/dist/tools/errors.js +1 -3
  132. package/dist/tools/index.d.ts +3 -0
  133. package/dist/types/agent.d.ts +21 -9
  134. package/dist/types/agent.js +30 -4
  135. package/dist/types.d.ts +128 -13
  136. package/package.json +3 -3
  137. package/dist/providers/deepseek.d.ts +0 -46
  138. package/dist/providers/deepseek.js +0 -97
  139. package/dist/providers/glm.d.ts +0 -25
  140. package/dist/providers/glm.js +0 -48
  141. package/dist/providers/kimi.d.ts +0 -23
  142. package/dist/providers/kimi.js +0 -30
  143. package/dist/providers/minimax.d.ts +0 -49
  144. package/dist/providers/minimax.js +0 -98
  145. package/dist/providers/profiles.d.ts +0 -1992
  146. package/dist/providers/profiles.js +0 -796
  147. package/dist/providers/qwen.d.ts +0 -38
  148. package/dist/providers/qwen.js +0 -97
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Binds the host storage protocol to the public Memory contract for one agent and namespace.
3
+ * This is deliberately an SDK adapter: it does not lower memory mutations into the Kernel.
4
+ */
5
+ export class DurableMemory {
6
+ store;
7
+ agentId;
8
+ scope;
9
+ namespace;
10
+ constructor(store, agentId, scope) {
11
+ this.store = store;
12
+ this.agentId = agentId;
13
+ this.scope = scope;
14
+ this.namespace = scope.namespace;
15
+ }
16
+ async search(query, options = {}) {
17
+ const request = {
18
+ scope: this.scope,
19
+ query,
20
+ top_k: options.topK ?? 5,
21
+ kinds: options.kinds ?? [],
22
+ ...(options.minScore === undefined ? {} : { min_score: options.minScore }),
23
+ };
24
+ return (await this.store.search(this.agentId, request))
25
+ .map(hit => hit.record)
26
+ .filter(record => sameScope(record.scope, this.scope));
27
+ }
28
+ async get(id) {
29
+ const record = await this.store.get(this.agentId, id);
30
+ return record !== null && sameScope(record.scope, this.scope) ? record : null;
31
+ }
32
+ async put(record) {
33
+ if (!sameScope(record.scope, this.scope)) {
34
+ throw new Error("memory record scope must match the bound Memory scope");
35
+ }
36
+ await this.store.put(this.agentId, record);
37
+ }
38
+ async delete(id) {
39
+ const record = await this.get(id);
40
+ if (record !== null)
41
+ await this.store.delete(this.agentId, id);
42
+ }
43
+ }
44
+ function sameScope(left, right) {
45
+ return left.tenant_id === right.tenant_id && left.namespace === right.namespace;
46
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
- * `InMemoryDreamStore` — a lightweight `DreamStore` implementation backed by per-agent `Map`s.
2
+ * `InMemoryMemoryStore` — a lightweight `MemoryStore` implementation backed by per-agent `Map`s.
3
3
  *
4
- * Originally lived as `MockDreamStore` in the SDK's test helpers; promoted here so benchmarks,
4
+ * Originally lived as `MockMemoryStore` in the SDK's test helpers; promoted here so benchmarks,
5
5
  * examples, and downstream consumers can use it without copying the boilerplate.
6
6
  *
7
7
  * Use cases:
@@ -14,8 +14,8 @@
14
14
  * the full record set, so it (M3) bounds itself by value-ordered retention eviction and (M3/M4)
15
15
  * mirrors recall lifecycle and pin state. For semantic search, plug in a real store.
16
16
  */
17
- import type { DreamStore, MemoryQuery, MemoryRecall, MemoryRecallLifecycle, MemoryRecord, SessionData } from "./protocols.js";
18
- export interface InMemoryDreamStoreOptions {
17
+ import type { MemoryStore, MemoryQuery, MemoryRecall, MemoryRecallLifecycle, MemoryRecord, SessionData } from "./protocols.js";
18
+ export interface InMemoryMemoryStoreOptions {
19
19
  /** Cap the per-agent record set; a write past it evicts the lowest-value unpinned records (M3). */
20
20
  maxRecords?: number;
21
21
  /** Age (days) past which a record's recall relevance is discounted. Default 2. */
@@ -23,7 +23,7 @@ export interface InMemoryDreamStoreOptions {
23
23
  /** Wall-clock source for staleness scoring + recall stamps. Injectable for deterministic tests. */
24
24
  now?: () => number;
25
25
  }
26
- export declare class InMemoryDreamStore implements DreamStore {
26
+ export declare class InMemoryMemoryStore implements MemoryStore {
27
27
  private readonly initialMemories;
28
28
  private memories;
29
29
  /** Sessions persisted via `saveSession`; exposed for test assertions. */
@@ -35,9 +35,11 @@ export declare class InMemoryDreamStore implements DreamStore {
35
35
  * @param initialMemories Optional seed memories applied to every agent that asks for memories
36
36
  * for the first time. Useful for benchmark scenarios that preload a fact.
37
37
  */
38
- constructor(initialMemories?: MemoryRecord[], options?: InMemoryDreamStoreOptions);
38
+ constructor(initialMemories?: MemoryRecord[], options?: InMemoryMemoryStoreOptions);
39
39
  private recordsFor;
40
- upsert(agentId: string, incoming: MemoryRecord): Promise<void>;
40
+ put(agentId: string, incoming: MemoryRecord): Promise<void>;
41
+ get(agentId: string, recordId: string): Promise<MemoryRecord | null>;
42
+ delete(agentId: string, recordId: string): Promise<void>;
41
43
  /** M3: value-ordered retention eviction. Sheds the lowest-value unpinned records — the shared
42
44
  * deterministic formula, never a blind tail-cut — until the set fits `maxRecords`. */
43
45
  private evictToCapacity;
@@ -1,6 +1,6 @@
1
1
  import { rankMemories } from "./ranking.js";
2
2
  import { memoryRetentionScore } from "./retention.js";
3
- export class InMemoryDreamStore {
3
+ export class InMemoryMemoryStore {
4
4
  initialMemories;
5
5
  memories = new Map();
6
6
  /** Sessions persisted via `saveSession`; exposed for test assertions. */
@@ -27,7 +27,7 @@ export class InMemoryDreamStore {
27
27
  }
28
28
  return [];
29
29
  }
30
- async upsert(agentId, incoming) {
30
+ async put(agentId, incoming) {
31
31
  const kept = [...this.recordsFor(agentId)];
32
32
  const index = kept.findIndex(record => record.scope.tenant_id === incoming.scope.tenant_id
33
33
  && record.scope.namespace === incoming.scope.namespace
@@ -39,6 +39,12 @@ export class InMemoryDreamStore {
39
39
  kept.push(incoming);
40
40
  this.memories.set(agentId, this.evictToCapacity(kept));
41
41
  }
42
+ async get(agentId, recordId) {
43
+ return this.recordsFor(agentId).find(record => record.record_id === recordId) ?? null;
44
+ }
45
+ async delete(agentId, recordId) {
46
+ this.memories.set(agentId, this.recordsFor(agentId).filter(record => record.record_id !== recordId));
47
+ }
42
48
  /** M3: value-ordered retention eviction. Sheds the lowest-value unpinned records — the shared
43
49
  * deterministic formula, never a blind tail-cut — until the set fits `maxRecords`. */
44
50
  evictToCapacity(records) {
@@ -60,10 +60,28 @@ export interface MemoryRecallLifecycle {
60
60
  recall_count: number;
61
61
  last_recalled_at: number;
62
62
  }
63
- export interface DreamStore {
64
- /** The only durable memory mutation. Callers must reach this through the kernel WriteMemory gate. */
65
- upsert(agentId: string, record: MemoryRecord): Promise<void>;
66
- /** Semantic search over the agent's long-term memories. Called on demand during a run. */
63
+ /** Search options for the public, agent-bound durable `Memory` descriptor. */
64
+ export interface MemorySearchOptions {
65
+ topK?: number;
66
+ kinds?: MemoryKind[];
67
+ minScore?: number;
68
+ }
69
+ /**
70
+ * Public durable memory descriptor bound to one agent and scope. It intentionally returns records,
71
+ * not ranking internals, and is distinct from `WorkingMemory`, the SDK-only scratch pad.
72
+ */
73
+ export interface Memory {
74
+ readonly namespace?: string;
75
+ search(query: string, options?: MemorySearchOptions): Promise<MemoryRecord[]>;
76
+ get(id: string): Promise<MemoryRecord | null>;
77
+ put(record: MemoryRecord): Promise<void>;
78
+ delete(id: string): Promise<void>;
79
+ }
80
+ /** Host-owned durable storage behind an agent-bound public `Memory` descriptor. */
81
+ export interface MemoryStore {
82
+ put(agentId: string, record: MemoryRecord): Promise<void>;
83
+ get(agentId: string, recordId: string): Promise<MemoryRecord | null>;
84
+ delete(agentId: string, recordId: string): Promise<void>;
67
85
  search(agentId: string, query: MemoryQuery): Promise<MemoryRecall[]>;
68
86
  /** Persist the completed session before the runner performs its one extraction pass. */
69
87
  saveSession(data: SessionData): Promise<void>;
@@ -1,9 +1,10 @@
1
1
  export { WorkingMemory } from "./working.js";
2
- export { InMemoryDreamStore } from "./in-memory-store.js";
3
- export type { InMemoryDreamStoreOptions } from "./in-memory-store.js";
2
+ export { DurableMemory } from "./durable.js";
3
+ export { InMemoryMemoryStore } from "./in-memory-store.js";
4
+ export type { InMemoryMemoryStoreOptions } from "./in-memory-store.js";
4
5
  export { memoryRetentionScore } from "./retention.js";
5
6
  export { rankMemories } from "./ranking.js";
6
7
  export type { RankableMemory, RankedMemory, RankOptions } from "./ranking.js";
7
8
  export { extractSessionMemories, parseExtractedMemories } from "./extraction.js";
8
- export type { DreamStore, SessionData, SessionMessage, MemoryRecord, MemoryRecall, MemoryQuery, MemoryScope, MemoryProvenance, MemoryRecallLifecycle, MemoryKind, MemoryAuthor, MemoryTrustLevel, } from "./protocols.js";
9
+ export type { MemoryStore, Memory, MemorySearchOptions, SessionData, SessionMessage, MemoryRecord, MemoryRecall, MemoryQuery, MemoryScope, MemoryProvenance, MemoryRecallLifecycle, MemoryKind, MemoryAuthor, MemoryTrustLevel, } from "./protocols.js";
9
10
  export type { KnowledgeSource } from "../knowledge/source.js";
@@ -1,6 +1,7 @@
1
- // `@deepstrike/sdk/memory` — long-term (dream) and working memory, plus the knowledge-source interface.
1
+ // `@deepstrike/sdk/memory` — durable and working memory, plus the knowledge-source interface.
2
2
  export { WorkingMemory } from "./working.js";
3
- export { InMemoryDreamStore } from "./in-memory-store.js";
3
+ export { DurableMemory } from "./durable.js";
4
+ export { InMemoryMemoryStore } from "./in-memory-store.js";
4
5
  export { memoryRetentionScore } from "./retention.js";
5
6
  export { rankMemories } from "./ranking.js";
6
7
  export { extractSessionMemories, parseExtractedMemories } from "./extraction.js";
@@ -0,0 +1,47 @@
1
+ import type { Message, ProviderReplay, ProviderUsage, ToolCall } from "../types.js";
2
+ import type { CanonicalAdapterInput } from "./content-normalization.js";
3
+ import { type AdapterDecodeInput, type AdapterOutput, type AdapterStreamInput, type CanonicalStopReason, type ProtocolAdapter } from "./protocol-adapter.js";
4
+ export interface AnthropicRequestPlan {
5
+ transport: "stable" | "beta";
6
+ params: Record<string, unknown>;
7
+ cacheSlots: {
8
+ system: boolean;
9
+ tools: boolean;
10
+ messages: boolean;
11
+ };
12
+ }
13
+ export type AnthropicStreamChunk = Record<string, any>;
14
+ export interface AnthropicStreamState {
15
+ readonly input: CanonicalAdapterInput;
16
+ readonly cacheSlots: {
17
+ system: boolean;
18
+ tools: boolean;
19
+ messages: boolean;
20
+ };
21
+ readonly toolBlocks: Record<number, {
22
+ id: string;
23
+ name: string;
24
+ argsBuffer: string;
25
+ }>;
26
+ readonly nativeBlocks: Record<number, Record<string, unknown>>;
27
+ readonly finalToolCalls: ToolCall[];
28
+ finalText: string;
29
+ uncachedInput: number;
30
+ cacheReadTokens: number;
31
+ cacheCreationTokens: number;
32
+ outputTokens: number;
33
+ }
34
+ export declare class AnthropicMessagesAdapter implements ProtocolAdapter<AnthropicRequestPlan, Record<string, any>, AnthropicStreamChunk, AnthropicStreamState, undefined> {
35
+ readonly protocol: "anthropic-messages";
36
+ readonly protocolCapabilities: import("./protocol-capabilities.js").ProtocolRuntimeCapabilities;
37
+ buildRequest(input: CanonicalAdapterInput): AnthropicRequestPlan;
38
+ decodeComplete(raw: Record<string, any>, _input: AdapterDecodeInput): {
39
+ message: Message;
40
+ replay?: ProviderReplay;
41
+ };
42
+ createStreamState(input: AdapterStreamInput): AnthropicStreamState;
43
+ pushStreamChunk(chunk: AnthropicStreamChunk, state: AnthropicStreamState): AdapterOutput;
44
+ finishStream(state: AnthropicStreamState): AdapterOutput;
45
+ normalizeUsage(raw: unknown): ProviderUsage | undefined;
46
+ normalizeStopReason(raw: string | undefined): CanonicalStopReason | undefined;
47
+ }
@@ -0,0 +1,444 @@
1
+ import { normalizeToolCall } from "./base.js";
2
+ import { ProtocolResponseError, } from "./protocol-adapter.js";
3
+ import { ANTHROPIC_PROTOCOL_CAPABILITIES } from "./protocol-capabilities.js";
4
+ const CACHE_BREAKPOINT_STRATEGIES = new Set([
5
+ "default", "tools-only", "system-only", "frozen-prefix", "none",
6
+ ]);
7
+ function cacheStrategy(extensions) {
8
+ const raw = extensions.cacheBreakpointStrategy;
9
+ return typeof raw === "string" && CACHE_BREAKPOINT_STRATEGIES.has(raw)
10
+ ? raw
11
+ : "default";
12
+ }
13
+ function extensionsForWire(extensions) {
14
+ const blocked = new Set([
15
+ "model", "messages", "system", "tools", "max_tokens", "stream",
16
+ "__deepstrikeThinkingEnabled", "degradeMissingReasoningReplay",
17
+ ]);
18
+ return Object.fromEntries(Object.entries(extensions).filter(([key]) => !blocked.has(key)));
19
+ }
20
+ function systemBlocks(context, strategy) {
21
+ if (!context.systemStable && !context.systemKnowledge) {
22
+ return context.systemText || undefined;
23
+ }
24
+ const cache = strategy === "default" || strategy === "system-only";
25
+ const blocks = [];
26
+ if (context.systemStable) {
27
+ blocks.push({
28
+ type: "text",
29
+ text: context.systemStable,
30
+ ...(cache ? { cache_control: { type: "ephemeral" } } : {}),
31
+ });
32
+ }
33
+ if (context.systemKnowledge) {
34
+ blocks.push({
35
+ type: "text",
36
+ text: context.systemKnowledge,
37
+ ...(cache ? { cache_control: { type: "ephemeral" } } : {}),
38
+ });
39
+ }
40
+ return blocks.length ? blocks : undefined;
41
+ }
42
+ function toolResult(result) {
43
+ const blocks = result.blocks;
44
+ const native = blocks.map(block => {
45
+ if (block.type === "text")
46
+ return { type: "text", text: block.text };
47
+ if (block.type === "image") {
48
+ if (block.source.kind === "base64") {
49
+ return {
50
+ type: "image",
51
+ source: {
52
+ type: "base64",
53
+ media_type: block.mediaType ?? "image/png",
54
+ data: block.source.data,
55
+ },
56
+ };
57
+ }
58
+ if (block.source.kind === "url") {
59
+ return { type: "image", source: { type: "url", url: block.source.url } };
60
+ }
61
+ }
62
+ return { type: "text", text: `[${block.type}]` };
63
+ });
64
+ return {
65
+ type: "tool_result",
66
+ tool_use_id: result.callId,
67
+ content: result.contentForm !== "blocks" && blocks.length === 1 && blocks[0].type === "text"
68
+ ? blocks[0].text
69
+ : native,
70
+ is_error: result.isError,
71
+ };
72
+ }
73
+ function canonicalMessage(message) {
74
+ if (message.role === "assistant"
75
+ && message.toolCalls?.length
76
+ && message.providerReplay?.native_blocks?.length) {
77
+ return { role: "assistant", content: ensureAssistantToolText(message.providerReplay.native_blocks) };
78
+ }
79
+ const content = [];
80
+ for (const item of message.blocks) {
81
+ if (item.type === "tool_result") {
82
+ content.push(toolResult(item));
83
+ }
84
+ else if (item.type === "text") {
85
+ if (item.text)
86
+ content.push({ type: "text", text: item.text });
87
+ }
88
+ else if (item.type === "image") {
89
+ if (item.source.kind === "base64") {
90
+ content.push({
91
+ type: "image",
92
+ source: {
93
+ type: "base64",
94
+ media_type: item.mediaType ?? "image/png",
95
+ data: item.source.data,
96
+ },
97
+ });
98
+ }
99
+ else if (item.source.kind === "url") {
100
+ content.push({ type: "image", source: { type: "url", url: item.source.url } });
101
+ }
102
+ }
103
+ }
104
+ if (message.role === "assistant" && message.toolCalls?.length) {
105
+ if (!content.length)
106
+ content.push({ type: "text", text: "Tool call requested." });
107
+ for (const call of message.toolCalls) {
108
+ let args = {};
109
+ try {
110
+ args = JSON.parse(call.arguments);
111
+ }
112
+ catch {
113
+ args = {};
114
+ }
115
+ content.push({ type: "tool_use", id: call.id, name: call.name, input: args });
116
+ }
117
+ }
118
+ if (message.role === "tool" && !content.some(block => block.type === "tool_result")) {
119
+ return undefined;
120
+ }
121
+ return {
122
+ role: message.role === "tool" ? "user" : message.role,
123
+ content: message.contentForm !== "blocks" && content.length === 1 && content[0].type === "text"
124
+ ? content[0].text
125
+ : content,
126
+ };
127
+ }
128
+ function ensureAssistantToolText(blocks) {
129
+ if (!blocks.some(block => block.type === "tool_use"))
130
+ return blocks;
131
+ if (blocks.some(block => block.type === "text" && String(block.text ?? "").trim()))
132
+ return blocks;
133
+ if (blocks.some(block => block.type === "thinking"))
134
+ return blocks;
135
+ return [{ type: "text", text: "Tool call requested." }, ...blocks];
136
+ }
137
+ function markLastBlockCacheable(message) {
138
+ const cache_control = { type: "ephemeral" };
139
+ if (typeof message.content === "string") {
140
+ if (message.content) {
141
+ message.content = [{ type: "text", text: message.content, cache_control }];
142
+ }
143
+ return;
144
+ }
145
+ if (Array.isArray(message.content) && message.content.length) {
146
+ const last = message.content.at(-1);
147
+ last.cache_control = cache_control;
148
+ }
149
+ }
150
+ function applyMessageCacheControl(messages, frozenPrefixLen, strategy) {
151
+ if (!messages.length || ["tools-only", "system-only", "none"].includes(strategy))
152
+ return;
153
+ const targets = new Set([messages.length - 1]);
154
+ if (typeof frozenPrefixLen === "number" && frozenPrefixLen >= 1 && frozenPrefixLen < messages.length) {
155
+ targets.add(frozenPrefixLen - 1);
156
+ }
157
+ else if (strategy === "default") {
158
+ for (let index = messages.length - 2; index >= 0 && targets.size < 2; index--) {
159
+ if (messages[index].role === "user")
160
+ targets.add(index);
161
+ }
162
+ }
163
+ for (const index of targets)
164
+ markLastBlockCacheable(messages[index]);
165
+ }
166
+ function requestTools(input, system, strategy) {
167
+ if (!input.tools.length)
168
+ return undefined;
169
+ const anchor = !Array.isArray(system)
170
+ && (strategy === "default" || strategy === "tools-only");
171
+ return input.tools.map((tool, index) => ({
172
+ name: tool.name,
173
+ description: tool.description,
174
+ input_schema: JSON.parse(tool.parameters),
175
+ ...(anchor && index === input.tools.length - 1
176
+ ? { cache_control: { type: "ephemeral" } }
177
+ : {}),
178
+ }));
179
+ }
180
+ function countSlots(system, tools, messages) {
181
+ return {
182
+ system: Array.isArray(system) && system.some(block => block.cache_control),
183
+ tools: !!tools?.some(tool => tool.cache_control),
184
+ messages: messages.some(message => Array.isArray(message.content)
185
+ && message.content.some(block => block.cache_control)),
186
+ };
187
+ }
188
+ function countCacheBreakpoints(value) {
189
+ if (Array.isArray(value))
190
+ return value.reduce((total, item) => total + countCacheBreakpoints(item), 0);
191
+ if (!value || typeof value !== "object")
192
+ return 0;
193
+ const record = value;
194
+ return (record.cache_control ? 1 : 0)
195
+ + Object.entries(record)
196
+ .filter(([key]) => key !== "cache_control")
197
+ .reduce((total, [, item]) => total + countCacheBreakpoints(item), 0);
198
+ }
199
+ function assertCacheBudget(params) {
200
+ const count = countCacheBreakpoints({
201
+ system: params.system,
202
+ tools: params.tools,
203
+ messages: params.messages,
204
+ });
205
+ if (count > 4) {
206
+ throw new Error(`Anthropic cache_control budget exceeded: ${count} > 4`);
207
+ }
208
+ }
209
+ function estimateCacheRead(cacheRead, slots) {
210
+ if (cacheRead <= 0)
211
+ return undefined;
212
+ const keys = ["system", "tools", "messages"].filter(key => slots[key]);
213
+ if (!keys.length)
214
+ return undefined;
215
+ const share = Math.floor(cacheRead / keys.length);
216
+ const remainder = cacheRead - share * keys.length;
217
+ return Object.fromEntries(keys.map((key, index) => [key, share + (index === 0 ? remainder : 0)]));
218
+ }
219
+ function numeric(raw, field) {
220
+ const value = raw[field];
221
+ if (value === undefined || value === null)
222
+ return undefined;
223
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) {
224
+ throw new ProtocolResponseError("anthropic-messages", `usage.${field} is invalid`);
225
+ }
226
+ return value;
227
+ }
228
+ export class AnthropicMessagesAdapter {
229
+ protocol = "anthropic-messages";
230
+ protocolCapabilities = ANTHROPIC_PROTOCOL_CAPABILITIES;
231
+ buildRequest(input) {
232
+ const strategy = cacheStrategy(input.extensions);
233
+ const system = systemBlocks(input.context, strategy);
234
+ const messages = input.context.turns
235
+ .map(canonicalMessage)
236
+ .filter((message) => message !== undefined);
237
+ applyMessageCacheControl(messages, input.context.frozenPrefixLen, strategy);
238
+ if (input.context.stateTurn) {
239
+ const stateMessage = canonicalMessage(input.context.stateTurn);
240
+ if (stateMessage)
241
+ messages.push(stateMessage);
242
+ }
243
+ if (!messages.length)
244
+ messages.push({ role: "user", content: "Proceed." });
245
+ const tools = requestTools(input, system, strategy);
246
+ const wire = extensionsForWire(input.extensions);
247
+ const betas = Array.isArray(input.extensions.betas) && input.extensions.betas.length
248
+ ? input.extensions.betas
249
+ : undefined;
250
+ const params = {
251
+ ...wire,
252
+ model: input.resolved.identity.modelId,
253
+ max_tokens: typeof input.extensions.max_tokens === "number"
254
+ ? input.extensions.max_tokens
255
+ : 8096,
256
+ ...(system ? { system } : {}),
257
+ messages,
258
+ ...(tools ? { tools } : {}),
259
+ ...(betas ? { betas } : {}),
260
+ };
261
+ assertCacheBudget(params);
262
+ return {
263
+ transport: betas ? "beta" : "stable",
264
+ params,
265
+ cacheSlots: countSlots(system, tools, messages),
266
+ };
267
+ }
268
+ decodeComplete(raw, _input) {
269
+ let content = "";
270
+ const toolCalls = [];
271
+ for (const block of raw.content ?? []) {
272
+ if (block.type === "text")
273
+ content += block.text;
274
+ else if (block.type === "tool_use") {
275
+ const call = normalizeToolCall(block.id, block.name, block.input);
276
+ if (call)
277
+ toolCalls.push(call);
278
+ }
279
+ }
280
+ const usage = this.normalizeUsage(raw.usage);
281
+ const blocks = raw.content;
282
+ return {
283
+ message: {
284
+ role: "assistant",
285
+ content,
286
+ ...(usage ? { tokenCount: usage.outputTokens } : {}),
287
+ toolCalls,
288
+ },
289
+ ...(blocks?.length ? { replay: { protocol: "anthropic-messages", native_blocks: blocks } } : {}),
290
+ };
291
+ }
292
+ createStreamState(input) {
293
+ const plan = this.buildRequest(input.input);
294
+ return {
295
+ input: input.input,
296
+ cacheSlots: plan.cacheSlots,
297
+ toolBlocks: {},
298
+ nativeBlocks: {},
299
+ finalToolCalls: [],
300
+ finalText: "",
301
+ uncachedInput: 0,
302
+ cacheReadTokens: 0,
303
+ cacheCreationTokens: 0,
304
+ outputTokens: 0,
305
+ };
306
+ }
307
+ pushStreamChunk(chunk, state) {
308
+ const events = [];
309
+ if (chunk.type === "message_start" || chunk.type === "message_delta") {
310
+ const raw = chunk.usage ?? chunk.message?.usage;
311
+ if (raw) {
312
+ state.uncachedInput = Math.max(state.uncachedInput, numeric(raw, "input_tokens") ?? 0);
313
+ state.cacheReadTokens = Math.max(state.cacheReadTokens, numeric(raw, "cache_read_input_tokens") ?? 0);
314
+ state.cacheCreationTokens = Math.max(state.cacheCreationTokens, numeric(raw, "cache_creation_input_tokens") ?? 0);
315
+ state.outputTokens = Math.max(state.outputTokens, numeric(raw, "output_tokens") ?? 0);
316
+ const inputTokens = state.uncachedInput + state.cacheReadTokens + state.cacheCreationTokens;
317
+ const providerUsage = {
318
+ inputTokens,
319
+ outputTokens: state.outputTokens,
320
+ ...(state.cacheReadTokens ? { cacheReadInputTokens: state.cacheReadTokens } : {}),
321
+ ...(state.cacheCreationTokens ? { cacheCreationInputTokens: state.cacheCreationTokens } : {}),
322
+ };
323
+ const rawStopReason = chunk.delta?.stop_reason;
324
+ const stopReason = this.normalizeStopReason(rawStopReason);
325
+ const bySlot = estimateCacheRead(state.cacheReadTokens, state.cacheSlots);
326
+ events.push({
327
+ type: "usage",
328
+ totalTokens: inputTokens + state.outputTokens,
329
+ inputTokens,
330
+ outputTokens: state.outputTokens,
331
+ cacheReadInputTokens: state.cacheReadTokens,
332
+ cacheCreationInputTokens: state.cacheCreationTokens,
333
+ ...(bySlot ? { cacheReadInputTokensBySlot: bySlot } : {}),
334
+ ...(stopReason ? { stopReason } : {}),
335
+ ...(rawStopReason ? { rawStopReason } : {}),
336
+ providerUsage,
337
+ });
338
+ }
339
+ }
340
+ else if (chunk.type === "content_block_start") {
341
+ state.nativeBlocks[chunk.index] = { ...chunk.content_block };
342
+ if (chunk.content_block.type === "tool_use") {
343
+ state.toolBlocks[chunk.index] = {
344
+ id: chunk.content_block.id,
345
+ name: chunk.content_block.name,
346
+ argsBuffer: "",
347
+ };
348
+ }
349
+ }
350
+ else if (chunk.type === "content_block_delta") {
351
+ const delta = chunk.delta;
352
+ if (delta.type === "text_delta") {
353
+ state.finalText += delta.text;
354
+ state.nativeBlocks[chunk.index] = {
355
+ ...state.nativeBlocks[chunk.index],
356
+ text: String(state.nativeBlocks[chunk.index]?.text ?? "") + delta.text,
357
+ };
358
+ events.push({ type: "text_delta", delta: delta.text });
359
+ }
360
+ else if (delta.type === "thinking_delta") {
361
+ state.nativeBlocks[chunk.index] = {
362
+ ...state.nativeBlocks[chunk.index],
363
+ thinking: String(state.nativeBlocks[chunk.index]?.thinking ?? "") + delta.thinking,
364
+ };
365
+ events.push({ type: "thinking_delta", delta: delta.thinking });
366
+ }
367
+ else if (delta.type === "signature_delta") {
368
+ state.nativeBlocks[chunk.index] = {
369
+ ...state.nativeBlocks[chunk.index],
370
+ signature: String(state.nativeBlocks[chunk.index]?.signature ?? "") + delta.signature,
371
+ };
372
+ }
373
+ else if (delta.type === "input_json_delta" && state.toolBlocks[chunk.index]) {
374
+ state.toolBlocks[chunk.index].argsBuffer += delta.partial_json;
375
+ }
376
+ }
377
+ else if (chunk.type === "content_block_stop" && state.toolBlocks[chunk.index]) {
378
+ const tool = state.toolBlocks[chunk.index];
379
+ delete state.toolBlocks[chunk.index];
380
+ let args = {};
381
+ try {
382
+ args = JSON.parse(tool.argsBuffer || "{}");
383
+ }
384
+ catch {
385
+ args = {};
386
+ }
387
+ state.nativeBlocks[chunk.index] = { ...state.nativeBlocks[chunk.index], input: args };
388
+ state.finalToolCalls.push({
389
+ id: tool.id,
390
+ name: tool.name,
391
+ arguments: JSON.stringify(args),
392
+ });
393
+ events.push({
394
+ type: "tool_call",
395
+ id: tool.id,
396
+ name: tool.name,
397
+ arguments: args,
398
+ });
399
+ }
400
+ return { events };
401
+ }
402
+ finishStream(state) {
403
+ const blocks = Object.keys(state.nativeBlocks)
404
+ .map(Number)
405
+ .sort((left, right) => left - right)
406
+ .map(index => state.nativeBlocks[index]);
407
+ return {
408
+ events: [],
409
+ ...(blocks.length ? { replay: { protocol: "anthropic-messages", native_blocks: blocks } } : {}),
410
+ };
411
+ }
412
+ normalizeUsage(raw) {
413
+ if (raw === undefined || raw === null)
414
+ return undefined;
415
+ if (typeof raw !== "object" || Array.isArray(raw)) {
416
+ throw new ProtocolResponseError("anthropic-messages", "usage must be an object");
417
+ }
418
+ const record = raw;
419
+ const uncached = numeric(record, "input_tokens");
420
+ const cacheRead = numeric(record, "cache_read_input_tokens");
421
+ const cacheCreation = numeric(record, "cache_creation_input_tokens");
422
+ const output = numeric(record, "output_tokens");
423
+ if (uncached === undefined && cacheRead === undefined
424
+ && cacheCreation === undefined && output === undefined)
425
+ return undefined;
426
+ return {
427
+ inputTokens: (uncached ?? 0) + (cacheRead ?? 0) + (cacheCreation ?? 0),
428
+ outputTokens: output ?? 0,
429
+ ...(cacheRead ? { cacheReadInputTokens: cacheRead } : {}),
430
+ ...(cacheCreation ? { cacheCreationInputTokens: cacheCreation } : {}),
431
+ };
432
+ }
433
+ normalizeStopReason(raw) {
434
+ if (raw === undefined)
435
+ return undefined;
436
+ switch (raw) {
437
+ case "end_turn": return "end_turn";
438
+ case "tool_use": return "tool_use";
439
+ case "max_tokens": return "max_tokens";
440
+ case "stop_sequence": return "stop_sequence";
441
+ default: return "other";
442
+ }
443
+ }
444
+ }