@deepstrike/sdk 0.2.52 → 0.2.61
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 +28 -28
- package/dist/agent-ir.d.ts +103 -0
- package/dist/agent-ir.js +134 -0
- package/dist/agent.d.ts +67 -0
- package/dist/agent.js +36 -0
- package/dist/collaboration/harness.js +1 -1
- package/dist/collaboration/modes/creator-verifier.d.ts +2 -7
- package/dist/collaboration/modes/creator-verifier.js +4 -6
- package/dist/collaboration/pool.d.ts +8 -20
- package/dist/collaboration/pool.js +27 -97
- package/dist/compat/anthropic/mcp.d.ts +15 -0
- package/dist/compat/anthropic/mcp.js +10 -0
- package/dist/compat/openai/agent.d.ts +34 -0
- package/dist/compat/openai/agent.js +24 -0
- package/dist/governance.d.ts +1 -17
- package/dist/governance.js +1 -34
- package/dist/guardrail.d.ts +6 -0
- package/dist/guardrail.js +1 -0
- package/dist/handoff-target.d.ts +12 -0
- package/dist/handoff-target.js +1 -0
- package/dist/harness/manifest.js +0 -4
- package/dist/index.d.ts +19 -7
- package/dist/index.js +8 -5
- package/dist/kernel.d.ts +2 -20
- package/dist/knowledge/public.d.ts +29 -0
- package/dist/knowledge/public.js +1 -0
- package/dist/mcp-server.d.ts +28 -0
- package/dist/mcp-server.js +1 -0
- package/dist/memory/agent.d.ts +2 -2
- package/dist/memory/agent.js +2 -2
- package/dist/memory/durable.d.ts +16 -0
- package/dist/memory/durable.js +46 -0
- package/dist/memory/in-memory-store.d.ts +9 -7
- package/dist/memory/in-memory-store.js +8 -2
- package/dist/memory/protocols.d.ts +22 -4
- package/dist/memory/public.d.ts +4 -3
- package/dist/memory/public.js +3 -2
- package/dist/os/public.d.ts +1 -1
- package/dist/os/public.js +1 -1
- package/dist/providers/anthropic-adapter.d.ts +59 -0
- package/dist/providers/anthropic-adapter.js +530 -0
- package/dist/providers/anthropic-compatible.d.ts +2 -3
- package/dist/providers/anthropic-compatible.js +8 -5
- package/dist/providers/anthropic.d.ts +20 -23
- package/dist/providers/anthropic.js +176 -395
- package/dist/providers/base.d.ts +2 -2
- package/dist/providers/base.js +50 -8
- package/dist/providers/capability-router.d.ts +29 -0
- package/dist/providers/capability-router.js +43 -0
- package/dist/providers/catalog.d.ts +16 -4
- package/dist/providers/catalog.js +112 -36
- package/dist/providers/content-normalization.d.ts +57 -0
- package/dist/providers/content-normalization.js +238 -0
- package/dist/providers/content-policy.d.ts +16 -0
- package/dist/providers/content-policy.js +39 -0
- package/dist/providers/credentials.d.ts +83 -0
- package/dist/providers/credentials.js +190 -0
- package/dist/providers/endpoints.d.ts +137 -0
- package/dist/providers/endpoints.js +128 -0
- package/dist/providers/factories.js +25 -9
- package/dist/providers/gemini-adapter.d.ts +33 -0
- package/dist/providers/gemini-adapter.js +264 -0
- package/dist/providers/gemini.d.ts +16 -3
- package/dist/providers/gemini.js +97 -195
- package/dist/providers/model-catalog.d.ts +37 -0
- package/dist/providers/model-catalog.js +62 -0
- package/dist/providers/model-registry.d.ts +119 -0
- package/dist/providers/model-registry.js +379 -0
- package/dist/providers/ollama-adapter.d.ts +65 -0
- package/dist/providers/ollama-adapter.js +188 -0
- package/dist/providers/ollama.d.ts +9 -4
- package/dist/providers/ollama.js +96 -109
- package/dist/providers/openai-chat-dialects.d.ts +154 -0
- package/dist/providers/openai-chat-dialects.js +179 -0
- package/dist/providers/openai-chat.d.ts +46 -18
- package/dist/providers/openai-chat.js +416 -51
- package/dist/providers/openai-responses-adapter.d.ts +42 -0
- package/dist/providers/openai-responses-adapter.js +343 -0
- package/dist/providers/openai-responses.d.ts +19 -33
- package/dist/providers/openai-responses.js +164 -264
- package/dist/providers/openai.d.ts +29 -76
- package/dist/providers/openai.js +195 -292
- package/dist/providers/protocol-adapter.d.ts +39 -0
- package/dist/providers/protocol-adapter.js +13 -0
- package/dist/providers/protocol-capabilities.d.ts +34 -0
- package/dist/providers/protocol-capabilities.js +44 -0
- package/dist/providers/provider-error.d.ts +31 -0
- package/dist/providers/provider-error.js +153 -0
- package/dist/providers/public.d.ts +26 -3
- package/dist/providers/public.js +13 -1
- package/dist/providers/registry.d.ts +7 -6
- package/dist/providers/registry.js +47 -20
- package/dist/providers/request-plan.d.ts +89 -0
- package/dist/providers/request-plan.js +199 -0
- package/dist/providers/usage-normalizer.d.ts +48 -0
- package/dist/providers/usage-normalizer.js +139 -0
- package/dist/providers/vendor-profiles.d.ts +2 -15
- package/dist/providers/vendor-profiles.js +14 -60
- package/dist/runtime/canonical-kernel-step.d.ts +1 -2
- package/dist/runtime/canonical-kernel-step.js +47 -12
- package/dist/runtime/context-policy.d.ts +10 -12
- package/dist/runtime/context-policy.js +6 -8
- package/dist/runtime/durable-content.d.ts +50 -0
- package/dist/runtime/durable-content.js +159 -0
- package/dist/runtime/execution-plane.d.ts +2 -2
- package/dist/runtime/execution-plane.js +2 -2
- package/dist/runtime/kernel-event-log.js +0 -1
- package/dist/runtime/kernel-step.d.ts +0 -1
- package/dist/runtime/kernel-step.js +4 -2
- package/dist/runtime/mcp-proxy-plane.d.ts +25 -1
- package/dist/runtime/mcp-proxy-plane.js +44 -6
- package/dist/runtime/output-schema.d.ts +1 -2
- package/dist/runtime/provider-replay.d.ts +5 -1
- package/dist/runtime/provider-replay.js +26 -27
- package/dist/runtime/reactive-session.d.ts +1 -1
- package/dist/runtime/reactive-session.js +2 -3
- package/dist/runtime/run-group.d.ts +1 -1
- package/dist/runtime/runner.d.ts +31 -45
- package/dist/runtime/runner.js +178 -63
- package/dist/runtime/session-log.d.ts +8 -1
- package/dist/runtime/session-log.js +42 -2
- package/dist/runtime/session-repair.d.ts +1 -1
- package/dist/runtime/session-repair.js +1 -1
- package/dist/runtime/sub-agent-orchestrator.d.ts +1 -1
- package/dist/runtime/sub-agent-orchestrator.js +8 -11
- package/dist/runtime/workflow-control-flow.d.ts +0 -4
- package/dist/runtime/workflow-control-flow.js +0 -16
- package/dist/session.d.ts +11 -0
- package/dist/session.js +1 -0
- package/dist/skill.d.ts +17 -0
- package/dist/skill.js +16 -0
- package/dist/skills/loader.d.ts +3 -0
- package/dist/tools/errors.d.ts +1 -3
- package/dist/tools/errors.js +1 -3
- package/dist/tools/index.d.ts +3 -0
- package/dist/types/agent.d.ts +21 -9
- package/dist/types/agent.js +30 -4
- package/dist/types.d.ts +135 -17
- package/package.json +4 -4
- package/dist/providers/deepseek.d.ts +0 -46
- package/dist/providers/deepseek.js +0 -97
- package/dist/providers/glm.d.ts +0 -25
- package/dist/providers/glm.js +0 -48
- package/dist/providers/kimi.d.ts +0 -23
- package/dist/providers/kimi.js +0 -30
- package/dist/providers/minimax.d.ts +0 -49
- package/dist/providers/minimax.js +0 -98
- package/dist/providers/profiles.d.ts +0 -1992
- package/dist/providers/profiles.js +0 -796
- package/dist/providers/qwen.d.ts +0 -38
- package/dist/providers/qwen.js +0 -97
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import { normalizeToolCall } from "./base.js";
|
|
2
|
+
import { ProtocolResponseError, } from "./protocol-adapter.js";
|
|
3
|
+
import { ANTHROPIC_PROTOCOL_CAPABILITIES } from "./protocol-capabilities.js";
|
|
4
|
+
import { endpointProfiles } from "./endpoints.js";
|
|
5
|
+
export const ANTHROPIC_TEXTUAL_TOOL_CALL_START_MARKER = "<||DSML||tool_calls>";
|
|
6
|
+
const TEXTUAL_TOOL_CALL_CAPTURE_LIMIT = 64 * 1024;
|
|
7
|
+
const CACHE_BREAKPOINT_STRATEGIES = new Set([
|
|
8
|
+
"default", "tools-only", "system-only", "frozen-prefix", "none",
|
|
9
|
+
]);
|
|
10
|
+
function cacheStrategy(extensions) {
|
|
11
|
+
const raw = extensions.cacheBreakpointStrategy;
|
|
12
|
+
return typeof raw === "string" && CACHE_BREAKPOINT_STRATEGIES.has(raw)
|
|
13
|
+
? raw
|
|
14
|
+
: "default";
|
|
15
|
+
}
|
|
16
|
+
function extensionsForWire(extensions) {
|
|
17
|
+
const blocked = new Set([
|
|
18
|
+
"model", "messages", "system", "tools", "max_tokens", "stream",
|
|
19
|
+
"__deepstrikeThinkingEnabled", "degradeMissingReasoningReplay", "textualToolCallPolicy",
|
|
20
|
+
]);
|
|
21
|
+
return Object.fromEntries(Object.entries(extensions).filter(([key]) => !blocked.has(key)));
|
|
22
|
+
}
|
|
23
|
+
function textualToolCallPolicy(input) {
|
|
24
|
+
if (input.tools.length === 0)
|
|
25
|
+
return "off";
|
|
26
|
+
const explicit = input.extensions.textualToolCallPolicy;
|
|
27
|
+
if (explicit === "off" || explicit === "reject")
|
|
28
|
+
return explicit;
|
|
29
|
+
const official = endpointProfiles["anthropic.messages"];
|
|
30
|
+
const endpoint = input.resolved.endpoint;
|
|
31
|
+
const isOfficial = input.resolved.identity.endpointId === official.id
|
|
32
|
+
&& (!endpoint || endpoint.baseURL === official.baseURL);
|
|
33
|
+
return isOfficial ? "off" : "reject";
|
|
34
|
+
}
|
|
35
|
+
function textualToolCallError() {
|
|
36
|
+
return new ProtocolResponseError("anthropic-messages", "Provider emitted a tool call as text instead of a native tool block", { providerCode: "textual_tool_call", retryable: true });
|
|
37
|
+
}
|
|
38
|
+
function hasTextualToolCall(text, input) {
|
|
39
|
+
return textualToolCallPolicy(input) === "reject"
|
|
40
|
+
&& text.includes(ANTHROPIC_TEXTUAL_TOOL_CALL_START_MARKER);
|
|
41
|
+
}
|
|
42
|
+
function markerTailLength(text) {
|
|
43
|
+
const max = Math.min(text.length, ANTHROPIC_TEXTUAL_TOOL_CALL_START_MARKER.length - 1);
|
|
44
|
+
for (let length = max; length > 0; length -= 1) {
|
|
45
|
+
if (text.endsWith(ANTHROPIC_TEXTUAL_TOOL_CALL_START_MARKER.slice(0, length)))
|
|
46
|
+
return length;
|
|
47
|
+
}
|
|
48
|
+
return 0;
|
|
49
|
+
}
|
|
50
|
+
function utf8Length(text) {
|
|
51
|
+
return Buffer.byteLength(text, "utf8");
|
|
52
|
+
}
|
|
53
|
+
function guardTextDelta(text, guard) {
|
|
54
|
+
if (guard.policy === "off")
|
|
55
|
+
return text;
|
|
56
|
+
if (guard.mode === "candidate") {
|
|
57
|
+
guard.capturedLength += utf8Length(text);
|
|
58
|
+
if (guard.capturedLength > TEXTUAL_TOOL_CALL_CAPTURE_LIMIT)
|
|
59
|
+
throw textualToolCallError();
|
|
60
|
+
return "";
|
|
61
|
+
}
|
|
62
|
+
const combined = guard.tail + text;
|
|
63
|
+
const markerIndex = combined.indexOf(ANTHROPIC_TEXTUAL_TOOL_CALL_START_MARKER);
|
|
64
|
+
if (markerIndex >= 0) {
|
|
65
|
+
guard.mode = "candidate";
|
|
66
|
+
guard.tail = "";
|
|
67
|
+
guard.capturedLength = utf8Length(combined.slice(markerIndex));
|
|
68
|
+
if (guard.capturedLength > TEXTUAL_TOOL_CALL_CAPTURE_LIMIT)
|
|
69
|
+
throw textualToolCallError();
|
|
70
|
+
return combined.slice(0, markerIndex);
|
|
71
|
+
}
|
|
72
|
+
const tailLength = markerTailLength(combined);
|
|
73
|
+
guard.tail = tailLength > 0 ? combined.slice(-tailLength) : "";
|
|
74
|
+
return tailLength > 0 ? combined.slice(0, -tailLength) : combined;
|
|
75
|
+
}
|
|
76
|
+
function systemBlocks(context, strategy) {
|
|
77
|
+
if (!context.systemStable && !context.systemKnowledge) {
|
|
78
|
+
return context.systemText || undefined;
|
|
79
|
+
}
|
|
80
|
+
const cache = strategy === "default" || strategy === "system-only";
|
|
81
|
+
const blocks = [];
|
|
82
|
+
if (context.systemStable) {
|
|
83
|
+
blocks.push({
|
|
84
|
+
type: "text",
|
|
85
|
+
text: context.systemStable,
|
|
86
|
+
...(cache ? { cache_control: { type: "ephemeral" } } : {}),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
if (context.systemKnowledge) {
|
|
90
|
+
blocks.push({
|
|
91
|
+
type: "text",
|
|
92
|
+
text: context.systemKnowledge,
|
|
93
|
+
...(cache ? { cache_control: { type: "ephemeral" } } : {}),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return blocks.length ? blocks : undefined;
|
|
97
|
+
}
|
|
98
|
+
function toolResult(result) {
|
|
99
|
+
const blocks = result.blocks;
|
|
100
|
+
const native = blocks.map(block => {
|
|
101
|
+
if (block.type === "text")
|
|
102
|
+
return { type: "text", text: block.text };
|
|
103
|
+
if (block.type === "image") {
|
|
104
|
+
if (block.source.kind === "base64") {
|
|
105
|
+
return {
|
|
106
|
+
type: "image",
|
|
107
|
+
source: {
|
|
108
|
+
type: "base64",
|
|
109
|
+
media_type: block.mediaType ?? "image/png",
|
|
110
|
+
data: block.source.data,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (block.source.kind === "url") {
|
|
115
|
+
return { type: "image", source: { type: "url", url: block.source.url } };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { type: "text", text: `[${block.type}]` };
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
type: "tool_result",
|
|
122
|
+
tool_use_id: result.callId,
|
|
123
|
+
content: result.contentForm !== "blocks" && blocks.length === 1 && blocks[0].type === "text"
|
|
124
|
+
? blocks[0].text
|
|
125
|
+
: native,
|
|
126
|
+
is_error: result.isError,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function canonicalMessage(message) {
|
|
130
|
+
if (message.role === "assistant"
|
|
131
|
+
&& message.toolCalls?.length
|
|
132
|
+
&& message.providerReplay?.native_blocks?.length) {
|
|
133
|
+
return { role: "assistant", content: ensureAssistantToolText(message.providerReplay.native_blocks) };
|
|
134
|
+
}
|
|
135
|
+
const content = [];
|
|
136
|
+
for (const item of message.blocks) {
|
|
137
|
+
if (item.type === "tool_result") {
|
|
138
|
+
content.push(toolResult(item));
|
|
139
|
+
}
|
|
140
|
+
else if (item.type === "text") {
|
|
141
|
+
if (item.text)
|
|
142
|
+
content.push({ type: "text", text: item.text });
|
|
143
|
+
}
|
|
144
|
+
else if (item.type === "image") {
|
|
145
|
+
if (item.source.kind === "base64") {
|
|
146
|
+
content.push({
|
|
147
|
+
type: "image",
|
|
148
|
+
source: {
|
|
149
|
+
type: "base64",
|
|
150
|
+
media_type: item.mediaType ?? "image/png",
|
|
151
|
+
data: item.source.data,
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
else if (item.source.kind === "url") {
|
|
156
|
+
content.push({ type: "image", source: { type: "url", url: item.source.url } });
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
161
|
+
if (!content.length)
|
|
162
|
+
content.push({ type: "text", text: "Tool call requested." });
|
|
163
|
+
for (const call of message.toolCalls) {
|
|
164
|
+
let args = {};
|
|
165
|
+
try {
|
|
166
|
+
args = JSON.parse(call.arguments);
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
args = {};
|
|
170
|
+
}
|
|
171
|
+
content.push({ type: "tool_use", id: call.id, name: call.name, input: args });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (message.role === "tool" && !content.some(block => block.type === "tool_result")) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
role: message.role === "tool" ? "user" : message.role,
|
|
179
|
+
content: message.contentForm !== "blocks" && content.length === 1 && content[0].type === "text"
|
|
180
|
+
? content[0].text
|
|
181
|
+
: content,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function ensureAssistantToolText(blocks) {
|
|
185
|
+
if (!blocks.some(block => block.type === "tool_use"))
|
|
186
|
+
return blocks;
|
|
187
|
+
if (blocks.some(block => block.type === "text" && String(block.text ?? "").trim()))
|
|
188
|
+
return blocks;
|
|
189
|
+
if (blocks.some(block => block.type === "thinking"))
|
|
190
|
+
return blocks;
|
|
191
|
+
return [{ type: "text", text: "Tool call requested." }, ...blocks];
|
|
192
|
+
}
|
|
193
|
+
function markLastBlockCacheable(message) {
|
|
194
|
+
const cache_control = { type: "ephemeral" };
|
|
195
|
+
if (typeof message.content === "string") {
|
|
196
|
+
if (message.content) {
|
|
197
|
+
message.content = [{ type: "text", text: message.content, cache_control }];
|
|
198
|
+
}
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (Array.isArray(message.content) && message.content.length) {
|
|
202
|
+
const last = message.content.at(-1);
|
|
203
|
+
last.cache_control = cache_control;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
function applyMessageCacheControl(messages, frozenPrefixLen, strategy) {
|
|
207
|
+
if (!messages.length || ["tools-only", "system-only", "none"].includes(strategy))
|
|
208
|
+
return;
|
|
209
|
+
const targets = new Set([messages.length - 1]);
|
|
210
|
+
if (typeof frozenPrefixLen === "number" && frozenPrefixLen >= 1 && frozenPrefixLen < messages.length) {
|
|
211
|
+
targets.add(frozenPrefixLen - 1);
|
|
212
|
+
}
|
|
213
|
+
else if (strategy === "default") {
|
|
214
|
+
for (let index = messages.length - 2; index >= 0 && targets.size < 2; index--) {
|
|
215
|
+
if (messages[index].role === "user")
|
|
216
|
+
targets.add(index);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
for (const index of targets)
|
|
220
|
+
markLastBlockCacheable(messages[index]);
|
|
221
|
+
}
|
|
222
|
+
function requestTools(input, system, strategy) {
|
|
223
|
+
if (!input.tools.length)
|
|
224
|
+
return undefined;
|
|
225
|
+
const anchor = !Array.isArray(system)
|
|
226
|
+
&& (strategy === "default" || strategy === "tools-only");
|
|
227
|
+
return input.tools.map((tool, index) => ({
|
|
228
|
+
name: tool.name,
|
|
229
|
+
description: tool.description,
|
|
230
|
+
input_schema: JSON.parse(tool.parameters),
|
|
231
|
+
...(anchor && index === input.tools.length - 1
|
|
232
|
+
? { cache_control: { type: "ephemeral" } }
|
|
233
|
+
: {}),
|
|
234
|
+
}));
|
|
235
|
+
}
|
|
236
|
+
function countSlots(system, tools, messages) {
|
|
237
|
+
return {
|
|
238
|
+
system: Array.isArray(system) && system.some(block => block.cache_control),
|
|
239
|
+
tools: !!tools?.some(tool => tool.cache_control),
|
|
240
|
+
messages: messages.some(message => Array.isArray(message.content)
|
|
241
|
+
&& message.content.some(block => block.cache_control)),
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function countCacheBreakpoints(value) {
|
|
245
|
+
if (Array.isArray(value))
|
|
246
|
+
return value.reduce((total, item) => total + countCacheBreakpoints(item), 0);
|
|
247
|
+
if (!value || typeof value !== "object")
|
|
248
|
+
return 0;
|
|
249
|
+
const record = value;
|
|
250
|
+
return (record.cache_control ? 1 : 0)
|
|
251
|
+
+ Object.entries(record)
|
|
252
|
+
.filter(([key]) => key !== "cache_control")
|
|
253
|
+
.reduce((total, [, item]) => total + countCacheBreakpoints(item), 0);
|
|
254
|
+
}
|
|
255
|
+
function assertCacheBudget(params) {
|
|
256
|
+
const count = countCacheBreakpoints({
|
|
257
|
+
system: params.system,
|
|
258
|
+
tools: params.tools,
|
|
259
|
+
messages: params.messages,
|
|
260
|
+
});
|
|
261
|
+
if (count > 4) {
|
|
262
|
+
throw new Error(`Anthropic cache_control budget exceeded: ${count} > 4`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
function numeric(raw, field) {
|
|
266
|
+
const value = raw[field];
|
|
267
|
+
if (value === undefined || value === null)
|
|
268
|
+
return undefined;
|
|
269
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
270
|
+
throw new ProtocolResponseError("anthropic-messages", `usage.${field} must be a non-negative safe integer`);
|
|
271
|
+
}
|
|
272
|
+
return value;
|
|
273
|
+
}
|
|
274
|
+
export class AnthropicMessagesAdapter {
|
|
275
|
+
protocol = "anthropic-messages";
|
|
276
|
+
protocolCapabilities = ANTHROPIC_PROTOCOL_CAPABILITIES;
|
|
277
|
+
buildRequest(input) {
|
|
278
|
+
const strategy = cacheStrategy(input.extensions);
|
|
279
|
+
const system = systemBlocks(input.context, strategy);
|
|
280
|
+
const messages = input.context.turns
|
|
281
|
+
.map(canonicalMessage)
|
|
282
|
+
.filter((message) => message !== undefined);
|
|
283
|
+
applyMessageCacheControl(messages, input.context.frozenPrefixLen, strategy);
|
|
284
|
+
if (input.context.stateTurn) {
|
|
285
|
+
const stateMessage = canonicalMessage(input.context.stateTurn);
|
|
286
|
+
if (stateMessage)
|
|
287
|
+
messages.push(stateMessage);
|
|
288
|
+
}
|
|
289
|
+
if (!messages.length)
|
|
290
|
+
messages.push({ role: "user", content: "Proceed." });
|
|
291
|
+
const tools = requestTools(input, system, strategy);
|
|
292
|
+
const wire = extensionsForWire(input.extensions);
|
|
293
|
+
const betas = Array.isArray(input.extensions.betas) && input.extensions.betas.length
|
|
294
|
+
? input.extensions.betas
|
|
295
|
+
: undefined;
|
|
296
|
+
const params = {
|
|
297
|
+
...wire,
|
|
298
|
+
model: input.resolved.identity.modelId,
|
|
299
|
+
max_tokens: typeof input.extensions.max_tokens === "number"
|
|
300
|
+
? input.extensions.max_tokens
|
|
301
|
+
: 8096,
|
|
302
|
+
...(system ? { system } : {}),
|
|
303
|
+
messages,
|
|
304
|
+
...(tools ? { tools } : {}),
|
|
305
|
+
...(betas ? { betas } : {}),
|
|
306
|
+
};
|
|
307
|
+
assertCacheBudget(params);
|
|
308
|
+
return {
|
|
309
|
+
transport: betas ? "beta" : "stable",
|
|
310
|
+
params,
|
|
311
|
+
cacheSlots: countSlots(system, tools, messages),
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
decodeComplete(raw, decodeInput) {
|
|
315
|
+
let content = "";
|
|
316
|
+
const toolCalls = [];
|
|
317
|
+
for (const block of raw.content ?? []) {
|
|
318
|
+
if (block.type === "text")
|
|
319
|
+
content += block.text;
|
|
320
|
+
else if (block.type === "tool_use") {
|
|
321
|
+
const call = normalizeToolCall(block.id, block.name, block.input);
|
|
322
|
+
if (call)
|
|
323
|
+
toolCalls.push(call);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (hasTextualToolCall(content, decodeInput.input))
|
|
327
|
+
throw textualToolCallError();
|
|
328
|
+
const usage = this.normalizeUsage(raw.usage);
|
|
329
|
+
const blocks = raw.content;
|
|
330
|
+
return {
|
|
331
|
+
message: {
|
|
332
|
+
role: "assistant",
|
|
333
|
+
content,
|
|
334
|
+
...(usage ? { tokenCount: usage.outputTokens } : {}),
|
|
335
|
+
toolCalls,
|
|
336
|
+
},
|
|
337
|
+
...(blocks?.length ? { replay: { protocol: "anthropic-messages", native_blocks: blocks } } : {}),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
createStreamState(input) {
|
|
341
|
+
const plan = this.buildRequest(input.input);
|
|
342
|
+
return {
|
|
343
|
+
input: input.input,
|
|
344
|
+
cacheSlots: plan.cacheSlots,
|
|
345
|
+
toolBlocks: {},
|
|
346
|
+
nativeBlocks: {},
|
|
347
|
+
finalToolCalls: [],
|
|
348
|
+
textualToolCallGuard: {
|
|
349
|
+
policy: textualToolCallPolicy(input.input),
|
|
350
|
+
mode: "passthrough",
|
|
351
|
+
tail: "",
|
|
352
|
+
capturedLength: 0,
|
|
353
|
+
sawNativeToolCall: false,
|
|
354
|
+
},
|
|
355
|
+
finalText: "",
|
|
356
|
+
uncachedInput: 0,
|
|
357
|
+
cacheReadTokens: 0,
|
|
358
|
+
cacheCreationTokens: 0,
|
|
359
|
+
cacheTelemetryMeasured: false,
|
|
360
|
+
outputTokens: 0,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
pushStreamChunk(chunk, state) {
|
|
364
|
+
const events = [];
|
|
365
|
+
if (chunk.type === "message_start" || chunk.type === "message_delta") {
|
|
366
|
+
const raw = chunk.usage ?? chunk.message?.usage;
|
|
367
|
+
if (raw) {
|
|
368
|
+
if (Object.prototype.hasOwnProperty.call(raw, "cache_read_input_tokens")
|
|
369
|
+
|| Object.prototype.hasOwnProperty.call(raw, "cache_creation_input_tokens")) {
|
|
370
|
+
state.cacheTelemetryMeasured = true;
|
|
371
|
+
}
|
|
372
|
+
state.uncachedInput = Math.max(state.uncachedInput, numeric(raw, "input_tokens") ?? 0);
|
|
373
|
+
state.cacheReadTokens = Math.max(state.cacheReadTokens, numeric(raw, "cache_read_input_tokens") ?? 0);
|
|
374
|
+
state.cacheCreationTokens = Math.max(state.cacheCreationTokens, numeric(raw, "cache_creation_input_tokens") ?? 0);
|
|
375
|
+
state.outputTokens = Math.max(state.outputTokens, numeric(raw, "output_tokens") ?? 0);
|
|
376
|
+
const inputTokens = state.uncachedInput + state.cacheReadTokens + state.cacheCreationTokens;
|
|
377
|
+
const cacheTelemetryStatus = state.cacheTelemetryMeasured ? "measured" : "unavailable";
|
|
378
|
+
const providerUsage = {
|
|
379
|
+
inputTokens,
|
|
380
|
+
outputTokens: state.outputTokens,
|
|
381
|
+
...(state.cacheReadTokens ? { cacheReadInputTokens: state.cacheReadTokens } : {}),
|
|
382
|
+
...(state.cacheCreationTokens ? { cacheCreationInputTokens: state.cacheCreationTokens } : {}),
|
|
383
|
+
cacheTelemetryStatus,
|
|
384
|
+
...(state.cacheTelemetryMeasured ? { cacheTelemetrySource: "anthropic_usage" } : {}),
|
|
385
|
+
};
|
|
386
|
+
const rawStopReason = chunk.delta?.stop_reason;
|
|
387
|
+
const stopReason = this.normalizeStopReason(rawStopReason);
|
|
388
|
+
events.push({
|
|
389
|
+
type: "usage",
|
|
390
|
+
totalTokens: inputTokens + state.outputTokens,
|
|
391
|
+
inputTokens,
|
|
392
|
+
outputTokens: state.outputTokens,
|
|
393
|
+
cacheReadInputTokens: state.cacheReadTokens,
|
|
394
|
+
cacheCreationInputTokens: state.cacheCreationTokens,
|
|
395
|
+
cacheTelemetryStatus,
|
|
396
|
+
...(state.cacheTelemetryMeasured ? { cacheTelemetrySource: "anthropic_usage" } : {}),
|
|
397
|
+
...(stopReason ? { stopReason } : {}),
|
|
398
|
+
...(rawStopReason ? { rawStopReason } : {}),
|
|
399
|
+
providerUsage,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
else if (chunk.type === "content_block_start") {
|
|
404
|
+
state.nativeBlocks[chunk.index] = { ...chunk.content_block };
|
|
405
|
+
if (chunk.content_block.type === "text") {
|
|
406
|
+
const initialText = String(chunk.content_block.text ?? "");
|
|
407
|
+
const visibleText = guardTextDelta(initialText, state.textualToolCallGuard);
|
|
408
|
+
state.finalText += visibleText;
|
|
409
|
+
if (visibleText)
|
|
410
|
+
events.push({ type: "text_delta", delta: visibleText });
|
|
411
|
+
}
|
|
412
|
+
else if (chunk.content_block.type === "tool_use") {
|
|
413
|
+
state.textualToolCallGuard.sawNativeToolCall = true;
|
|
414
|
+
state.toolBlocks[chunk.index] = {
|
|
415
|
+
id: chunk.content_block.id,
|
|
416
|
+
name: chunk.content_block.name,
|
|
417
|
+
argsBuffer: "",
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
else if (chunk.type === "content_block_delta") {
|
|
422
|
+
const delta = chunk.delta;
|
|
423
|
+
if (delta.type === "text_delta") {
|
|
424
|
+
const visibleText = guardTextDelta(delta.text, state.textualToolCallGuard);
|
|
425
|
+
state.finalText += visibleText;
|
|
426
|
+
state.nativeBlocks[chunk.index] = {
|
|
427
|
+
...state.nativeBlocks[chunk.index],
|
|
428
|
+
text: String(state.nativeBlocks[chunk.index]?.text ?? "") + delta.text,
|
|
429
|
+
};
|
|
430
|
+
if (visibleText)
|
|
431
|
+
events.push({ type: "text_delta", delta: visibleText });
|
|
432
|
+
}
|
|
433
|
+
else if (delta.type === "thinking_delta") {
|
|
434
|
+
state.nativeBlocks[chunk.index] = {
|
|
435
|
+
...state.nativeBlocks[chunk.index],
|
|
436
|
+
thinking: String(state.nativeBlocks[chunk.index]?.thinking ?? "") + delta.thinking,
|
|
437
|
+
};
|
|
438
|
+
events.push({ type: "thinking_delta", delta: delta.thinking });
|
|
439
|
+
}
|
|
440
|
+
else if (delta.type === "signature_delta") {
|
|
441
|
+
state.nativeBlocks[chunk.index] = {
|
|
442
|
+
...state.nativeBlocks[chunk.index],
|
|
443
|
+
signature: String(state.nativeBlocks[chunk.index]?.signature ?? "") + delta.signature,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
else if (delta.type === "input_json_delta" && state.toolBlocks[chunk.index]) {
|
|
447
|
+
state.toolBlocks[chunk.index].argsBuffer += delta.partial_json;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
else if (chunk.type === "content_block_stop" && state.toolBlocks[chunk.index]) {
|
|
451
|
+
const tool = state.toolBlocks[chunk.index];
|
|
452
|
+
delete state.toolBlocks[chunk.index];
|
|
453
|
+
let args = {};
|
|
454
|
+
try {
|
|
455
|
+
args = JSON.parse(tool.argsBuffer || "{}");
|
|
456
|
+
}
|
|
457
|
+
catch {
|
|
458
|
+
args = {};
|
|
459
|
+
}
|
|
460
|
+
state.nativeBlocks[chunk.index] = { ...state.nativeBlocks[chunk.index], input: args };
|
|
461
|
+
state.finalToolCalls.push({
|
|
462
|
+
id: tool.id,
|
|
463
|
+
name: tool.name,
|
|
464
|
+
arguments: JSON.stringify(args),
|
|
465
|
+
});
|
|
466
|
+
events.push({
|
|
467
|
+
type: "tool_call",
|
|
468
|
+
id: tool.id,
|
|
469
|
+
name: tool.name,
|
|
470
|
+
arguments: args,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
return { events };
|
|
474
|
+
}
|
|
475
|
+
finishStream(state) {
|
|
476
|
+
if (state.textualToolCallGuard.mode === "candidate")
|
|
477
|
+
throw textualToolCallError();
|
|
478
|
+
const events = [];
|
|
479
|
+
if (state.textualToolCallGuard.tail) {
|
|
480
|
+
const tail = state.textualToolCallGuard.tail;
|
|
481
|
+
state.textualToolCallGuard.tail = "";
|
|
482
|
+
state.finalText += tail;
|
|
483
|
+
events.push({ type: "text_delta", delta: tail });
|
|
484
|
+
}
|
|
485
|
+
const blocks = Object.keys(state.nativeBlocks)
|
|
486
|
+
.map(Number)
|
|
487
|
+
.sort((left, right) => left - right)
|
|
488
|
+
.map(index => state.nativeBlocks[index]);
|
|
489
|
+
return {
|
|
490
|
+
events,
|
|
491
|
+
...(blocks.length ? { replay: { protocol: "anthropic-messages", native_blocks: blocks } } : {}),
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
normalizeUsage(raw) {
|
|
495
|
+
if (raw === undefined || raw === null)
|
|
496
|
+
return undefined;
|
|
497
|
+
if (typeof raw !== "object" || Array.isArray(raw)) {
|
|
498
|
+
throw new ProtocolResponseError("anthropic-messages", "usage must be an object");
|
|
499
|
+
}
|
|
500
|
+
const record = raw;
|
|
501
|
+
const uncached = numeric(record, "input_tokens");
|
|
502
|
+
const cacheRead = numeric(record, "cache_read_input_tokens");
|
|
503
|
+
const cacheCreation = numeric(record, "cache_creation_input_tokens");
|
|
504
|
+
const output = numeric(record, "output_tokens");
|
|
505
|
+
if (uncached === undefined && cacheRead === undefined
|
|
506
|
+
&& cacheCreation === undefined && output === undefined)
|
|
507
|
+
return undefined;
|
|
508
|
+
return {
|
|
509
|
+
inputTokens: (uncached ?? 0) + (cacheRead ?? 0) + (cacheCreation ?? 0),
|
|
510
|
+
outputTokens: output ?? 0,
|
|
511
|
+
...(cacheRead ? { cacheReadInputTokens: cacheRead } : {}),
|
|
512
|
+
...(cacheCreation ? { cacheCreationInputTokens: cacheCreation } : {}),
|
|
513
|
+
...(Object.prototype.hasOwnProperty.call(record, "cache_read_input_tokens")
|
|
514
|
+
|| Object.prototype.hasOwnProperty.call(record, "cache_creation_input_tokens")
|
|
515
|
+
? { cacheTelemetryStatus: "measured", cacheTelemetrySource: "anthropic_usage" }
|
|
516
|
+
: { cacheTelemetryStatus: "unavailable" }),
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
normalizeStopReason(raw) {
|
|
520
|
+
if (raw === undefined)
|
|
521
|
+
return undefined;
|
|
522
|
+
switch (raw) {
|
|
523
|
+
case "end_turn": return "end_turn";
|
|
524
|
+
case "tool_use": return "tool_use";
|
|
525
|
+
case "max_tokens": return "max_tokens";
|
|
526
|
+
case "stop_sequence": return "stop_sequence";
|
|
527
|
+
default: return "other";
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
@@ -9,15 +9,14 @@ import { type AnthropicVendorProfile } from "./vendor-profiles.js";
|
|
|
9
9
|
* `<Vendor>AnthropicProvider` subclasses that existed only to carry that config.
|
|
10
10
|
*
|
|
11
11
|
* Adding a new Anthropic-compatible vendor is now "add a profile" — no new
|
|
12
|
-
* provider class is required
|
|
13
|
-
* kept only for backward compatibility / `instanceof` checks).
|
|
12
|
+
* provider class is required.
|
|
14
13
|
*/
|
|
15
14
|
export declare class AnthropicCompatibleProvider extends AnthropicProvider {
|
|
16
15
|
private readonly vendorProfile;
|
|
17
16
|
constructor(profile: AnthropicVendorProfile, apiKey: string, model?: string, retry?: {
|
|
18
17
|
maxRetries: number;
|
|
19
18
|
baseDelay: number;
|
|
20
|
-
}, baseURL?: string);
|
|
19
|
+
}, baseURL?: string, runtimePolicy?: RuntimePolicy);
|
|
21
20
|
protected providerName(): string;
|
|
22
21
|
runtimePolicy(): RuntimePolicy;
|
|
23
22
|
}
|
|
@@ -8,15 +8,18 @@ import { anthropicVendorBaseURL } from "./vendor-profiles.js";
|
|
|
8
8
|
* `<Vendor>AnthropicProvider` subclasses that existed only to carry that config.
|
|
9
9
|
*
|
|
10
10
|
* Adding a new Anthropic-compatible vendor is now "add a profile" — no new
|
|
11
|
-
* provider class is required
|
|
12
|
-
* kept only for backward compatibility / `instanceof` checks).
|
|
11
|
+
* provider class is required.
|
|
13
12
|
*/
|
|
14
13
|
export class AnthropicCompatibleProvider extends AnthropicProvider {
|
|
15
14
|
vendorProfile;
|
|
16
|
-
constructor(profile, apiKey, model, retry, baseURL) {
|
|
17
|
-
super(
|
|
15
|
+
constructor(profile, apiKey, model, retry, baseURL, runtimePolicy) {
|
|
16
|
+
super({
|
|
17
|
+
apiKey,
|
|
18
|
+
model: model ?? profile.defaultModel,
|
|
19
|
+
retry,
|
|
18
20
|
baseURL: baseURL ?? anthropicVendorBaseURL(profile),
|
|
19
21
|
authMode: "api-key",
|
|
22
|
+
runtimePolicy,
|
|
20
23
|
});
|
|
21
24
|
this.vendorProfile = profile;
|
|
22
25
|
}
|
|
@@ -24,6 +27,6 @@ export class AnthropicCompatibleProvider extends AnthropicProvider {
|
|
|
24
27
|
return this.vendorProfile.providerId;
|
|
25
28
|
}
|
|
26
29
|
runtimePolicy() {
|
|
27
|
-
return
|
|
30
|
+
return super.runtimePolicy();
|
|
28
31
|
}
|
|
29
32
|
}
|
|
@@ -1,46 +1,43 @@
|
|
|
1
|
-
import type { Message, ProviderDescriptor, ProviderReplay, ProviderRunState, RenderedContext,
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
authMode?: "api-key" | "bearer";
|
|
5
|
-
}
|
|
6
|
-
/** Options-object form for `AnthropicProvider` — the recommended constructor shape. */
|
|
7
|
-
export interface AnthropicProviderConfig extends AnthropicProviderOptions {
|
|
1
|
+
import type { LLMProvider, Message, PromptMeasurement, ProviderDescriptor, ProviderReplay, ProviderRunState, RenderedContext, RuntimePolicy, StreamEvent, ToolSchema } from "../types.js";
|
|
2
|
+
import { type CanonicalAdapterInput } from "./content-normalization.js";
|
|
3
|
+
export interface AnthropicProviderConfig {
|
|
8
4
|
apiKey: string;
|
|
9
5
|
model?: string;
|
|
10
6
|
retry?: {
|
|
11
7
|
maxRetries: number;
|
|
12
8
|
baseDelay: number;
|
|
13
9
|
};
|
|
10
|
+
baseURL?: string;
|
|
11
|
+
authMode?: "api-key" | "bearer";
|
|
12
|
+
runtimePolicy?: RuntimePolicy;
|
|
14
13
|
}
|
|
14
|
+
type ResolvedAnthropicRuntime = CanonicalAdapterInput["resolved"];
|
|
15
15
|
export declare class AnthropicProvider implements LLMProvider {
|
|
16
16
|
private client;
|
|
17
17
|
private circuit;
|
|
18
18
|
private maxRetries;
|
|
19
19
|
private baseDelay;
|
|
20
20
|
protected readonly model: string;
|
|
21
|
-
private
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
private readonly adapter;
|
|
22
|
+
private readonly nativeAssistantBlocks;
|
|
23
|
+
private readonly resolvedRuntimePolicy;
|
|
24
|
+
private readonly directNativeTokenCounting;
|
|
25
|
+
private readonly defaultTextualToolCallPolicy;
|
|
26
|
+
private resolvedRuntime?;
|
|
27
|
+
constructor(config: AnthropicProviderConfig);
|
|
26
28
|
runtimePolicy(): RuntimePolicy;
|
|
27
|
-
/** Identity advertised in the descriptor; overridden by Anthropic-compatible vendors
|
|
29
|
+
/** Identity advertised in the descriptor; overridden by Anthropic-compatible vendors. */
|
|
28
30
|
protected providerName(): string;
|
|
29
31
|
descriptor(): ProviderDescriptor;
|
|
32
|
+
bindResolvedRuntime(resolved: ResolvedAnthropicRuntime): void;
|
|
30
33
|
peekProviderReplay(message: Pick<Message, "content" | "toolCalls">): ProviderReplay | undefined;
|
|
31
34
|
seedProviderReplay(message: Pick<Message, "content" | "toolCalls">, replay: ProviderReplay): void;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
* only when the system blocks won't carry one (`anchorCache`). When structured
|
|
35
|
-
* system blocks are present, their breakpoints already cache the tools prefix
|
|
36
|
-
* (tools render before system), so a redundant tool breakpoint would only burn
|
|
37
|
-
* one of Anthropic's 4 cache_control slots — slots the message history needs.
|
|
38
|
-
*/
|
|
39
|
-
private buildTools;
|
|
35
|
+
private adapterInput;
|
|
36
|
+
private buildPlan;
|
|
40
37
|
complete(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<Message>;
|
|
38
|
+
/** Native measurement belongs to the verified official endpoint, not the wire protocol. */
|
|
39
|
+
countTokens(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>): Promise<PromptMeasurement>;
|
|
41
40
|
stream(context: RenderedContext, tools: ToolSchema[], extensions?: Record<string, unknown>, _state?: ProviderRunState, signal?: AbortSignal): AsyncIterable<StreamEvent>;
|
|
42
|
-
private requestExtensions;
|
|
43
|
-
private hasBetas;
|
|
44
41
|
private createMessage;
|
|
45
42
|
private streamMessage;
|
|
46
43
|
private buildSystem;
|