@code-yeongyu/senpi-ai 2026.10.30-2 → 2026.10.31-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/anthropic-messages.d.ts +13 -3
- package/dist/api/anthropic-messages.js +62 -185
- package/dist/api/anthropic-system-blocks.d.ts +12 -0
- package/dist/api/anthropic-system-blocks.js +35 -0
- package/dist/api/openai-completions.js +19 -2
- package/dist/auth/helpers.d.ts +1 -0
- package/dist/auth/helpers.js +1 -0
- package/dist/auth/oauth/load.d.ts +0 -2
- package/dist/auth/oauth/load.js +0 -5
- package/dist/auth/pool/slots.d.ts +11 -1
- package/dist/auth/pool/slots.js +63 -1
- package/dist/auth/types.d.ts +7 -0
- package/dist/bun-oauth.js +0 -2
- package/dist/compat/extension-oauth-types.d.ts +1 -0
- package/dist/models.js +1 -1
- package/dist/oauth.d.ts +1 -1
- package/dist/oauth.js +1 -1
- package/dist/providers/anthropic.js +2 -1
- package/dist/providers/chatgpt-subscription.js +2 -0
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/cloudflare-ai-gateway.json +1 -1
- package/dist/providers/data/opengateway.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/venice.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/utils/chatgpt-subscription-auth.d.ts +7 -0
- package/dist/utils/chatgpt-subscription-auth.js +21 -4
- package/dist/utils/prompt-cache-ttl.d.ts +2 -1
- package/dist/utils/prompt-cache-ttl.js +2 -0
- package/dist/utils/retry-hint.d.ts +3 -1
- package/dist/utils/retry-hint.js +80 -2
- package/dist/utils/tool-schema-compat.js +35 -0
- package/dist/utils/transcript.d.ts +1 -1
- package/dist/utils/transcript.js +12 -2
- package/dist/utils/validation.js +111 -4
- package/package.json +2 -2
- package/dist/auth/oauth/anthropic-callback-listener.d.ts +0 -40
- package/dist/auth/oauth/anthropic-callback-listener.js +0 -138
- package/dist/auth/oauth/anthropic.d.ts +0 -13
- package/dist/auth/oauth/anthropic.js +0 -285
- package/dist/auth/oauth/authorization-input.d.ts +0 -6
- package/dist/auth/oauth/authorization-input.js +0 -29
- package/dist/auth/oauth/error-details.d.ts +0 -3
- package/dist/auth/oauth/error-details.js +0 -20
- package/dist/utils/claude-code-version-cache.d.ts +0 -12
- package/dist/utils/claude-code-version-cache.js +0 -60
- package/dist/utils/claude-code-version.d.ts +0 -78
- package/dist/utils/claude-code-version.js +0 -203
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import Anthropic from "@anthropic-ai/sdk";
|
|
2
2
|
import type { MessageCreateParamsNonStreaming } from "@anthropic-ai/sdk/resources/beta/messages/messages.js";
|
|
3
|
-
import type { AnthropicRefusalFallback, Context, Model, SimpleStreamOptions, StreamFunction, StreamOptions
|
|
3
|
+
import type { AnthropicRefusalFallback, Context, Model, SimpleStreamOptions, StreamFunction, StreamOptions } from "../types.ts";
|
|
4
4
|
export { getAnthropicCompat } from "../utils/prompt-cache-ttl.ts";
|
|
5
|
-
export declare const toClaudeCodeName: (name: string) => string;
|
|
6
|
-
export declare const fromClaudeCodeName: (name: string, tools?: Tool[]) => string;
|
|
7
5
|
export type AnthropicEffort = "low" | "medium" | "high" | "xhigh" | "max";
|
|
8
6
|
export type AnthropicThinkingDisplay = "summarized" | "omitted";
|
|
9
7
|
export interface AnthropicOptions extends StreamOptions {
|
|
@@ -72,6 +70,18 @@ export interface AnthropicOptions extends StreamOptions {
|
|
|
72
70
|
*/
|
|
73
71
|
client?: Anthropic;
|
|
74
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* A Claude OAuth token (`sk-ant-oat...`) offered as an API key. senpi no longer sends such a token
|
|
75
|
+
* to the Messages API while presenting itself as Claude Code (senpi#5131); the subscription path is
|
|
76
|
+
* the `anthropic-subscription` provider, which runs the official Claude Code CLI.
|
|
77
|
+
*/
|
|
78
|
+
export declare class ClaudeOAuthTokenRefusedError extends Error {
|
|
79
|
+
readonly code = "claude_oauth_token_refused";
|
|
80
|
+
readonly provider: string;
|
|
81
|
+
readonly modelId: string;
|
|
82
|
+
constructor(provider: string, modelId: string);
|
|
83
|
+
}
|
|
84
|
+
export declare function isClaudeOAuthTokenRefusedError(error: unknown): error is ClaudeOAuthTokenRefusedError;
|
|
75
85
|
export declare const stream: StreamFunction<"anthropic-messages", AnthropicOptions>;
|
|
76
86
|
export declare const streamSimple: StreamFunction<"anthropic-messages", SimpleStreamOptions>;
|
|
77
87
|
export declare function buildAnthropicWarmPromptCacheParams(model: Model<"anthropic-messages">, context: Context, options?: AnthropicOptions): MessageCreateParamsNonStreaming;
|
|
@@ -6,7 +6,6 @@ import { registerSessionResourceCleanup } from "../session-resources.js";
|
|
|
6
6
|
import { isVideoMimeType } from "../types.js";
|
|
7
7
|
import { combineAbortSignals } from "../utils/abort-signals.js";
|
|
8
8
|
import { pushAssistantProgress } from "../utils/assistant-capture.js";
|
|
9
|
-
import { claudeCodeVersionTooOldHint, getClaudeCodeVersion, isClaudeCodeVersionTooOldError, recoverClaudeCodeVersion, } from "../utils/claude-code-version.js";
|
|
10
9
|
import { splitDeferredTools } from "../utils/deferred-tools.js";
|
|
11
10
|
import { appendAssistantMessageDiagnostic } from "../utils/diagnostics.js";
|
|
12
11
|
import { AssistantMessageEventStream } from "../utils/event-stream.js";
|
|
@@ -23,6 +22,7 @@ import { retryProviderRequest } from "../utils/provider-retry.js";
|
|
|
23
22
|
import { appendRetryAfterMsMarker, extract429RetryAfterMs } from "../utils/retry-hint.js";
|
|
24
23
|
import { normalizeAnthropicRetryFailure } from "../utils/retry-profile/failure.js";
|
|
25
24
|
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
25
|
+
import { anthropicSystemTextBlocks } from "./anthropic-system-blocks.js";
|
|
26
26
|
import { applyServerFallbackAbort, applyServerFallbackContinuation, parseServerFallbackReceipt, parseStickyFallbackReceipt, } from "../utils/server-fallback-receipt.js";
|
|
27
27
|
import { getSystemMessageText, renderSystemMessageUpdate } from "../utils/text.js";
|
|
28
28
|
import { normalizeToolCallId } from "../utils/tool-call-id.js";
|
|
@@ -72,49 +72,6 @@ function getCacheControl(model, cacheRetention, env) {
|
|
|
72
72
|
cacheControl: { type: "ephemeral", ...(ttl && { ttl }) },
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
-
// Stealth mode: Mimic Claude Code's identity and tool naming exactly.
|
|
76
|
-
// The bundled Claude Code version and the floor of the advertised `claude-cli/<version>`
|
|
77
|
-
// (see utils/claude-code-version.ts). Keep this exact declaration: a downstream installer
|
|
78
|
-
// (oh-my-openagent) rewrites it byte-for-byte in the installed dist and bundle.
|
|
79
|
-
const claudeCodeVersion = "2.1.306";
|
|
80
|
-
// Claude Code 2.x tool names (canonical casing)
|
|
81
|
-
// Source: https://cchistory.mariozechner.at/data/prompts-2.1.11.md
|
|
82
|
-
// To update: https://github.com/badlogic/cchistory
|
|
83
|
-
const claudeCodeTools = [
|
|
84
|
-
"Read",
|
|
85
|
-
"Write",
|
|
86
|
-
"Edit",
|
|
87
|
-
"Bash",
|
|
88
|
-
"Grep",
|
|
89
|
-
"Glob",
|
|
90
|
-
"AskUserQuestion",
|
|
91
|
-
"EnterPlanMode",
|
|
92
|
-
"ExitPlanMode",
|
|
93
|
-
"KillShell",
|
|
94
|
-
"NotebookEdit",
|
|
95
|
-
"Skill",
|
|
96
|
-
"Task",
|
|
97
|
-
"TaskOutput",
|
|
98
|
-
"TodoWrite",
|
|
99
|
-
"WebFetch",
|
|
100
|
-
"WebSearch",
|
|
101
|
-
];
|
|
102
|
-
const ccToolLookup = new Map(claudeCodeTools.map((t) => [t.toLowerCase(), t]));
|
|
103
|
-
const ccToolAliases = new Map([["ask_user_question", "AskUserQuestion"]]);
|
|
104
|
-
// Convert tool name to CC canonical casing if it matches (case-insensitive)
|
|
105
|
-
export const toClaudeCodeName = (name) => ccToolAliases.get(name) ?? ccToolLookup.get(name.toLowerCase()) ?? name;
|
|
106
|
-
export const fromClaudeCodeName = (name, tools) => {
|
|
107
|
-
if (tools && tools.length > 0) {
|
|
108
|
-
const alias = [...ccToolAliases].find(([, wireName]) => wireName === name);
|
|
109
|
-
if (alias && tools.some((tool) => tool.name === alias[0]))
|
|
110
|
-
return alias[0];
|
|
111
|
-
const lowerName = name.toLowerCase();
|
|
112
|
-
const matchedTool = tools.find((tool) => tool.name.toLowerCase() === lowerName);
|
|
113
|
-
if (matchedTool)
|
|
114
|
-
return matchedTool.name;
|
|
115
|
-
}
|
|
116
|
-
return name;
|
|
117
|
-
};
|
|
118
75
|
function convertContentBlocks(content) {
|
|
119
76
|
// If only text blocks, return as concatenated string for simplicity
|
|
120
77
|
const hasImages = content.some((c) => c.type === "image");
|
|
@@ -322,6 +279,28 @@ function assertRequestAuth(provider, apiKey, headers) {
|
|
|
322
279
|
if (!hasRequestAuth(apiKey, headers))
|
|
323
280
|
throw new Error(`No API key for provider: ${provider}`);
|
|
324
281
|
}
|
|
282
|
+
const CLAUDE_OAUTH_TOKEN_MARKER = "sk-ant-oat";
|
|
283
|
+
/**
|
|
284
|
+
* A Claude OAuth token (`sk-ant-oat...`) offered as an API key. senpi no longer sends such a token
|
|
285
|
+
* to the Messages API while presenting itself as Claude Code (senpi#5131); the subscription path is
|
|
286
|
+
* the `anthropic-subscription` provider, which runs the official Claude Code CLI.
|
|
287
|
+
*/
|
|
288
|
+
export class ClaudeOAuthTokenRefusedError extends Error {
|
|
289
|
+
constructor(provider, modelId) {
|
|
290
|
+
super(`${provider}/${modelId}: a Claude OAuth token (${CLAUDE_OAUTH_TOKEN_MARKER}...) is not accepted as an API key; senpi does not send Claude subscription tokens to the Anthropic API directly. For a Claude Pro/Max subscription sign in with /login anthropic-subscription (or set CLAUDE_CODE_OAUTH_TOKEN) and use anthropic-subscription/${modelId}; otherwise use an Anthropic API key.`);
|
|
291
|
+
this.code = "claude_oauth_token_refused";
|
|
292
|
+
this.name = "ClaudeOAuthTokenRefusedError";
|
|
293
|
+
this.provider = provider;
|
|
294
|
+
this.modelId = modelId;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
export function isClaudeOAuthTokenRefusedError(error) {
|
|
298
|
+
return error instanceof ClaudeOAuthTokenRefusedError;
|
|
299
|
+
}
|
|
300
|
+
function assertNotClaudeOAuthToken(model, apiKey) {
|
|
301
|
+
if (apiKey?.includes(CLAUDE_OAUTH_TOKEN_MARKER))
|
|
302
|
+
throw new ClaudeOAuthTokenRefusedError(model.provider, model.id);
|
|
303
|
+
}
|
|
325
304
|
/**
|
|
326
305
|
* Anthropic SDK client that never runs the SDK's own credential chain
|
|
327
306
|
* (ANTHROPIC_PROFILE config files, federation env vars). Without this, every
|
|
@@ -409,7 +388,7 @@ function userMessageClosesServerTurn(message) {
|
|
|
409
388
|
return message.content.trim().length > 0;
|
|
410
389
|
return message.content.some((block) => (block.type === "text" && block.text.trim().length > 0) || block.type === "image");
|
|
411
390
|
}
|
|
412
|
-
function collectProviderNativeToolPairing(messages, model, deferredToolNames,
|
|
391
|
+
function collectProviderNativeToolPairing(messages, model, deferredToolNames, discardedFallbackToolCallIds) {
|
|
413
392
|
const resolvedUseIds = new Set();
|
|
414
393
|
const validResultIds = new Set();
|
|
415
394
|
// Uses whose turn can still be resumed. A same-model assistant resets the
|
|
@@ -461,10 +440,9 @@ function collectProviderNativeToolPairing(messages, model, deferredToolNames, no
|
|
|
461
440
|
// and the pending use resumable.
|
|
462
441
|
let emitsReferences = false;
|
|
463
442
|
for (const name of message.addedToolNames ?? []) {
|
|
464
|
-
|
|
465
|
-
if (!deferredToolNames.has(normalizedName) || loadedReferenceNames.has(normalizedName))
|
|
443
|
+
if (!deferredToolNames.has(name) || loadedReferenceNames.has(name))
|
|
466
444
|
continue;
|
|
467
|
-
loadedReferenceNames.add(
|
|
445
|
+
loadedReferenceNames.add(name);
|
|
468
446
|
emitsReferences = true;
|
|
469
447
|
}
|
|
470
448
|
if (emitsReferences)
|
|
@@ -925,7 +903,6 @@ async function* iterateAnthropicEvents(response, signal, onTransportActivity) {
|
|
|
925
903
|
export const stream = (model, context, options) => {
|
|
926
904
|
const stream = new AssistantMessageEventStream({ captureBlocks: true });
|
|
927
905
|
const normalizedContext = resolveTranscript(context, supportsMidConvoSystemMessages(model));
|
|
928
|
-
const currentTools = getCurrentTools(normalizedContext.messages);
|
|
929
906
|
(async () => {
|
|
930
907
|
const providerThinkingLevel = managedEffortForRequest(model, options);
|
|
931
908
|
const output = {
|
|
@@ -952,8 +929,6 @@ export const stream = (model, context, options) => {
|
|
|
952
929
|
const requestSignal = combinedAbort.signal;
|
|
953
930
|
try {
|
|
954
931
|
let client;
|
|
955
|
-
let isOAuth = false;
|
|
956
|
-
let advertisedClaudeCodeVersion;
|
|
957
932
|
let usageModel = model;
|
|
958
933
|
let inputTransformations;
|
|
959
934
|
let openClient;
|
|
@@ -966,6 +941,7 @@ export const stream = (model, context, options) => {
|
|
|
966
941
|
const federation = getAnthropicFederation(model, apiKey, optionsHeaders, options?.env);
|
|
967
942
|
if (!federation)
|
|
968
943
|
assertRequestAuth(model.provider, apiKey, optionsHeaders);
|
|
944
|
+
assertNotClaudeOAuthToken(model, apiKey);
|
|
969
945
|
let copilotDynamicHeaders;
|
|
970
946
|
if (model.provider === "github-copilot") {
|
|
971
947
|
const hasImages = hasCopilotVisionInput(normalizedContext.messages);
|
|
@@ -977,37 +953,12 @@ export const stream = (model, context, options) => {
|
|
|
977
953
|
const cacheRetention = resolveCacheRetention(options?.cacheRetention ?? model.cacheRetention, options?.env, "short");
|
|
978
954
|
const cacheSessionId = cacheRetention === "none" ? undefined : options?.sessionId;
|
|
979
955
|
openClient = () => {
|
|
980
|
-
|
|
956
|
+
client = createClient(model, apiKey, options?.interleavedThinking ?? true, shouldUseFineGrainedToolStreamingBeta(model, normalizedContext), options?.refusalFallbacks !== undefined && configuredBetaHeader(model, options) !== null, optionsHeaders, getAnthropicCompat(model).supportsGzipRequestBody
|
|
981
957
|
? withGzipRequestBodies(options?.fetch)
|
|
982
958
|
: options?.fetch, copilotDynamicHeaders, cacheSessionId, options?.env, federation);
|
|
983
|
-
client = created.client;
|
|
984
|
-
isOAuth = created.isOAuthToken;
|
|
985
|
-
advertisedClaudeCodeVersion = created.claudeCodeVersion;
|
|
986
959
|
};
|
|
987
960
|
openClient();
|
|
988
961
|
}
|
|
989
|
-
// One retry per request: a `claude_code_version_too_old` 400 names the version Anthropic
|
|
990
|
-
// wants, so the fingerprint is raised and the same request goes out again with it.
|
|
991
|
-
let claudeCodeVersionRetried = false;
|
|
992
|
-
const retryWithNewerClaudeCode = async (error) => {
|
|
993
|
-
if (claudeCodeVersionRetried ||
|
|
994
|
-
openClient === undefined ||
|
|
995
|
-
advertisedClaudeCodeVersion === undefined ||
|
|
996
|
-
!isClaudeCodeVersionTooOldError(error)) {
|
|
997
|
-
return false;
|
|
998
|
-
}
|
|
999
|
-
const next = await recoverClaudeCodeVersion(error, claudeCodeVersion, advertisedClaudeCodeVersion, options?.env);
|
|
1000
|
-
if (next === undefined)
|
|
1001
|
-
return false;
|
|
1002
|
-
claudeCodeVersionRetried = true;
|
|
1003
|
-
openClient();
|
|
1004
|
-
return true;
|
|
1005
|
-
};
|
|
1006
|
-
const noteTooOldClaudeCode = (error) => {
|
|
1007
|
-
if (advertisedClaudeCodeVersion !== undefined && isClaudeCodeVersionTooOldError(error)) {
|
|
1008
|
-
error.message = `${error.message}\n${claudeCodeVersionTooOldHint(advertisedClaudeCodeVersion)}`;
|
|
1009
|
-
}
|
|
1010
|
-
};
|
|
1011
962
|
const fallbackKey = unsignedThinkingFallbackKey(model, options?.sessionId);
|
|
1012
963
|
let unsignedThinkingReplay = fallbackKey && unsignedThinkingTextReplayFallbacks.has(fallbackKey)
|
|
1013
964
|
? "text"
|
|
@@ -1024,7 +975,7 @@ export const stream = (model, context, options) => {
|
|
|
1024
975
|
}
|
|
1025
976
|
let lastSentParams;
|
|
1026
977
|
const createRequest = async () => {
|
|
1027
|
-
let params = buildParams(model, normalizedContext,
|
|
978
|
+
let params = buildParams(model, normalizedContext, options, unsignedThinkingReplay);
|
|
1028
979
|
const nextParams = await options?.onPayload?.(params, model);
|
|
1029
980
|
if (nextParams !== undefined) {
|
|
1030
981
|
params = nextParams;
|
|
@@ -1109,16 +1060,6 @@ export const stream = (model, context, options) => {
|
|
|
1109
1060
|
}
|
|
1110
1061
|
if (markNewlyExpiredSearches(error))
|
|
1111
1062
|
return createRequestDemotingExpiredSearches();
|
|
1112
|
-
if (await retryWithNewerClaudeCode(error)) {
|
|
1113
|
-
try {
|
|
1114
|
-
return await createRequest();
|
|
1115
|
-
}
|
|
1116
|
-
catch (retryError) {
|
|
1117
|
-
noteTooOldClaudeCode(retryError);
|
|
1118
|
-
throw retryError;
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
noteTooOldClaudeCode(error);
|
|
1122
1063
|
throw error;
|
|
1123
1064
|
}
|
|
1124
1065
|
}, {
|
|
@@ -1231,9 +1172,7 @@ export const stream = (model, context, options) => {
|
|
|
1231
1172
|
const block = {
|
|
1232
1173
|
type: "toolCall",
|
|
1233
1174
|
id: event.content_block.id,
|
|
1234
|
-
name:
|
|
1235
|
-
? fromClaudeCodeName(event.content_block.name, currentTools)
|
|
1236
|
-
: event.content_block.name,
|
|
1175
|
+
name: event.content_block.name,
|
|
1237
1176
|
arguments: isRecord(event.content_block.input)
|
|
1238
1177
|
? event.content_block.input
|
|
1239
1178
|
: {},
|
|
@@ -1593,6 +1532,7 @@ export const streamSimple = (model, context, options) => {
|
|
|
1593
1532
|
if (!getAnthropicFederation(model, apiKey, optionsHeaders, options?.env)) {
|
|
1594
1533
|
assertRequestAuth(model.provider, apiKey, optionsHeaders);
|
|
1595
1534
|
}
|
|
1535
|
+
assertNotClaudeOAuthToken(model, apiKey);
|
|
1596
1536
|
const base = {
|
|
1597
1537
|
...buildBaseOptions(model, context, options, options?.apiKey),
|
|
1598
1538
|
toolChoice: options?.toolChoice,
|
|
@@ -1624,9 +1564,6 @@ export const streamSimple = (model, context, options) => {
|
|
|
1624
1564
|
thinkingBudgetTokens: Math.min(adjusted.thinkingBudget, Math.max(0, maxTokens - 1024)),
|
|
1625
1565
|
});
|
|
1626
1566
|
};
|
|
1627
|
-
function isOAuthToken(apiKey) {
|
|
1628
|
-
return apiKey.includes("sk-ant-oat");
|
|
1629
|
-
}
|
|
1630
1567
|
function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStreamingBeta, useServerSideFallbackBeta, optionsHeaders, fetch, dynamicHeaders, sessionId, env, federation) {
|
|
1631
1568
|
// Adaptive thinking models have interleaved thinking built in, so skip the beta header.
|
|
1632
1569
|
const needsInterleavedBeta = interleavedThinking && !supportsAdaptiveThinking(model);
|
|
@@ -1656,7 +1593,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
1656
1593
|
...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
|
|
1657
1594
|
}, model.headers, optionsHeaders)),
|
|
1658
1595
|
});
|
|
1659
|
-
return
|
|
1596
|
+
return client;
|
|
1660
1597
|
}
|
|
1661
1598
|
// Copilot: Bearer auth, selective betas.
|
|
1662
1599
|
if (model.provider === "github-copilot") {
|
|
@@ -1672,26 +1609,7 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
1672
1609
|
...(betaFeatures.length > 0 ? { "anthropic-beta": betaFeatures.join(",") } : {}),
|
|
1673
1610
|
}, model.headers, dynamicHeaders, optionsHeaders)),
|
|
1674
1611
|
});
|
|
1675
|
-
return
|
|
1676
|
-
}
|
|
1677
|
-
// OAuth: Bearer auth, Claude Code identity headers
|
|
1678
|
-
if (apiKey && isOAuthToken(apiKey)) {
|
|
1679
|
-
const advertisedClaudeCodeVersion = getClaudeCodeVersion(claudeCodeVersion, env);
|
|
1680
|
-
const client = new PiAnthropic({
|
|
1681
|
-
apiKey: null,
|
|
1682
|
-
authToken: apiKey,
|
|
1683
|
-
baseURL: model.baseUrl,
|
|
1684
|
-
dangerouslyAllowBrowser: true,
|
|
1685
|
-
fetch,
|
|
1686
|
-
defaultHeaders: sanitizeAdaptiveThinkingHeaders(model, mergeClientHeaders(model, {
|
|
1687
|
-
accept: "application/json",
|
|
1688
|
-
"anthropic-dangerous-direct-browser-access": "true",
|
|
1689
|
-
"anthropic-beta": ["claude-code-20250219", "oauth-2025-04-20", ...betaFeatures].join(","),
|
|
1690
|
-
"user-agent": `claude-cli/${advertisedClaudeCodeVersion}`,
|
|
1691
|
-
"x-app": "cli",
|
|
1692
|
-
}, model.headers, optionsHeaders)),
|
|
1693
|
-
});
|
|
1694
|
-
return { client, isOAuthToken: true, claudeCodeVersion: advertisedClaudeCodeVersion };
|
|
1612
|
+
return client;
|
|
1695
1613
|
}
|
|
1696
1614
|
// API key, header-owned auth, or workload identity federation.
|
|
1697
1615
|
const affinityCompat = getAnthropicCompat(model);
|
|
@@ -1720,9 +1638,9 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
1720
1638
|
});
|
|
1721
1639
|
federationClient = { key, fetch, client };
|
|
1722
1640
|
}
|
|
1723
|
-
return
|
|
1641
|
+
return federationClient.client.withOptions({ defaultHeaders });
|
|
1724
1642
|
}
|
|
1725
|
-
|
|
1643
|
+
return new PiAnthropic({
|
|
1726
1644
|
apiKey: apiKey ?? null,
|
|
1727
1645
|
authToken: null,
|
|
1728
1646
|
baseURL: model.baseUrl,
|
|
@@ -1730,13 +1648,12 @@ function createClient(model, apiKey, interleavedThinking, useFineGrainedToolStre
|
|
|
1730
1648
|
fetch,
|
|
1731
1649
|
defaultHeaders,
|
|
1732
1650
|
});
|
|
1733
|
-
return { client, isOAuthToken: false };
|
|
1734
1651
|
}
|
|
1735
1652
|
export function buildAnthropicWarmPromptCacheParams(model, context, options) {
|
|
1736
1653
|
// Public fork entry (warmPromptCache, cache-keepalive): accepts a raw Context and builds
|
|
1737
1654
|
// the same transcript the turn's stream() resolves, so the warmed prefix matches.
|
|
1738
1655
|
const transcript = resolveTranscript(normalizeContext(context), supportsMidConvoSystemMessages(model));
|
|
1739
|
-
const params = buildParams(model, transcript,
|
|
1656
|
+
const params = buildParams(model, transcript, {
|
|
1740
1657
|
...options,
|
|
1741
1658
|
maxTokens: 0,
|
|
1742
1659
|
thinkingEnabled: undefined,
|
|
@@ -1758,14 +1675,12 @@ function configuredBetaHeader(model, options) {
|
|
|
1758
1675
|
}
|
|
1759
1676
|
return configured;
|
|
1760
1677
|
}
|
|
1761
|
-
function getBetaFeatures(model, context,
|
|
1678
|
+
function getBetaFeatures(model, context, shape, options) {
|
|
1762
1679
|
const configured = configuredBetaHeader(model, options);
|
|
1763
1680
|
if (configured === null)
|
|
1764
1681
|
return [];
|
|
1765
1682
|
// Betas the request body depends on: the API rejects the request without them.
|
|
1766
1683
|
const required = [];
|
|
1767
|
-
if (isOAuthToken)
|
|
1768
|
-
required.push("claude-code-20250219", "oauth-2025-04-20");
|
|
1769
1684
|
if (shape.midConvoEffort)
|
|
1770
1685
|
required.push(MID_CONVERSATION_OUTPUT_CONFIG_BETA);
|
|
1771
1686
|
if (shape.thinkingBinding)
|
|
@@ -1800,7 +1715,7 @@ function defaultOptionalBetas(model, context, options) {
|
|
|
1800
1715
|
features.push(SERVER_SIDE_FALLBACK_BETA);
|
|
1801
1716
|
return features;
|
|
1802
1717
|
}
|
|
1803
|
-
function buildParams(model, context,
|
|
1718
|
+
function buildParams(model, context, options, unsignedThinkingReplay = getAnthropicCompat(model).unsignedThinkingReplay) {
|
|
1804
1719
|
const compat = getAnthropicCompat(model);
|
|
1805
1720
|
const { cacheControl } = getCacheControl(model, options?.cacheRetention ?? model.cacheRetention, options?.env);
|
|
1806
1721
|
const initialSystemMessage = getInitialSystemMessage(context.messages);
|
|
@@ -1815,7 +1730,7 @@ function buildParams(model, context, isOAuthToken, options, unsignedThinkingRepl
|
|
|
1815
1730
|
// old boundary (read) and the new one (written for the next step) are marked. Two checkpoints fit
|
|
1816
1731
|
// only when the system block holds one, which then also covers the tools before it (senpi#3242).
|
|
1817
1732
|
const stablePrefixMarkers = conversationMessages.filter((message) => message.role === "assistant" && message.promptCacheBreakpoint === true).length;
|
|
1818
|
-
const systemHoldsCheckpoint =
|
|
1733
|
+
const systemHoldsCheckpoint = initialSystemText.length > 0;
|
|
1819
1734
|
const stablePrefixCheckpointLimit = stablePrefixMarkers >= 2 && systemHoldsCheckpoint ? 2 : Math.min(1, stablePrefixMarkers);
|
|
1820
1735
|
// Native tool changes reference tools by name, so a redefined name cannot be expressed,
|
|
1821
1736
|
// and Anthropic rejects a tool list where every tool is deferred, so there must be an
|
|
@@ -1823,18 +1738,14 @@ function buildParams(model, context, isOAuthToken, options, unsignedThinkingRepl
|
|
|
1823
1738
|
const initialTools = initialSystemMessage?.toolsAdded ?? [];
|
|
1824
1739
|
// A configured `anthropic-beta: null` asks for no betas at all, so the request takes a shape that needs none:
|
|
1825
1740
|
// the current tool list instead of native tool changes, top-level effort instead of per-message markers, and
|
|
1826
|
-
// no server-side fallbacks (senpi#2957).
|
|
1741
|
+
// no server-side fallbacks (senpi#2957).
|
|
1827
1742
|
const betasSuppressed = configuredBetaHeader(model, options) === null;
|
|
1828
|
-
if (betasSuppressed && isOAuthToken) {
|
|
1829
|
-
throw new Error(`The anthropic-beta header is set to null, but ${model.provider}/${model.id} is called with an OAuth token, which needs the claude-code-20250219 and oauth-2025-04-20 betas. Remove the null, or list the betas you want instead; senpi adds the ones a request needs.`);
|
|
1830
|
-
}
|
|
1831
1743
|
const midConvoEffort = model.compat?.supportsMidConvoEffort === true && !betasSuppressed;
|
|
1832
1744
|
const nativeToolChanges = !betasSuppressed &&
|
|
1833
1745
|
supportsMidConvoSystemMessages(model) &&
|
|
1834
1746
|
supportsMidConvoToolChanges(model) &&
|
|
1835
1747
|
initialTools.length > 0 &&
|
|
1836
1748
|
!hasToolRedefinitions(context.messages);
|
|
1837
|
-
const normalizeToolName = isOAuthToken ? toClaudeCodeName : (name) => name;
|
|
1838
1749
|
// A marker on a discarded pre-fallback result must not defer its tool:
|
|
1839
1750
|
// convertMessages drops that result, so no tool_reference would replay to
|
|
1840
1751
|
// load the deferred definition.
|
|
@@ -1845,23 +1756,23 @@ function buildParams(model, context, isOAuthToken, options, unsignedThinkingRepl
|
|
|
1845
1756
|
// `defer_loading` and loaded by a `tool_reference`. Native tool changes own deferral otherwise.
|
|
1846
1757
|
const toolPlacement = nativeToolChanges
|
|
1847
1758
|
? { immediate: [], deferred: new Map() }
|
|
1848
|
-
: splitDeferredTools({ tools: getCurrentTools(context.messages), messages: partitionMessages }, compat.supportsToolReferences
|
|
1759
|
+
: splitDeferredTools({ tools: getCurrentTools(context.messages), messages: partitionMessages }, compat.supportsToolReferences);
|
|
1849
1760
|
let immediateTools = toolPlacement.immediate;
|
|
1850
1761
|
let deferredTools = [...toolPlacement.deferred.values()];
|
|
1851
1762
|
if (immediateTools.length === 0 && deferredTools.length > 0) {
|
|
1852
1763
|
immediateTools = deferredTools;
|
|
1853
1764
|
deferredTools = [];
|
|
1854
1765
|
}
|
|
1855
|
-
const deferredToolNames = new Set(deferredTools.map((tool) =>
|
|
1766
|
+
const deferredToolNames = new Set(deferredTools.map((tool) => tool.name));
|
|
1856
1767
|
const activeEffort = managedEffortForRequest(model, options) ?? "high";
|
|
1857
1768
|
const sendFallbacks = options?.refusalFallbacks !== undefined && !betasSuppressed;
|
|
1858
|
-
const betaFeatures = getBetaFeatures(model, context,
|
|
1769
|
+
const betaFeatures = getBetaFeatures(model, context, {
|
|
1859
1770
|
midConvoEffort,
|
|
1860
1771
|
thinkingBinding: midConvoEffort && options?.thinkingEnabled !== false,
|
|
1861
1772
|
nativeToolChanges,
|
|
1862
1773
|
refusalFallbacks: sendFallbacks,
|
|
1863
1774
|
}, options);
|
|
1864
|
-
const convertedMessages = convertMessages(conversationMessages, model,
|
|
1775
|
+
const convertedMessages = convertMessages(conversationMessages, model, cacheControl, unsignedThinkingReplay, deferredToolNames, midConvoEffort ? model.provider : undefined, nativeToolChanges, stablePrefixCheckpointLimit);
|
|
1865
1776
|
const messages = midConvoEffort
|
|
1866
1777
|
? insertThinkingLevelMessages(convertedMessages, activeEffort)
|
|
1867
1778
|
: convertedMessages.messages;
|
|
@@ -1887,32 +1798,8 @@ function buildParams(model, context, isOAuthToken, options, unsignedThinkingRepl
|
|
|
1887
1798
|
stream: true,
|
|
1888
1799
|
...(betaFeatures.length > 0 ? { betas: betaFeatures } : {}),
|
|
1889
1800
|
};
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
params.system = [
|
|
1893
|
-
{
|
|
1894
|
-
type: "text",
|
|
1895
|
-
text: "You are Claude Code, Anthropic's official CLI for Claude.",
|
|
1896
|
-
...(!initialSystemText && cacheControl ? { cache_control: cacheControl } : {}),
|
|
1897
|
-
},
|
|
1898
|
-
];
|
|
1899
|
-
if (initialSystemText) {
|
|
1900
|
-
params.system.push({
|
|
1901
|
-
type: "text",
|
|
1902
|
-
text: sanitizeSurrogates(initialSystemText),
|
|
1903
|
-
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
1904
|
-
});
|
|
1905
|
-
}
|
|
1906
|
-
}
|
|
1907
|
-
else if (initialSystemText) {
|
|
1908
|
-
// Add cache control to system prompt for non-OAuth tokens
|
|
1909
|
-
params.system = [
|
|
1910
|
-
{
|
|
1911
|
-
type: "text",
|
|
1912
|
-
text: sanitizeSurrogates(initialSystemText),
|
|
1913
|
-
...(cacheControl ? { cache_control: cacheControl } : {}),
|
|
1914
|
-
},
|
|
1915
|
-
];
|
|
1801
|
+
if (initialSystemText) {
|
|
1802
|
+
params.system = anthropicSystemTextBlocks(initialSystemText, initialSystemMessage?.stablePrefix, cacheControl);
|
|
1916
1803
|
}
|
|
1917
1804
|
// Temperature is incompatible with extended thinking and unsupported on Claude Opus 4.7+.
|
|
1918
1805
|
if (options?.temperature !== undefined && !options?.thinkingEnabled && compat.supportsTemperature) {
|
|
@@ -1932,15 +1819,15 @@ function buildParams(model, context, isOAuthToken, options, unsignedThinkingRepl
|
|
|
1932
1819
|
const initialNames = new Set(initialTools.map((tool) => tool.name));
|
|
1933
1820
|
const laterTools = getDeclaredTools(context.messages).filter((tool) => !initialNames.has(tool.name));
|
|
1934
1821
|
params.tools = [
|
|
1935
|
-
...convertTools(initialTools,
|
|
1822
|
+
...convertTools(initialTools, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, toolCacheControl),
|
|
1936
1823
|
DEFERRED_TOOL_PLACEHOLDER,
|
|
1937
|
-
...convertTools(laterTools,
|
|
1824
|
+
...convertTools(laterTools, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, undefined, true),
|
|
1938
1825
|
];
|
|
1939
1826
|
}
|
|
1940
1827
|
else if (immediateTools.length > 0 || deferredTools.length > 0) {
|
|
1941
1828
|
params.tools = [
|
|
1942
|
-
...convertTools(immediateTools,
|
|
1943
|
-
...convertTools(deferredTools,
|
|
1829
|
+
...convertTools(immediateTools, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, toolCacheControl),
|
|
1830
|
+
...convertTools(deferredTools, compat.supportsEagerToolInputStreaming, compat.supportsStrictTools, undefined, true),
|
|
1944
1831
|
];
|
|
1945
1832
|
}
|
|
1946
1833
|
// Managed effort models always use adaptive thinking so prefix mismatches can
|
|
@@ -2061,17 +1948,13 @@ function finalAssistantTurnStartsWithToolUse(messages) {
|
|
|
2061
1948
|
}
|
|
2062
1949
|
return false;
|
|
2063
1950
|
}
|
|
2064
|
-
function convertToolResult(msg,
|
|
1951
|
+
function convertToolResult(msg, deferredToolNames, loadedToolNames) {
|
|
2065
1952
|
const references = [];
|
|
2066
1953
|
for (const name of msg.addedToolNames ?? []) {
|
|
2067
|
-
|
|
2068
|
-
if (!deferredToolNames.has(normalizedName) || loadedToolNames.has(normalizedName))
|
|
1954
|
+
if (!deferredToolNames.has(name) || loadedToolNames.has(name))
|
|
2069
1955
|
continue;
|
|
2070
|
-
loadedToolNames.add(
|
|
2071
|
-
references.push({
|
|
2072
|
-
type: "tool_reference",
|
|
2073
|
-
tool_name: isOAuthToken ? toClaudeCodeName(name) : name,
|
|
2074
|
-
});
|
|
1956
|
+
loadedToolNames.add(name);
|
|
1957
|
+
references.push({ type: "tool_reference", tool_name: name });
|
|
2075
1958
|
}
|
|
2076
1959
|
// The video block variant is not in the SDK's ContentBlockParam union, so the
|
|
2077
1960
|
// converted array is cast through the same escape hatch as tool_reference blocks.
|
|
@@ -2091,7 +1974,7 @@ function convertToolResult(msg, isOAuthToken, deferredToolNames, loadedToolNames
|
|
|
2091
1974
|
: convertedContent,
|
|
2092
1975
|
};
|
|
2093
1976
|
}
|
|
2094
|
-
function convertMessages(transformedMessages, model,
|
|
1977
|
+
function convertMessages(transformedMessages, model, cacheControl, unsignedThinkingReplay = "text", deferredToolNames = new Set(), managedProvider, nativeToolChanges = false, stablePrefixCheckpointLimit = 0) {
|
|
2095
1978
|
const params = [];
|
|
2096
1979
|
const assistantLevels = new Map();
|
|
2097
1980
|
const loadedToolNames = new Set();
|
|
@@ -2110,7 +1993,7 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
2110
1993
|
// assistant turn below; drop their tool_results in lockstep so none dangle.
|
|
2111
1994
|
const discardedFallbackToolCallIds = collectDiscardedFallbackToolCallIds(transformedMessages, model);
|
|
2112
1995
|
const rejectsNativeWebSearchReplay = !getAnthropicCompat(model).supportsWebSearch;
|
|
2113
|
-
const providerNativeToolPairing = collectProviderNativeToolPairing(transformedMessages, model, deferredToolNames,
|
|
1996
|
+
const providerNativeToolPairing = collectProviderNativeToolPairing(transformedMessages, model, deferredToolNames, discardedFallbackToolCallIds);
|
|
2114
1997
|
for (let i = 0; i < transformedMessages.length; i++) {
|
|
2115
1998
|
const msg = transformedMessages[i];
|
|
2116
1999
|
if (msg.role === "system") {
|
|
@@ -2122,16 +2005,10 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
2122
2005
|
blocks.push({ type: "text", text: sanitizeSurrogates(text) });
|
|
2123
2006
|
if (nativeToolChanges) {
|
|
2124
2007
|
for (const tool of msg.toolsRemoved ?? []) {
|
|
2125
|
-
blocks.push({
|
|
2126
|
-
type: "tool_removal",
|
|
2127
|
-
tool: { type: "tool_reference", name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name },
|
|
2128
|
-
});
|
|
2008
|
+
blocks.push({ type: "tool_removal", tool: { type: "tool_reference", name: tool.name } });
|
|
2129
2009
|
}
|
|
2130
2010
|
for (const tool of msg.toolsAdded ?? []) {
|
|
2131
|
-
blocks.push({
|
|
2132
|
-
type: "tool_addition",
|
|
2133
|
-
tool: { type: "tool_reference", name: isOAuthToken ? toClaudeCodeName(tool.name) : tool.name },
|
|
2134
|
-
});
|
|
2011
|
+
blocks.push({ type: "tool_addition", tool: { type: "tool_reference", name: tool.name } });
|
|
2135
2012
|
}
|
|
2136
2013
|
}
|
|
2137
2014
|
if (blocks.length > 0)
|
|
@@ -2262,7 +2139,7 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
2262
2139
|
blocks.push({
|
|
2263
2140
|
type: "tool_use",
|
|
2264
2141
|
id: block.id,
|
|
2265
|
-
name:
|
|
2142
|
+
name: block.name,
|
|
2266
2143
|
input: block.arguments ?? {},
|
|
2267
2144
|
});
|
|
2268
2145
|
}
|
|
@@ -2307,7 +2184,7 @@ function convertMessages(transformedMessages, model, isOAuthToken, cacheControl,
|
|
|
2307
2184
|
while (j < transformedMessages.length && transformedMessages[j].role === "toolResult") {
|
|
2308
2185
|
const nextMsg = transformedMessages[j]; // We know it's a toolResult
|
|
2309
2186
|
if (!discardedFallbackToolCallIds.has(nextMsg.toolCallId)) {
|
|
2310
|
-
const converted = convertToolResult(nextMsg,
|
|
2187
|
+
const converted = convertToolResult(nextMsg, deferredToolNames, loadedToolNames);
|
|
2311
2188
|
toolResults.push(converted.toolResult);
|
|
2312
2189
|
siblingContent.push(...converted.siblingContent);
|
|
2313
2190
|
}
|
|
@@ -2399,7 +2276,7 @@ const isAnthropicStrictUnsupportedKeyword = (key, value) => {
|
|
|
2399
2276
|
return typeof value !== "string" || !ANTHROPIC_STRICT_STRING_FORMATS.has(value);
|
|
2400
2277
|
return false;
|
|
2401
2278
|
};
|
|
2402
|
-
function convertTools(tools,
|
|
2279
|
+
function convertTools(tools, supportsEagerToolInputStreaming, supportsStrictTools, cacheControl, deferLoading = false) {
|
|
2403
2280
|
if (!tools)
|
|
2404
2281
|
return [];
|
|
2405
2282
|
return tools.map((tool, index) => {
|
|
@@ -2420,7 +2297,7 @@ function convertTools(tools, isOAuthToken, supportsEagerToolInputStreaming, supp
|
|
|
2420
2297
|
}
|
|
2421
2298
|
: legacyInputSchema;
|
|
2422
2299
|
return {
|
|
2423
|
-
name:
|
|
2300
|
+
name: tool.name,
|
|
2424
2301
|
description: tool.description,
|
|
2425
2302
|
...(supportsEagerToolInputStreaming ? { eager_input_streaming: true } : {}),
|
|
2426
2303
|
...(strict === true ? { strict: true } : {}),
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BetaCacheControlEphemeral, BetaTextBlockParam as TextBlockParam } from "@anthropic-ai/sdk/resources/beta/messages/messages.js";
|
|
2
|
+
/**
|
|
3
|
+
* The system prompt as Anthropic `system` text blocks (senpi#4447).
|
|
4
|
+
*
|
|
5
|
+
* With a stable prefix, the prompt goes out as two blocks whose concatenation is the prompt: the
|
|
6
|
+
* part that is the same across sessions carries the system cache breakpoint, the part that changes
|
|
7
|
+
* between sessions (memory, MCP instructions) carries none. Another session then reads tools and the
|
|
8
|
+
* stable part from cache even when its tail differs, and the request keeps the same number of
|
|
9
|
+
* breakpoints. The later conversation breakpoint still caches the tail within a session.
|
|
10
|
+
*/
|
|
11
|
+
export declare function anthropicSystemTextBlocks(text: string, stablePrefix: string | undefined, cacheControl: BetaCacheControlEphemeral | undefined): TextBlockParam[];
|
|
12
|
+
//# sourceMappingURL=anthropic-system-blocks.d.ts.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
|
|
2
|
+
const HAS_VISIBLE_TEXT = /\S/;
|
|
3
|
+
/**
|
|
4
|
+
* The system prompt as Anthropic `system` text blocks (senpi#4447).
|
|
5
|
+
*
|
|
6
|
+
* With a stable prefix, the prompt goes out as two blocks whose concatenation is the prompt: the
|
|
7
|
+
* part that is the same across sessions carries the system cache breakpoint, the part that changes
|
|
8
|
+
* between sessions (memory, MCP instructions) carries none. Another session then reads tools and the
|
|
9
|
+
* stable part from cache even when its tail differs, and the request keeps the same number of
|
|
10
|
+
* breakpoints. The later conversation breakpoint still caches the tail within a session.
|
|
11
|
+
*/
|
|
12
|
+
export function anthropicSystemTextBlocks(text, stablePrefix, cacheControl) {
|
|
13
|
+
const marker = cacheControl ? { cache_control: cacheControl } : {};
|
|
14
|
+
const boundary = splitPoint(text, stablePrefix);
|
|
15
|
+
if (boundary === undefined)
|
|
16
|
+
return [{ type: "text", text: sanitizeSurrogates(text), ...marker }];
|
|
17
|
+
return [
|
|
18
|
+
{ type: "text", text: sanitizeSurrogates(text.slice(0, boundary)), ...marker },
|
|
19
|
+
{ type: "text", text: sanitizeSurrogates(text.slice(boundary)) },
|
|
20
|
+
];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The split offset, kept off a surrogate pair. Undefined when the text no longer starts with the prefix
|
|
24
|
+
* (a later rewrite of the prompt) or when either side would have no visible text.
|
|
25
|
+
*/
|
|
26
|
+
function splitPoint(text, stablePrefix) {
|
|
27
|
+
if (stablePrefix === undefined || stablePrefix.length >= text.length || !text.startsWith(stablePrefix))
|
|
28
|
+
return undefined;
|
|
29
|
+
const code = text.charCodeAt(stablePrefix.length - 1);
|
|
30
|
+
const boundary = code >= 0xd800 && code <= 0xdbff ? stablePrefix.length - 1 : stablePrefix.length;
|
|
31
|
+
const stable = text.slice(0, boundary);
|
|
32
|
+
const rest = text.slice(boundary);
|
|
33
|
+
return HAS_VISIBLE_TEXT.test(stable) && HAS_VISIBLE_TEXT.test(rest) ? boundary : undefined;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=anthropic-system-blocks.js.map
|
|
@@ -1500,7 +1500,24 @@ export function convertMessages(model, context, compat, options = {}) {
|
|
|
1500
1500
|
return params;
|
|
1501
1501
|
}
|
|
1502
1502
|
function convertTools(tools, compat) {
|
|
1503
|
-
|
|
1503
|
+
const strictByTool = tools.map((tool) => tool.freeform || resolveGrammarConstrainedSampling(tool, compat.supportsOpenAIGrammarTools)
|
|
1504
|
+
? undefined
|
|
1505
|
+
: resolveJsonSchemaStrictSampling(tool, compat.supportsStrictMode !== false));
|
|
1506
|
+
if (compat.mixedStrictTools === false) {
|
|
1507
|
+
const nonStrictTool = tools.find((tool, index) => !tool.freeform &&
|
|
1508
|
+
!resolveGrammarConstrainedSampling(tool, compat.supportsOpenAIGrammarTools) &&
|
|
1509
|
+
strictByTool[index] !== true);
|
|
1510
|
+
if (nonStrictTool) {
|
|
1511
|
+
const requiredTool = tools.find((tool) => tool.constrainedSampling &&
|
|
1512
|
+
tool.constrainedSampling.type === "json_schema" &&
|
|
1513
|
+
tool.constrainedSampling.strict === "require");
|
|
1514
|
+
if (requiredTool) {
|
|
1515
|
+
throw new Error(`Tool "${requiredTool.name}" requires JSON-schema constrained sampling, but tool "${nonStrictTool.name}" cannot be strict and this provider rejects mixed strict and non-strict tools.`);
|
|
1516
|
+
}
|
|
1517
|
+
strictByTool.fill(undefined);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
return tools.map((tool, index) => {
|
|
1504
1521
|
const grammar = resolveGrammarConstrainedSampling(tool, compat.supportsOpenAIGrammarTools);
|
|
1505
1522
|
if (grammar) {
|
|
1506
1523
|
return {
|
|
@@ -1521,7 +1538,7 @@ function convertTools(tools, compat) {
|
|
|
1521
1538
|
if (tool.freeform) {
|
|
1522
1539
|
throw new Error("Freeform tools cannot be sent to OpenAI Chat Completions; use Responses API");
|
|
1523
1540
|
}
|
|
1524
|
-
const strict =
|
|
1541
|
+
const strict = strictByTool[index];
|
|
1525
1542
|
const schemaParameters = getJsonSchemaToolParameters(tool, strict);
|
|
1526
1543
|
const normalizedParameters = compat.toolSchemaFlavor === "moonshot-mfjs"
|
|
1527
1544
|
? normalizeToolParametersForMoonshot(schemaParameters)
|
package/dist/auth/helpers.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare function lazyOAuth(input: {
|
|
|
18
18
|
isSubscription?: boolean;
|
|
19
19
|
loginLabel?: string;
|
|
20
20
|
rejectedTokenStatuses?: readonly number[];
|
|
21
|
+
accountIdentity?: OAuthAuth["accountIdentity"];
|
|
21
22
|
load: () => Promise<OAuthAuth>;
|
|
22
23
|
}): OAuthAuth;
|
|
23
24
|
//# sourceMappingURL=helpers.d.ts.map
|