@bastani/pi-ai 0.9.20-alpha.2 → 0.9.20-alpha.4
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/CHANGELOG.md +34 -1
- package/NOTICE.md +1 -1
- package/README.md +28 -5
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +167 -85
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/azure-openai-responses.d.ts.map +1 -1
- package/dist/api/azure-openai-responses.js +17 -5
- package/dist/api/azure-openai-responses.js.map +1 -1
- package/dist/api/bedrock-converse-stream.d.ts.map +1 -1
- package/dist/api/bedrock-converse-stream.js +15 -12
- package/dist/api/bedrock-converse-stream.js.map +1 -1
- package/dist/api/google-generative-ai.d.ts.map +1 -1
- package/dist/api/google-generative-ai.js +22 -80
- package/dist/api/google-generative-ai.js.map +1 -1
- package/dist/api/google-shared.d.ts +13 -4
- package/dist/api/google-shared.d.ts.map +1 -1
- package/dist/api/google-shared.js +54 -4
- package/dist/api/google-shared.js.map +1 -1
- package/dist/api/google-vertex.d.ts.map +1 -1
- package/dist/api/google-vertex.js +25 -65
- package/dist/api/google-vertex.js.map +1 -1
- package/dist/api/mistral-conversations.d.ts.map +1 -1
- package/dist/api/mistral-conversations.js +15 -11
- package/dist/api/mistral-conversations.js.map +1 -1
- package/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.js +20 -22
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-completions.d.ts +6 -4
- package/dist/api/openai-completions.d.ts.map +1 -1
- package/dist/api/openai-completions.js +39 -57
- package/dist/api/openai-completions.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts +7 -5
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +56 -56
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +14 -19
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/api/pi-messages.d.ts +3 -3
- package/dist/api/pi-messages.d.ts.map +1 -1
- package/dist/api/pi-messages.js +2 -2
- package/dist/api/pi-messages.js.map +1 -1
- package/dist/api/simple-options.d.ts +3 -3
- package/dist/api/simple-options.d.ts.map +1 -1
- package/dist/api/simple-options.js.map +1 -1
- package/dist/api/transform-messages.d.ts.map +1 -1
- package/dist/api/transform-messages.js +21 -7
- package/dist/api/transform-messages.js.map +1 -1
- package/dist/auth/credential-store.d.ts.map +1 -1
- package/dist/auth/credential-store.js +3 -2
- package/dist/auth/credential-store.js.map +1 -1
- package/dist/auth/resolve.d.ts +4 -0
- package/dist/auth/resolve.d.ts.map +1 -1
- package/dist/auth/resolve.js +27 -8
- package/dist/auth/resolve.js.map +1 -1
- package/dist/compat.d.ts +3 -3
- package/dist/compat.d.ts.map +1 -1
- package/dist/compat.js +9 -6
- package/dist/compat.js.map +1 -1
- package/dist/env-api-keys.d.ts +2 -0
- package/dist/env-api-keys.d.ts.map +1 -1
- package/dist/env-api-keys.js +59 -43
- package/dist/env-api-keys.js.map +1 -1
- package/dist/image-models.generated.d.ts +30 -0
- package/dist/image-models.generated.d.ts.map +1 -1
- package/dist/image-models.generated.js +34 -4
- package/dist/image-models.generated.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +5 -4
- package/dist/models.d.ts.map +1 -1
- package/dist/models.generated.d.ts +2 -0
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +2 -0
- package/dist/models.generated.js.map +1 -1
- package/dist/models.js +6 -3
- package/dist/models.js.map +1 -1
- package/dist/providers/amazon-bedrock.models.d.ts +1 -2
- package/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
- package/dist/providers/amazon-bedrock.models.js.map +1 -1
- package/dist/providers/ant-ling.models.d.ts +1 -2
- package/dist/providers/ant-ling.models.d.ts.map +1 -1
- package/dist/providers/ant-ling.models.js.map +1 -1
- package/dist/providers/anthropic.models.d.ts +1 -2
- package/dist/providers/anthropic.models.d.ts.map +1 -1
- package/dist/providers/anthropic.models.js.map +1 -1
- package/dist/providers/azure-openai-responses.models.d.ts +1 -2
- package/dist/providers/azure-openai-responses.models.d.ts.map +1 -1
- package/dist/providers/azure-openai-responses.models.js.map +1 -1
- package/dist/providers/baseten.models.d.ts +1 -2
- package/dist/providers/baseten.models.d.ts.map +1 -1
- package/dist/providers/baseten.models.js.map +1 -1
- package/dist/providers/cerebras.models.d.ts +1 -2
- package/dist/providers/cerebras.models.d.ts.map +1 -1
- package/dist/providers/cerebras.models.js.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.models.d.ts +1 -2
- package/dist/providers/cloudflare-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.models.js.map +1 -1
- package/dist/providers/cloudflare-workers-ai.models.d.ts +1 -2
- package/dist/providers/cloudflare-workers-ai.models.d.ts.map +1 -1
- package/dist/providers/cloudflare-workers-ai.models.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/amazon-bedrock.json +1 -1
- package/dist/providers/data/anthropic.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/cerebras.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/deepseek.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/google-vertex.json +1 -1
- package/dist/providers/data/google.json +1 -1
- package/dist/providers/data/mistral.json +1 -1
- package/dist/providers/data/moonshotai-cn.json +1 -1
- package/dist/providers/data/moonshotai.json +1 -1
- package/dist/providers/data/nvidia.json +1 -1
- package/dist/providers/data/openai-codex.json +1 -1
- package/dist/providers/data/openai.json +1 -1
- package/dist/providers/data/opencode-go.json +1 -1
- package/dist/providers/data/opencode.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/radius.json +1 -0
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/zai-coding-cn.json +1 -1
- package/dist/providers/data/zai.json +1 -1
- package/dist/providers/deepseek.models.d.ts +1 -2
- package/dist/providers/deepseek.models.d.ts.map +1 -1
- package/dist/providers/deepseek.models.js.map +1 -1
- package/dist/providers/faux.d.ts +2 -2
- package/dist/providers/faux.d.ts.map +1 -1
- package/dist/providers/faux.js +11 -11
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/fireworks.models.d.ts +1 -2
- package/dist/providers/fireworks.models.d.ts.map +1 -1
- package/dist/providers/fireworks.models.js.map +1 -1
- package/dist/providers/github-copilot.models.d.ts +1 -2
- package/dist/providers/github-copilot.models.d.ts.map +1 -1
- package/dist/providers/github-copilot.models.js.map +1 -1
- package/dist/providers/google-vertex.models.d.ts +1 -2
- package/dist/providers/google-vertex.models.d.ts.map +1 -1
- package/dist/providers/google-vertex.models.js.map +1 -1
- package/dist/providers/google.models.d.ts +1 -2
- package/dist/providers/google.models.d.ts.map +1 -1
- package/dist/providers/google.models.js.map +1 -1
- package/dist/providers/groq.models.d.ts +1 -2
- package/dist/providers/groq.models.d.ts.map +1 -1
- package/dist/providers/groq.models.js.map +1 -1
- package/dist/providers/huggingface.models.d.ts +1 -2
- package/dist/providers/huggingface.models.d.ts.map +1 -1
- package/dist/providers/huggingface.models.js.map +1 -1
- package/dist/providers/kimi-coding.models.d.ts +1 -2
- package/dist/providers/kimi-coding.models.d.ts.map +1 -1
- package/dist/providers/kimi-coding.models.js.map +1 -1
- package/dist/providers/minimax-cn.models.d.ts +1 -2
- package/dist/providers/minimax-cn.models.d.ts.map +1 -1
- package/dist/providers/minimax-cn.models.js.map +1 -1
- package/dist/providers/minimax.models.d.ts +1 -2
- package/dist/providers/minimax.models.d.ts.map +1 -1
- package/dist/providers/minimax.models.js.map +1 -1
- package/dist/providers/mistral.models.d.ts +1 -2
- package/dist/providers/mistral.models.d.ts.map +1 -1
- package/dist/providers/mistral.models.js.map +1 -1
- package/dist/providers/moonshotai-cn.models.d.ts +1 -2
- package/dist/providers/moonshotai-cn.models.d.ts.map +1 -1
- package/dist/providers/moonshotai-cn.models.js.map +1 -1
- package/dist/providers/moonshotai.models.d.ts +1 -2
- package/dist/providers/moonshotai.models.d.ts.map +1 -1
- package/dist/providers/moonshotai.models.js.map +1 -1
- package/dist/providers/nvidia.models.d.ts +1 -2
- package/dist/providers/nvidia.models.d.ts.map +1 -1
- package/dist/providers/nvidia.models.js.map +1 -1
- package/dist/providers/openai-codex.models.d.ts +1 -2
- package/dist/providers/openai-codex.models.d.ts.map +1 -1
- package/dist/providers/openai-codex.models.js.map +1 -1
- package/dist/providers/openai.models.d.ts +1 -2
- package/dist/providers/openai.models.d.ts.map +1 -1
- package/dist/providers/openai.models.js.map +1 -1
- package/dist/providers/opencode-go.models.d.ts +1 -2
- package/dist/providers/opencode-go.models.d.ts.map +1 -1
- package/dist/providers/opencode-go.models.js.map +1 -1
- package/dist/providers/opencode.models.d.ts +1 -2
- package/dist/providers/opencode.models.d.ts.map +1 -1
- package/dist/providers/opencode.models.js.map +1 -1
- package/dist/providers/openrouter.models.d.ts +1 -2
- package/dist/providers/openrouter.models.d.ts.map +1 -1
- package/dist/providers/openrouter.models.js.map +1 -1
- package/dist/providers/qwen-token-plan-cn.models.d.ts +1 -2
- package/dist/providers/qwen-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-cn.models.js.map +1 -1
- package/dist/providers/qwen-token-plan-individual.models.d.ts +1 -2
- package/dist/providers/qwen-token-plan-individual.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan-individual.models.js.map +1 -1
- package/dist/providers/qwen-token-plan.models.d.ts +1 -2
- package/dist/providers/qwen-token-plan.models.d.ts.map +1 -1
- package/dist/providers/qwen-token-plan.models.js.map +1 -1
- package/dist/providers/radius.d.ts.map +1 -1
- package/dist/providers/radius.js +19 -5
- package/dist/providers/radius.js.map +1 -1
- package/dist/providers/radius.models.d.ts +3 -0
- package/dist/providers/radius.models.d.ts.map +1 -0
- package/dist/providers/radius.models.js +6 -0
- package/dist/providers/radius.models.js.map +1 -0
- package/dist/providers/together.models.d.ts +1 -2
- package/dist/providers/together.models.d.ts.map +1 -1
- package/dist/providers/together.models.js.map +1 -1
- package/dist/providers/vercel-ai-gateway.models.d.ts +1 -2
- package/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
- package/dist/providers/vercel-ai-gateway.models.js.map +1 -1
- package/dist/providers/xai.models.d.ts +1 -2
- package/dist/providers/xai.models.d.ts.map +1 -1
- package/dist/providers/xai.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts +1 -2
- package/dist/providers/xiaomi-token-plan-ams.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts +1 -2
- package/dist/providers/xiaomi-token-plan-cn.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts +1 -2
- package/dist/providers/xiaomi-token-plan-sgp.models.d.ts.map +1 -1
- package/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
- package/dist/providers/xiaomi.models.d.ts +1 -2
- package/dist/providers/xiaomi.models.d.ts.map +1 -1
- package/dist/providers/xiaomi.models.js.map +1 -1
- package/dist/providers/zai-coding-cn.models.d.ts +1 -2
- package/dist/providers/zai-coding-cn.models.d.ts.map +1 -1
- package/dist/providers/zai-coding-cn.models.js.map +1 -1
- package/dist/providers/zai.models.d.ts +1 -2
- package/dist/providers/zai.models.d.ts.map +1 -1
- package/dist/providers/zai.models.js.map +1 -1
- package/dist/types.d.ts +95 -26
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/diagnostics.d.ts +3 -2
- package/dist/utils/diagnostics.d.ts.map +1 -1
- package/dist/utils/diagnostics.js.map +1 -1
- package/dist/utils/estimate.d.ts +2 -2
- package/dist/utils/estimate.d.ts.map +1 -1
- package/dist/utils/estimate.js +8 -29
- package/dist/utils/estimate.js.map +1 -1
- package/dist/utils/overflow.d.ts +1 -0
- package/dist/utils/overflow.d.ts.map +1 -1
- package/dist/utils/overflow.js +17 -5
- package/dist/utils/overflow.js.map +1 -1
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js +2 -0
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/text.d.ts +9 -1
- package/dist/utils/text.d.ts.map +1 -1
- package/dist/utils/text.js +26 -0
- package/dist/utils/text.js.map +1 -1
- package/dist/utils/transcript.d.ts +84 -0
- package/dist/utils/transcript.d.ts.map +1 -0
- package/dist/utils/transcript.js +204 -0
- package/dist/utils/transcript.js.map +1 -0
- package/package.json +3 -3
- package/dist/utils/deferred-tools.d.ts +0 -9
- package/dist/utils/deferred-tools.d.ts.map +0 -1
- package/dist/utils/deferred-tools.js +0 -36
- package/dist/utils/deferred-tools.js.map +0 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import { calculateCost } from "../models.js";
|
|
3
|
-
import { splitDeferredTools } from "../utils/deferred-tools.js";
|
|
4
3
|
import { appendAssistantMessageDiagnostic } from "../utils/diagnostics.js";
|
|
5
4
|
import { assertSupportedDocumentMimeType } from "../utils/document-input.js";
|
|
6
5
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
@@ -11,6 +10,8 @@ import { getProviderEnvValue } from "../utils/provider-env.js";
|
|
|
11
10
|
import { retryProviderRequest } from "../utils/provider-retry.js";
|
|
12
11
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
13
12
|
import { createStreamDeadline, withStreamDeadline } from "../utils/stream-deadline.js";
|
|
13
|
+
import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
|
|
14
|
+
import { getCurrentTools, getDeclaredTools, getInitialSystemMessage, hasToolRedefinitions, resolveTranscript, } from "../utils/transcript.js";
|
|
14
15
|
import { getJsonSchemaToolParameters, resolveJsonSchemaStrictSampling } from "./constrained-sampling.js";
|
|
15
16
|
import { buildCopilotDynamicHeaders, hasCopilotVisionInput, preserveCopilotIntegrationHeader, } from "./github-copilot-headers.js";
|
|
16
17
|
import { adjustMaxTokensForThinking, buildBaseOptions, clampMaxTokensToContext } from "./simple-options.js";
|
|
@@ -127,6 +128,20 @@ const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
|
|
|
127
128
|
const SERVER_SIDE_FALLBACK_BETA = "server-side-fallback-2026-07-01";
|
|
128
129
|
const THINKING_BINDING_CONTROLS_BETA = "thinking-binding-controls-2026-08-01";
|
|
129
130
|
const MID_CONVERSATION_OUTPUT_CONFIG_BETA = "mid-conversation-output-config-2026-07-01";
|
|
131
|
+
const MID_CONVERSATION_TOOL_CHANGES_BETA = "mid-conversation-tool-changes-2026-07-01";
|
|
132
|
+
/**
|
|
133
|
+
* Stable deferred tool declared whenever native tool changes are in use. Anthropic adds
|
|
134
|
+
* hidden prompt scaffolding as soon as any tool has `defer_loading`; declaring this
|
|
135
|
+
* placeholder from the first request keeps that scaffolding in the cached prefix, so the
|
|
136
|
+
* first real late tool does not invalidate the cache (measured: full miss without it).
|
|
137
|
+
* It is never activated and the model cannot see it.
|
|
138
|
+
*/
|
|
139
|
+
const DEFERRED_TOOL_PLACEHOLDER = {
|
|
140
|
+
name: "__pi_deferred_placeholder__",
|
|
141
|
+
description: "Reserved placeholder. Never available. Never call this.",
|
|
142
|
+
input_schema: { type: "object", properties: {}, required: [] },
|
|
143
|
+
defer_loading: true,
|
|
144
|
+
};
|
|
130
145
|
function shouldUseServerSideFallbackBeta(model) {
|
|
131
146
|
return (model.compat?.allowedFallbackModels?.length ?? 0) > 0;
|
|
132
147
|
}
|
|
@@ -244,24 +259,10 @@ function getAnthropicCompat(model) {
|
|
|
244
259
|
supportsTemperature: model.compat?.supportsTemperature ?? true,
|
|
245
260
|
allowEmptySignature: model.compat?.allowEmptySignature ?? false,
|
|
246
261
|
supportsStrictTools: model.compat?.supportsStrictTools ?? false,
|
|
247
|
-
|
|
262
|
+
supportsMidConvoSystemMessages: model.compat?.supportsMidConvoSystemMessages ?? false,
|
|
263
|
+
supportsMidConvoToolChanges: model.compat?.supportsMidConvoToolChanges ?? false,
|
|
248
264
|
};
|
|
249
265
|
}
|
|
250
|
-
/**
|
|
251
|
-
* Default for `supportsToolReferences`: first-party Anthropic models except
|
|
252
|
-
* Haiku (rejects client-side tool_reference blocks) and models that predate
|
|
253
|
-
* tool search (Claude 3.x, Opus/Sonnet 4.0, Opus 4.1).
|
|
254
|
-
*/
|
|
255
|
-
function defaultSupportsToolReferences(model) {
|
|
256
|
-
if (model.provider !== "anthropic" || model.id.includes("haiku"))
|
|
257
|
-
return false;
|
|
258
|
-
const version = model.id.match(/^claude-(?:opus|sonnet|fable)-(\d+)(?:-(\d+))?(?:-|$)/);
|
|
259
|
-
if (!version)
|
|
260
|
-
return false;
|
|
261
|
-
const major = Number(version[1]);
|
|
262
|
-
const minor = version[2] && version[2].length < 8 ? Number(version[2]) : 0;
|
|
263
|
-
return major > 4 || (major === 4 && minor >= 5);
|
|
264
|
-
}
|
|
265
266
|
function mergeHeaders(...headerSources) {
|
|
266
267
|
const merged = {};
|
|
267
268
|
for (const headers of headerSources) {
|
|
@@ -456,6 +457,8 @@ async function* iterateAnthropicEvents(response, signal) {
|
|
|
456
457
|
}
|
|
457
458
|
export const stream = (model, context, options) => {
|
|
458
459
|
const stream = new AssistantMessageEventStream();
|
|
460
|
+
const normalizedContext = resolveTranscript(context, getAnthropicCompat(model).supportsMidConvoSystemMessages);
|
|
461
|
+
const currentTools = getCurrentTools(normalizedContext.messages);
|
|
459
462
|
(async () => {
|
|
460
463
|
const providerThinkingLevel = supportsMidConvoEffort(model) ? (options?.effort ?? "high") : undefined;
|
|
461
464
|
const output = {
|
|
@@ -491,20 +494,23 @@ export const stream = (model, context, options) => {
|
|
|
491
494
|
assertRequestAuth(model.provider, apiKey, options?.headers);
|
|
492
495
|
let copilotDynamicHeaders;
|
|
493
496
|
if (model.provider === "github-copilot") {
|
|
494
|
-
const hasImages = hasCopilotVisionInput(
|
|
497
|
+
const hasImages = hasCopilotVisionInput(normalizedContext.messages);
|
|
495
498
|
copilotDynamicHeaders = preserveCopilotIntegrationHeader(model.headers, buildCopilotDynamicHeaders({
|
|
496
|
-
messages:
|
|
499
|
+
messages: normalizedContext.messages,
|
|
497
500
|
hasImages,
|
|
498
501
|
apiKey,
|
|
499
502
|
}));
|
|
500
503
|
}
|
|
501
504
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention, options?.env);
|
|
502
505
|
const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
|
|
503
|
-
const created = createClient(model, apiKey, model.reasoning && options?.thinkingEnabled === true && (options.interleavedThinking ?? true), shouldUseFineGrainedToolStreamingBeta(model, context), shouldUseServerSideFallbackBeta(model), options?.headers, options?.fetch, copilotDynamicHeaders, cacheSessionId)
|
|
506
|
+
const created = createClient(model, apiKey, model.reasoning && options?.thinkingEnabled === true && (options.interleavedThinking ?? true), shouldUseFineGrainedToolStreamingBeta(model, context), shouldUseServerSideFallbackBeta(model), options?.headers, options?.fetch, copilotDynamicHeaders, cacheSessionId, getAnthropicCompat(model).supportsMidConvoToolChanges &&
|
|
507
|
+
getAnthropicCompat(model).supportsMidConvoSystemMessages &&
|
|
508
|
+
(getInitialSystemMessage(normalizedContext.messages)?.toolsAdded?.length ?? 0) > 0 &&
|
|
509
|
+
!hasToolRedefinitions(normalizedContext.messages));
|
|
504
510
|
client = created.client;
|
|
505
511
|
isOAuth = created.isOAuthToken;
|
|
506
512
|
}
|
|
507
|
-
let params = buildParams(model,
|
|
513
|
+
let params = buildParams(model, normalizedContext, isOAuth, options);
|
|
508
514
|
const nextParams = await options?.onPayload?.(params, model);
|
|
509
515
|
if (nextParams !== undefined) {
|
|
510
516
|
params = nextParams;
|
|
@@ -514,7 +520,7 @@ export const stream = (model, context, options) => {
|
|
|
514
520
|
...(options?.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),
|
|
515
521
|
maxRetries: 0,
|
|
516
522
|
};
|
|
517
|
-
const response = await retryProviderRequest(() => client.messages.create({ ...params, stream: true }, requestOptions).asResponse(), {
|
|
523
|
+
const response = await retryProviderRequest(() => client.beta.messages.create({ ...params, stream: true }, requestOptions).asResponse(), {
|
|
518
524
|
maxRetries: options?.maxRetries,
|
|
519
525
|
maxRetryDelayMs: options?.maxRetryDelayMs,
|
|
520
526
|
signal: streamDeadline.signal,
|
|
@@ -525,11 +531,13 @@ export const stream = (model, context, options) => {
|
|
|
525
531
|
for await (const event of withStreamDeadline(iterateAnthropicEvents(response, streamDeadline.signal), streamDeadline.deadlineMs, streamDeadline.abort)) {
|
|
526
532
|
if (event.type === "message_start") {
|
|
527
533
|
output.responseId = event.message.id;
|
|
528
|
-
|
|
529
|
-
|
|
534
|
+
const responseModel = event.message.model;
|
|
535
|
+
if (responseModel !== model.id)
|
|
536
|
+
output.responseModel = responseModel;
|
|
537
|
+
const fallbackCost = responseModel === model.id
|
|
530
538
|
? undefined
|
|
531
|
-
: model.compat?.allowedFallbackModels?.find((fallback) => fallback.provider === model.provider && fallback.model ===
|
|
532
|
-
usageModel = fallbackCost ? { ...model, id:
|
|
539
|
+
: model.compat?.allowedFallbackModels?.find((fallback) => fallback.provider === model.provider && fallback.model === responseModel)?.cost;
|
|
540
|
+
usageModel = fallbackCost ? { ...model, id: responseModel, cost: fallbackCost } : model;
|
|
533
541
|
// Capture initial token usage from message_start event
|
|
534
542
|
// This ensures we have input token counts even if the stream is aborted early
|
|
535
543
|
output.usage.input = event.message.usage.input_tokens || 0;
|
|
@@ -579,7 +587,7 @@ export const stream = (model, context, options) => {
|
|
|
579
587
|
type: "toolCall",
|
|
580
588
|
id: event.content_block.id,
|
|
581
589
|
name: isOAuth
|
|
582
|
-
? fromClaudeCodeName(event.content_block.name,
|
|
590
|
+
? fromClaudeCodeName(event.content_block.name, currentTools)
|
|
583
591
|
: event.content_block.name,
|
|
584
592
|
arguments: event.content_block.input ?? {},
|
|
585
593
|
partialJson: "",
|
|
@@ -839,7 +847,7 @@ export const streamSimple = (model, context, options) => {
|
|
|
839
847
|
function isOAuthToken(apiKey) {
|
|
840
848
|
return apiKey.includes("sk-ant-oat");
|
|
841
849
|
}
|
|
842
|
-
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, useServerSideFallbackBeta, optionsHeaders, fetch, dynamicHeaders, sessionId) {
|
|
850
|
+
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, useServerSideFallbackBeta, optionsHeaders, fetch, dynamicHeaders, sessionId, useNativeToolChanges = false) {
|
|
843
851
|
// Adaptive thinking models have interleaved thinking built in, so skip the beta header.
|
|
844
852
|
const needsInterleavedBeta = interleavedThinking && model.compat?.forceAdaptiveThinking !== true;
|
|
845
853
|
const betaFeatures = [];
|
|
@@ -858,6 +866,8 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
858
866
|
if (supportsMidConvoEffort(model)) {
|
|
859
867
|
betaFeatures.push(MID_CONVERSATION_OUTPUT_CONFIG_BETA, THINKING_BINDING_CONTROLS_BETA);
|
|
860
868
|
}
|
|
869
|
+
if (useNativeToolChanges)
|
|
870
|
+
betaFeatures.push(MID_CONVERSATION_TOOL_CHANGES_BETA);
|
|
861
871
|
const uniqueBetaFeatures = [...new Set(betaFeatures)];
|
|
862
872
|
// Copilot: Bearer auth, selective betas.
|
|
863
873
|
if (model.provider === "github-copilot") {
|
|
@@ -915,20 +925,58 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
915
925
|
});
|
|
916
926
|
return { client, isOAuthToken: false };
|
|
917
927
|
}
|
|
928
|
+
function getNativeToolChangeBetas(model, context, isOAuth, options) {
|
|
929
|
+
let configured;
|
|
930
|
+
for (const headers of [model.headers, options?.headers]) {
|
|
931
|
+
for (const [name, value] of Object.entries(headers ?? {})) {
|
|
932
|
+
if (name.toLowerCase() === "anthropic-beta")
|
|
933
|
+
configured = value;
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
if (configured === null)
|
|
937
|
+
return [];
|
|
938
|
+
if (configured !== undefined)
|
|
939
|
+
return [
|
|
940
|
+
...new Set(configured
|
|
941
|
+
.split(",")
|
|
942
|
+
.map((feature) => feature.trim())
|
|
943
|
+
.filter(Boolean)),
|
|
944
|
+
];
|
|
945
|
+
const features = [MID_CONVERSATION_TOOL_CHANGES_BETA];
|
|
946
|
+
if (isOAuth)
|
|
947
|
+
features.push("claude-code-20250219", "oauth-2025-04-20");
|
|
948
|
+
if (shouldUseFineGrainedToolStreamingBeta(model, context))
|
|
949
|
+
features.push(FINE_GRAINED_TOOL_STREAMING_BETA);
|
|
950
|
+
if (model.reasoning &&
|
|
951
|
+
options?.thinkingEnabled &&
|
|
952
|
+
(options.interleavedThinking ?? true) &&
|
|
953
|
+
model.compat?.forceAdaptiveThinking !== true) {
|
|
954
|
+
features.push(INTERLEAVED_THINKING_BETA);
|
|
955
|
+
}
|
|
956
|
+
if (shouldUseServerSideFallbackBeta(model))
|
|
957
|
+
features.push(SERVER_SIDE_FALLBACK_BETA);
|
|
958
|
+
if (shouldUseThinkingBindingControlsBeta(model))
|
|
959
|
+
features.push(THINKING_BINDING_CONTROLS_BETA);
|
|
960
|
+
if (supportsMidConvoEffort(model))
|
|
961
|
+
features.push(MID_CONVERSATION_OUTPUT_CONFIG_BETA, THINKING_BINDING_CONTROLS_BETA);
|
|
962
|
+
return [...new Set(features)];
|
|
963
|
+
}
|
|
918
964
|
function buildParams(model, context, isOAuthToken, options) {
|
|
919
965
|
const { cacheControl } = getCacheControl(model, options?.cacheRetention, options?.env);
|
|
920
966
|
const compat = getAnthropicCompat(model);
|
|
967
|
+
const initialSystemMessage = getInitialSystemMessage(context.messages);
|
|
968
|
+
const initialSystemText = initialSystemMessage ? getSystemMessageText(initialSystemMessage) : "";
|
|
921
969
|
const transformedMessages = transformMessages(context.messages, model, normalizeToolCallId);
|
|
922
|
-
const
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
const converted = convertMessages(
|
|
970
|
+
const conversationMessages = initialSystemMessage ? transformedMessages.slice(1) : transformedMessages;
|
|
971
|
+
// Native tool changes reference tools by name, so a redefined name cannot be expressed,
|
|
972
|
+
// and Anthropic rejects a tool list where every tool is deferred, so there must be an
|
|
973
|
+
// initial active tool to anchor the deferred ones. Otherwise the current tool list is sent.
|
|
974
|
+
const initialTools = initialSystemMessage?.toolsAdded ?? [];
|
|
975
|
+
const nativeToolChanges = compat.supportsMidConvoSystemMessages &&
|
|
976
|
+
compat.supportsMidConvoToolChanges &&
|
|
977
|
+
initialTools.length > 0 &&
|
|
978
|
+
!hasToolRedefinitions(context.messages);
|
|
979
|
+
const converted = convertMessages(conversationMessages, isOAuthToken, cacheControl, compat.allowEmptySignature, supportsMidConvoEffort(model) ? model.provider : undefined, nativeToolChanges);
|
|
932
980
|
const activeEffort = options?.effort ?? "high";
|
|
933
981
|
const params = {
|
|
934
982
|
model: model.id,
|
|
@@ -938,6 +986,8 @@ function buildParams(model, context, isOAuthToken, options) {
|
|
|
938
986
|
max_tokens: options?.maxTokens ?? model.maxTokens,
|
|
939
987
|
stream: true,
|
|
940
988
|
};
|
|
989
|
+
if (nativeToolChanges)
|
|
990
|
+
params.betas = getNativeToolChangeBetas(model, context, isOAuthToken, options);
|
|
941
991
|
// For OAuth tokens, we MUST include Claude Code identity
|
|
942
992
|
if (isOAuthToken) {
|
|
943
993
|
params.system = [
|
|
@@ -947,20 +997,20 @@ function buildParams(model, context, isOAuthToken, options) {
|
|
|
947
997
|
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
948
998
|
},
|
|
949
999
|
];
|
|
950
|
-
if (
|
|
1000
|
+
if (initialSystemText) {
|
|
951
1001
|
params.system.push({
|
|
952
1002
|
type: "text",
|
|
953
|
-
text: sanitizeSurrogates(
|
|
1003
|
+
text: sanitizeSurrogates(initialSystemText),
|
|
954
1004
|
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
955
1005
|
});
|
|
956
1006
|
}
|
|
957
1007
|
}
|
|
958
|
-
else if (
|
|
1008
|
+
else if (initialSystemText) {
|
|
959
1009
|
// Add cache control to system prompt for non-OAuth tokens
|
|
960
1010
|
params.system = [
|
|
961
1011
|
{
|
|
962
1012
|
type: "text",
|
|
963
|
-
text: sanitizeSurrogates(
|
|
1013
|
+
text: sanitizeSurrogates(initialSystemText),
|
|
964
1014
|
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
965
1015
|
},
|
|
966
1016
|
];
|
|
@@ -972,12 +1022,26 @@ function buildParams(model, context, isOAuthToken, options) {
|
|
|
972
1022
|
compat.supportsTemperature) {
|
|
973
1023
|
params.temperature = options.temperature;
|
|
974
1024
|
}
|
|
975
|
-
|
|
1025
|
+
const toolCacheControl = compat.supportsCacheControlOnTools ? cacheControl : undefined;
|
|
1026
|
+
if (nativeToolChanges) {
|
|
1027
|
+
// Initial tools stay active with the cache breakpoint on the last one. Every later
|
|
1028
|
+
// declaration is deferred and only surfaced by its `tool_addition` block; removed
|
|
1029
|
+
// tools stay declared and are withdrawn by `tool_removal`. The request-level list
|
|
1030
|
+
// therefore only grows, keeping the cached prefix intact across tool changes.
|
|
1031
|
+
const initialNames = new Set(initialTools.map((tool) => tool.name));
|
|
1032
|
+
const laterTools = getDeclaredTools(context.messages).filter((tool) => !initialNames.has(tool.name));
|
|
976
1033
|
params.tools = [
|
|
977
|
-
...convertTools(
|
|
978
|
-
|
|
1034
|
+
...convertTools(initialTools, isOAuthToken, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, toolCacheControl),
|
|
1035
|
+
DEFERRED_TOOL_PLACEHOLDER,
|
|
1036
|
+
...convertTools(laterTools, isOAuthToken, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools).map((tool) => ({ ...tool, defer_loading: true })),
|
|
979
1037
|
];
|
|
980
1038
|
}
|
|
1039
|
+
else {
|
|
1040
|
+
const tools = getCurrentTools(context.messages);
|
|
1041
|
+
if (tools.length > 0) {
|
|
1042
|
+
params.tools = convertTools(tools, isOAuthToken, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, toolCacheControl);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
981
1045
|
// Managed effort models always use adaptive thinking. Their per-turn markers
|
|
982
1046
|
// carry the actual effort; the top-level high value deliberately stays stable.
|
|
983
1047
|
if (supportsMidConvoEffort(model)) {
|
|
@@ -1082,41 +1146,54 @@ function buildParams(model, context, isOAuthToken, options) {
|
|
|
1082
1146
|
function normalizeToolCallId(id) {
|
|
1083
1147
|
return id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
1084
1148
|
}
|
|
1085
|
-
function convertToolResult(msg
|
|
1086
|
-
const references = [];
|
|
1087
|
-
for (const name of msg.addedToolNames ?? []) {
|
|
1088
|
-
const normalizedName = normalizeToolName(name);
|
|
1089
|
-
if (!deferredToolNames.has(normalizedName) || loadedToolNames.has(normalizedName))
|
|
1090
|
-
continue;
|
|
1091
|
-
loadedToolNames.add(normalizedName);
|
|
1092
|
-
references.push({
|
|
1093
|
-
type: "tool_reference",
|
|
1094
|
-
tool_name: isOAuthToken ? toClaudeCodeName(name) : name,
|
|
1095
|
-
});
|
|
1096
|
-
}
|
|
1097
|
-
const convertedContent = convertContentBlocks(msg.content);
|
|
1098
|
-
// Anthropic rejects tool references mixed with ordinary tool-result content.
|
|
1149
|
+
function convertToolResult(msg) {
|
|
1099
1150
|
return {
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
is_error: msg.isError,
|
|
1105
|
-
},
|
|
1106
|
-
siblingContent: references.length === 0
|
|
1107
|
-
? []
|
|
1108
|
-
: typeof convertedContent === "string"
|
|
1109
|
-
? [{ type: "text", text: convertedContent }]
|
|
1110
|
-
: convertedContent,
|
|
1151
|
+
type: "tool_result",
|
|
1152
|
+
tool_use_id: msg.toolCallId,
|
|
1153
|
+
content: convertContentBlocks(msg.content),
|
|
1154
|
+
is_error: msg.isError,
|
|
1111
1155
|
};
|
|
1112
1156
|
}
|
|
1113
|
-
function convertMessages(transformedMessages, isOAuthToken, cacheControl, allowEmptySignature = false,
|
|
1157
|
+
function convertMessages(transformedMessages, isOAuthToken, cacheControl, allowEmptySignature = false, managedProvider, nativeToolChanges = false) {
|
|
1114
1158
|
const params = [];
|
|
1115
1159
|
const assistantLevels = new Map();
|
|
1116
|
-
|
|
1160
|
+
// Later system messages are held back and emitted directly before the next assistant
|
|
1161
|
+
// message (or at the end of the transcript). Anthropic requires `tool_result` blocks to
|
|
1162
|
+
// immediately follow their `tool_use`, so a system message between them is rejected; this
|
|
1163
|
+
// also mirrors where the managed-effort system messages are inserted. As a result an
|
|
1164
|
+
// update placed before a user message in the transcript lands after it on the wire.
|
|
1165
|
+
const pendingSystemMessages = [];
|
|
1166
|
+
const flushPendingSystemMessages = () => {
|
|
1167
|
+
params.push(...pendingSystemMessages);
|
|
1168
|
+
pendingSystemMessages.length = 0;
|
|
1169
|
+
};
|
|
1117
1170
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
1118
1171
|
const msg = transformedMessages[i];
|
|
1119
|
-
if (msg.role === "
|
|
1172
|
+
if (msg.role === "system") {
|
|
1173
|
+
// Later system messages only reach this point when the model accepts them natively;
|
|
1174
|
+
// otherwise the transcript was collapsed into the leading message before conversion.
|
|
1175
|
+
const text = renderSystemMessageUpdate(msg);
|
|
1176
|
+
const blocks = [];
|
|
1177
|
+
if (text.length > 0)
|
|
1178
|
+
blocks.push({ type: "text", text: sanitizeSurrogates(text) });
|
|
1179
|
+
if (nativeToolChanges) {
|
|
1180
|
+
for (const tool of msg.toolsRemoved ?? []) {
|
|
1181
|
+
blocks.push({
|
|
1182
|
+
type: "tool_removal",
|
|
1183
|
+
tool: { type: "tool_reference", name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name },
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
for (const tool of msg.toolsAdded ?? []) {
|
|
1187
|
+
blocks.push({
|
|
1188
|
+
type: "tool_addition",
|
|
1189
|
+
tool: { type: "tool_reference", name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name },
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
if (blocks.length > 0)
|
|
1194
|
+
pendingSystemMessages.push({ role: "system", content: blocks });
|
|
1195
|
+
}
|
|
1196
|
+
else if (msg.role === "user") {
|
|
1120
1197
|
if (typeof msg.content === "string") {
|
|
1121
1198
|
if (msg.content.trim().length > 0) {
|
|
1122
1199
|
params.push({
|
|
@@ -1173,6 +1250,7 @@ function convertMessages(transformedMessages, isOAuthToken, cacheControl, allowE
|
|
|
1173
1250
|
}
|
|
1174
1251
|
}
|
|
1175
1252
|
else if (msg.role === "assistant") {
|
|
1253
|
+
flushPendingSystemMessages();
|
|
1176
1254
|
const blocks = [];
|
|
1177
1255
|
for (const block of msg.content) {
|
|
1178
1256
|
if (block.type === "text") {
|
|
@@ -1261,31 +1339,32 @@ function convertMessages(transformedMessages, isOAuthToken, cacheControl, allowE
|
|
|
1261
1339
|
else if (msg.role === "toolResult") {
|
|
1262
1340
|
// Collect all consecutive toolResult messages, needed for z.ai Anthropic endpoint.
|
|
1263
1341
|
const toolResults = [];
|
|
1264
|
-
const siblingContent = [];
|
|
1265
1342
|
let j = i;
|
|
1266
1343
|
while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
|
|
1267
|
-
|
|
1268
|
-
toolResults.push(converted.toolResult);
|
|
1269
|
-
siblingContent.push(...converted.siblingContent);
|
|
1344
|
+
toolResults.push(convertToolResult(transformedMessages[j]));
|
|
1270
1345
|
j++;
|
|
1271
1346
|
}
|
|
1272
1347
|
// Skip the messages we've already processed.
|
|
1273
1348
|
i = j - 1;
|
|
1274
|
-
// Displaced reference-bearing results must follow every tool_result block.
|
|
1275
1349
|
params.push({
|
|
1276
1350
|
role: "user",
|
|
1277
|
-
content:
|
|
1351
|
+
content: toolResults,
|
|
1278
1352
|
});
|
|
1279
1353
|
}
|
|
1280
1354
|
}
|
|
1281
|
-
|
|
1355
|
+
flushPendingSystemMessages();
|
|
1356
|
+
// Add cache_control to the last user or system message to cache conversation history
|
|
1282
1357
|
if (cacheControl && params.length > 0) {
|
|
1283
1358
|
const lastMessage = params[params.length - 1];
|
|
1284
|
-
if (lastMessage.role === "user") {
|
|
1359
|
+
if (lastMessage.role === "user" || lastMessage.role === "system") {
|
|
1285
1360
|
if (Array.isArray(lastMessage.content)) {
|
|
1286
1361
|
const lastBlock = lastMessage.content[lastMessage.content.length - 1];
|
|
1287
1362
|
if (lastBlock &&
|
|
1288
|
-
(lastBlock.type === "text" ||
|
|
1363
|
+
(lastBlock.type === "text" ||
|
|
1364
|
+
lastBlock.type === "image" ||
|
|
1365
|
+
lastBlock.type === "tool_result" ||
|
|
1366
|
+
lastBlock.type === "tool_addition" ||
|
|
1367
|
+
lastBlock.type === "tool_removal")) {
|
|
1289
1368
|
lastBlock.cache_control = cacheControl;
|
|
1290
1369
|
}
|
|
1291
1370
|
}
|
|
@@ -1318,7 +1397,7 @@ function insertThinkingLevelMessages(converted, activeEffort) {
|
|
|
1318
1397
|
return messages;
|
|
1319
1398
|
}
|
|
1320
1399
|
function shouldUseFineGrainedToolStreamingBeta(model, context) {
|
|
1321
|
-
return
|
|
1400
|
+
return getCurrentTools(context.messages).length > 0 && !getAnthropicCompat(model).supportsEagerToolInputStreaming;
|
|
1322
1401
|
}
|
|
1323
1402
|
function projectObjectUnionForAnthropic(schema) {
|
|
1324
1403
|
if (schema.properties !== undefined || !Array.isArray(schema.anyOf) || schema.anyOf.length === 0)
|
|
@@ -1354,9 +1433,13 @@ function projectObjectUnionForAnthropic(schema) {
|
|
|
1354
1433
|
required: (branches[0]?.required ?? []).filter((key) => branches.every((branch) => (branch.required ?? []).includes(key))),
|
|
1355
1434
|
};
|
|
1356
1435
|
}
|
|
1357
|
-
function convertTools(tools, isOAuthToken, supportsEagerToolInputStreaming, supportsStrictTools, cacheControl
|
|
1436
|
+
function convertTools(tools, isOAuthToken, supportsEagerToolInputStreaming, supportsStrictTools, cacheControl) {
|
|
1358
1437
|
if (!tools)
|
|
1359
1438
|
return [];
|
|
1439
|
+
// OAuth canonicalization can make distinct transcript names collide. Keep the latest
|
|
1440
|
+
// declaration, as the pre-transcript tool serializer did, without sending duplicate names.
|
|
1441
|
+
if (isOAuthToken)
|
|
1442
|
+
tools = [...new Map(tools.map((tool) => [toClaudeCodeName(tool.name), tool])).values()];
|
|
1360
1443
|
return tools.map((tool, index) => {
|
|
1361
1444
|
const strict = resolveJsonSchemaStrictSampling(tool, supportsStrictTools);
|
|
1362
1445
|
const parameters = getJsonSchemaToolParameters(tool, strict);
|
|
@@ -1381,7 +1464,6 @@ function convertTools(tools, isOAuthToken, supportsEagerToolInputStreaming, supp
|
|
|
1381
1464
|
...(supportsEagerToolInputStreaming ? { eager_input_streaming: true } : {}),
|
|
1382
1465
|
...(strict === true ? { strict: true } : {}),
|
|
1383
1466
|
input_schema: inputSchema,
|
|
1384
|
-
...(deferLoading ? { defer_loading: true } : {}),
|
|
1385
1467
|
...(cacheControl && index === tools.length - 1 ? { cache_control: cacheControl } : {}),
|
|
1386
1468
|
};
|
|
1387
1469
|
});
|