@nick3/copilot-api 1.3.8 → 1.4.0

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.
@@ -1,8 +1,8 @@
1
1
  import { PATHS } from "./paths-DoT4SZ8f.js";
2
2
  import { listAccountsFromRegistry } from "./accounts-registry-c7rs5Ed9.js";
3
- import { HTTPError, accountFromState, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getCopilotUsage, getRootSessionId, getUUID, isNullish, prepareForCompact, prepareInteractionHeaders, sleep, state } from "./utils-BaoXuYkx.js";
4
- import "./get-copilot-token-CUT8hpgX.js";
5
- import { PROVIDER_TYPE_ANTHROPIC, accountsManager, getAliasTargetSet, getConfig, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getProviderConfig, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isMessagesApiEnabled, isResponsesApiContextManagementModel, mergeConfigWithDefaults, shouldCompactUseSmallModel } from "./accounts-manager-BGBtDChT.js";
3
+ import { HTTPError, accountFromState, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getCopilotUsage, getRootSessionId, getUUID, isNullish, parseUserIdMetadata, prepareForCompact, prepareInteractionHeaders, sleep, state } from "./utils-D8j9lvS0.js";
4
+ import "./get-copilot-token-BA1FaCgQ.js";
5
+ import { PROVIDER_TYPE_ANTHROPIC, accountsManager, getAliasTargetSet, getConfig, getExtraPromptForModel, getModelAliases, getModelAliasesInfo, getModelRefreshIntervalMs, getProviderConfig, getReasoningEffortForModel, getSmallModel, isForceAgentEnabled, isFreeModelLoadBalancingEnabled, isMessageStartInputTokensFallbackEnabled, isMessagesApiEnabled, isResponsesApiContextManagementModel, mergeConfigWithDefaults, shouldCompactUseSmallModel } from "./accounts-manager-BQCAoBZp.js";
6
6
  import consola from "consola";
7
7
  import fs, { readFile } from "node:fs/promises";
8
8
  import * as path$1 from "node:path";
@@ -2439,570 +2439,108 @@ const getTokenCount = async (payload, model) => {
2439
2439
  };
2440
2440
 
2441
2441
  //#endregion
2442
- //#region src/services/copilot/create-responses.ts
2443
- const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, isCompact }, account) => {
2442
+ //#region src/services/copilot/create-chat-completions.ts
2443
+ function isGpt5MiniFamily(modelId) {
2444
+ return modelId === "gpt-5-mini" || modelId.startsWith("gpt-5-mini-");
2445
+ }
2446
+ function applyDefaultReasoningEffort(payload) {
2447
+ if (!isGpt5MiniFamily(payload.model)) return payload;
2448
+ if (payload.reasoning_effort !== null && payload.reasoning_effort !== void 0) return payload;
2449
+ return {
2450
+ ...payload,
2451
+ reasoning_effort: getReasoningEffortForModel("gpt-5-mini")
2452
+ };
2453
+ }
2454
+ const getChatInitiator = (messages) => {
2455
+ if (isForceAgentEnabled()) return messages.some((msg) => ["assistant", "tool"].includes(msg.role)) ? "agent" : "user";
2456
+ const lastMessage = messages.at(-1);
2457
+ if (!lastMessage) return "user";
2458
+ return ["assistant", "tool"].includes(lastMessage.role) ? "agent" : "user";
2459
+ };
2460
+ const createChatCompletions = async (payload, account, options) => {
2444
2461
  const ctx = account ?? accountFromState();
2445
2462
  if (!ctx.copilotToken) throw new Error("Copilot token not found");
2463
+ const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x$1) => x$1.type === "image_url"));
2464
+ const initiator = options?.initiator ?? getChatInitiator(payload.messages);
2446
2465
  const headers = {
2447
- ...copilotHeaders(ctx, vision, upstreamRequestId),
2448
- "x-initiator": initiator
2466
+ ...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
2467
+ "x-initiator": options?.subagentMarker ? "agent" : initiator
2449
2468
  };
2450
- prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
2451
- prepareForCompact(headers, isCompact);
2452
- payload.service_tier = null;
2453
- const response = await fetch(`${copilotBaseUrl(ctx)}/responses`, {
2469
+ prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
2470
+ const upstreamPayload = applyDefaultReasoningEffort(payload);
2471
+ prepareForCompact(headers, options?.isCompact);
2472
+ const response = await fetch(`${copilotBaseUrl(ctx)}/chat/completions`, {
2454
2473
  method: "POST",
2455
2474
  headers,
2456
- body: JSON.stringify(payload)
2475
+ body: JSON.stringify(upstreamPayload)
2457
2476
  });
2458
2477
  if (!response.ok) {
2459
- consola.error("Failed to create responses", response);
2460
- throw new HTTPError("Failed to create responses", response);
2478
+ consola.error("Failed to create chat completions", response);
2479
+ throw new HTTPError("Failed to create chat completions", response);
2461
2480
  }
2462
2481
  if (payload.stream) return events(response);
2463
2482
  return await response.json();
2464
2483
  };
2465
2484
 
2466
2485
  //#endregion
2467
- //#region src/routes/messages/responses-translation.ts
2468
- const MESSAGE_TYPE = "message";
2469
- const COMPACTION_SIGNATURE_PREFIX = "cm1#";
2470
- const COMPACTION_SIGNATURE_SEPARATOR = "@";
2471
- const THINKING_TEXT$1 = "Thinking...";
2472
- const translateAnthropicMessagesToResponsesPayload = (payload, modelOverride) => {
2473
- const model = modelOverride ?? payload.model;
2474
- const input = [];
2475
- const applyPhase = shouldApplyPhase(payload.model);
2476
- for (const message of payload.messages) input.push(...translateMessage(message, payload.model, applyPhase));
2477
- const translatedTools = convertAnthropicTools(payload.tools);
2478
- const toolChoice = convertAnthropicToolChoice(payload.tool_choice);
2479
- const { safetyIdentifier, promptCacheKey } = parseUserId(payload.metadata?.user_id);
2480
- return {
2481
- model,
2482
- input,
2483
- instructions: translateSystemPrompt(payload.system, model),
2484
- temperature: 1,
2485
- top_p: payload.top_p ?? null,
2486
- max_output_tokens: Math.max(payload.max_tokens, 12800),
2487
- tools: translatedTools,
2488
- tool_choice: toolChoice,
2489
- metadata: payload.metadata ? { ...payload.metadata } : null,
2490
- safety_identifier: safetyIdentifier,
2491
- prompt_cache_key: promptCacheKey,
2492
- stream: payload.stream ?? null,
2493
- store: false,
2494
- parallel_tool_calls: true,
2495
- reasoning: {
2496
- effort: getReasoningEffortForModel(model),
2497
- summary: "auto"
2498
- },
2499
- include: ["reasoning.encrypted_content"]
2500
- };
2501
- };
2502
- const encodeCompactionCarrierSignature = (compaction) => {
2503
- return `${COMPACTION_SIGNATURE_PREFIX}${compaction.encrypted_content}${COMPACTION_SIGNATURE_SEPARATOR}${compaction.id}`;
2504
- };
2505
- const decodeCompactionCarrierSignature = (signature) => {
2506
- if (signature.startsWith(COMPACTION_SIGNATURE_PREFIX)) {
2507
- const raw = signature.slice(4);
2508
- const separatorIndex = raw.indexOf(COMPACTION_SIGNATURE_SEPARATOR);
2509
- if (separatorIndex <= 0 || separatorIndex === raw.length - 1) return;
2510
- const encrypted_content = raw.slice(0, separatorIndex);
2511
- const id = raw.slice(separatorIndex + 1);
2512
- if (!encrypted_content) return;
2513
- return {
2514
- id,
2515
- encrypted_content
2516
- };
2517
- }
2518
- };
2519
- const translateMessage = (message, model, applyPhase) => {
2520
- if (message.role === "user") return translateUserMessage(message);
2521
- return translateAssistantMessage(message, model, applyPhase);
2522
- };
2523
- const translateUserMessage = (message) => {
2524
- if (typeof message.content === "string") return [createMessage("user", message.content)];
2525
- if (!Array.isArray(message.content)) return [];
2526
- const items = [];
2527
- const pendingContent = [];
2528
- for (const block of message.content) {
2529
- if (block.type === "tool_result") {
2530
- flushPendingContent(pendingContent, items, { role: "user" });
2531
- items.push(createFunctionCallOutput(block));
2532
- continue;
2533
- }
2534
- const converted = translateUserContentBlock(block);
2535
- if (converted) pendingContent.push(converted);
2486
+ //#region src/routes/chat-completions/handler.ts
2487
+ const logger$6 = createHandlerLogger("chat-completions-handler");
2488
+ const CHAT_COMPLETIONS_ENDPOINT$1 = "/chat/completions";
2489
+ async function handleCompletion$1(c) {
2490
+ await checkRateLimit(state);
2491
+ const store = getRequestHistoryStore();
2492
+ const request = buildRequestContext$1(c);
2493
+ const payload = await c.req.json();
2494
+ const clientModel = payload.model;
2495
+ const streamRequested = Boolean(payload.stream);
2496
+ const initiator = getChatInitiator(payload.messages);
2497
+ const userId = payload.user ?? void 0;
2498
+ const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
2499
+ const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
2500
+ const normalizedPromptCacheKey = promptCacheKey ?? void 0;
2501
+ request.userId = userId;
2502
+ request.safetyIdentifier = normalizedSafetyIdentifier;
2503
+ request.promptCacheKey = normalizedPromptCacheKey;
2504
+ request.initiator = initiator;
2505
+ if (getAliasTargetSet().has(clientModel.toLowerCase())) {
2506
+ recordSelectionFailure$2(store, {
2507
+ request,
2508
+ clientModel,
2509
+ stream: streamRequested,
2510
+ reason: "MODEL_NOT_SUPPORTED"
2511
+ });
2512
+ return selectionFailureResponse$2(c, {
2513
+ clientModel,
2514
+ reason: "MODEL_NOT_SUPPORTED"
2515
+ });
2536
2516
  }
2537
- flushPendingContent(pendingContent, items, { role: "user" });
2538
- return items;
2539
- };
2540
- const translateAssistantMessage = (message, model, applyPhase) => {
2541
- const assistantPhase = resolveAssistantPhase(model, message.content, applyPhase);
2542
- if (typeof message.content === "string") return [createMessage("assistant", message.content, assistantPhase)];
2543
- if (!Array.isArray(message.content)) return [];
2544
- const items = [];
2545
- const pendingContent = [];
2546
- for (const block of message.content) {
2547
- if (block.type === "tool_use") {
2548
- flushPendingContent(pendingContent, items, {
2549
- role: "assistant",
2550
- phase: assistantPhase
2551
- });
2552
- items.push(createFunctionToolCall(block));
2553
- continue;
2554
- }
2555
- if (block.type === "thinking" && block.signature) {
2556
- const compactionContent = createCompactionContent(block);
2557
- if (compactionContent) {
2558
- flushPendingContent(pendingContent, items, {
2559
- role: "assistant",
2560
- phase: assistantPhase
2561
- });
2562
- items.push(compactionContent);
2563
- continue;
2564
- }
2565
- if (block.signature.includes("@")) {
2566
- flushPendingContent(pendingContent, items, {
2567
- role: "assistant",
2568
- phase: assistantPhase
2569
- });
2570
- items.push(createReasoningContent(block));
2571
- continue;
2572
- }
2573
- }
2574
- const converted = translateAssistantContentBlock(block);
2575
- if (converted) pendingContent.push(converted);
2517
+ logger$6.debug("Request payload:", JSON.stringify(payload).slice(-400));
2518
+ const selection = await accountsManager.selectAccountForRequest([{
2519
+ modelId: clientModel,
2520
+ endpoint: CHAT_COMPLETIONS_ENDPOINT$1
2521
+ }]);
2522
+ if (!selection.ok) {
2523
+ recordSelectionFailure$2(store, {
2524
+ request,
2525
+ clientModel,
2526
+ stream: streamRequested,
2527
+ reason: selection.reason
2528
+ });
2529
+ return selectionFailureResponse$2(c, {
2530
+ clientModel,
2531
+ reason: selection.reason
2532
+ });
2576
2533
  }
2577
- flushPendingContent(pendingContent, items, {
2578
- role: "assistant",
2579
- phase: assistantPhase
2580
- });
2581
- return items;
2582
- };
2583
- const translateUserContentBlock = (block) => {
2584
- switch (block.type) {
2585
- case "text": return createTextContent(block.text);
2586
- case "image": return createImageContent(block);
2587
- default: return;
2588
- }
2589
- };
2590
- const translateAssistantContentBlock = (block) => {
2591
- switch (block.type) {
2592
- case "text": return createOutPutTextContent(block.text);
2593
- default: return;
2594
- }
2595
- };
2596
- const flushPendingContent = (pendingContent, target, message) => {
2597
- if (pendingContent.length === 0) return;
2598
- const messageContent = [...pendingContent];
2599
- target.push(createMessage(message.role, messageContent, message.phase));
2600
- pendingContent.length = 0;
2601
- };
2602
- const createMessage = (role, content, phase) => ({
2603
- type: MESSAGE_TYPE,
2604
- role,
2605
- content,
2606
- ...role === "assistant" && phase ? { phase } : {}
2607
- });
2608
- const resolveAssistantPhase = (_model, content, applyPhase) => {
2609
- if (!applyPhase) return;
2610
- if (typeof content === "string") return "final_answer";
2611
- if (!Array.isArray(content)) return;
2612
- if (!content.some((block) => block.type === "text")) return;
2613
- return content.some((block) => block.type === "tool_use") ? "commentary" : "final_answer";
2614
- };
2615
- const shouldApplyPhase = (model) => {
2616
- return getExtraPromptForModel(model).includes("## Intermediary updates");
2617
- };
2618
- const createTextContent = (text) => ({
2619
- type: "input_text",
2620
- text
2621
- });
2622
- const createOutPutTextContent = (text) => ({
2623
- type: "output_text",
2624
- text
2625
- });
2626
- const createImageContent = (block) => ({
2627
- type: "input_image",
2628
- image_url: `data:${block.source.media_type};base64,${block.source.data}`,
2629
- detail: "auto"
2630
- });
2631
- const createReasoningContent = (block) => {
2632
- const { encryptedContent, id } = parseReasoningSignature(block.signature);
2633
- const thinking = block.thinking === THINKING_TEXT$1 ? "" : block.thinking;
2634
- return {
2635
- id,
2636
- type: "reasoning",
2637
- summary: thinking ? [{
2638
- type: "summary_text",
2639
- text: thinking
2640
- }] : [],
2641
- encrypted_content: encryptedContent
2642
- };
2643
- };
2644
- const createCompactionContent = (block) => {
2645
- const compaction = decodeCompactionCarrierSignature(block.signature);
2646
- if (!compaction) return;
2647
- return {
2648
- id: compaction.id,
2649
- type: "compaction",
2650
- encrypted_content: compaction.encrypted_content
2651
- };
2652
- };
2653
- const parseReasoningSignature = (signature) => {
2654
- const splitIndex = signature.lastIndexOf("@");
2655
- if (splitIndex <= 0 || splitIndex === signature.length - 1) return {
2656
- encryptedContent: signature,
2657
- id: ""
2658
- };
2659
- return {
2660
- encryptedContent: signature.slice(0, splitIndex),
2661
- id: signature.slice(splitIndex + 1)
2662
- };
2663
- };
2664
- const createFunctionToolCall = (block) => ({
2665
- type: "function_call",
2666
- call_id: block.id,
2667
- name: block.name,
2668
- arguments: JSON.stringify(block.input),
2669
- status: "completed"
2670
- });
2671
- const createFunctionCallOutput = (block) => ({
2672
- type: "function_call_output",
2673
- call_id: block.tool_use_id,
2674
- output: convertToolResultContent(block.content),
2675
- status: block.is_error ? "incomplete" : "completed"
2676
- });
2677
- const translateSystemPrompt = (system, model) => {
2678
- if (!system) return null;
2679
- const extraPrompt = getExtraPromptForModel(model);
2680
- if (typeof system === "string") return system + extraPrompt;
2681
- const text = system.map((block, index) => {
2682
- if (index === 0) return block.text + extraPrompt;
2683
- return block.text;
2684
- }).join(" ");
2685
- return text.length > 0 ? text : null;
2686
- };
2687
- const convertAnthropicTools = (tools) => {
2688
- if (!tools || tools.length === 0) return null;
2689
- return tools.map((tool) => ({
2690
- type: "function",
2691
- name: tool.name,
2692
- parameters: tool.input_schema,
2693
- strict: false,
2694
- ...tool.description ? { description: tool.description } : {}
2695
- }));
2696
- };
2697
- const convertAnthropicToolChoice = (choice) => {
2698
- if (!choice) return "auto";
2699
- switch (choice.type) {
2700
- case "auto": return "auto";
2701
- case "any": return "required";
2702
- case "tool": return choice.name ? {
2703
- type: "function",
2704
- name: choice.name
2705
- } : "auto";
2706
- case "none": return "none";
2707
- default: return "auto";
2708
- }
2709
- };
2710
- const translateResponsesResultToAnthropic = (response) => {
2711
- const contentBlocks = mapOutputToAnthropicContent(response.output);
2712
- const usage = mapResponsesUsage(response);
2713
- let anthropicContent = fallbackContentBlocks(response.output_text);
2714
- if (contentBlocks.length > 0) anthropicContent = contentBlocks;
2715
- const stopReason = mapResponsesStopReason(response);
2716
- return {
2717
- id: response.id,
2718
- type: "message",
2719
- role: "assistant",
2720
- content: anthropicContent,
2721
- model: response.model,
2722
- stop_reason: stopReason,
2723
- stop_sequence: null,
2724
- usage
2725
- };
2726
- };
2727
- const mapOutputToAnthropicContent = (output) => {
2728
- const contentBlocks = [];
2729
- for (const item of output) switch (item.type) {
2730
- case "reasoning": {
2731
- const thinkingText = extractReasoningText(item);
2732
- if (thinkingText.length > 0) contentBlocks.push({
2733
- type: "thinking",
2734
- thinking: thinkingText,
2735
- signature: (item.encrypted_content ?? "") + "@" + item.id
2736
- });
2737
- break;
2738
- }
2739
- case "function_call": {
2740
- const toolUseBlock = createToolUseContentBlock(item);
2741
- if (toolUseBlock) contentBlocks.push(toolUseBlock);
2742
- break;
2743
- }
2744
- case "message": {
2745
- const combinedText = combineMessageTextContent(item.content);
2746
- if (combinedText.length > 0) contentBlocks.push({
2747
- type: "text",
2748
- text: combinedText
2749
- });
2750
- break;
2751
- }
2752
- case "compaction": {
2753
- const compactionBlock = createCompactionThinkingBlock(item);
2754
- if (compactionBlock) contentBlocks.push(compactionBlock);
2755
- break;
2756
- }
2757
- default: {
2758
- const combinedText = combineMessageTextContent(item.content);
2759
- if (combinedText.length > 0) contentBlocks.push({
2760
- type: "text",
2761
- text: combinedText
2762
- });
2763
- }
2764
- }
2765
- return contentBlocks;
2766
- };
2767
- const combineMessageTextContent = (content) => {
2768
- if (!Array.isArray(content)) return "";
2769
- let aggregated = "";
2770
- for (const block of content) {
2771
- if (isResponseOutputText(block)) {
2772
- aggregated += block.text;
2773
- continue;
2774
- }
2775
- if (isResponseOutputRefusal(block)) {
2776
- aggregated += block.refusal;
2777
- continue;
2778
- }
2779
- if (typeof block.text === "string") {
2780
- aggregated += block.text;
2781
- continue;
2782
- }
2783
- if (typeof block.reasoning === "string") {
2784
- aggregated += block.reasoning;
2785
- continue;
2786
- }
2787
- }
2788
- return aggregated;
2789
- };
2790
- const extractReasoningText = (item) => {
2791
- const segments = [];
2792
- const collectFromBlocks = (blocks) => {
2793
- if (!Array.isArray(blocks)) return;
2794
- for (const block of blocks) if (typeof block.text === "string") {
2795
- segments.push(block.text);
2796
- continue;
2797
- }
2798
- };
2799
- if (!item.summary || item.summary.length === 0) return THINKING_TEXT$1;
2800
- collectFromBlocks(item.summary);
2801
- return segments.join("").trim();
2802
- };
2803
- const createToolUseContentBlock = (call) => {
2804
- const toolId = call.call_id;
2805
- if (!call.name || !toolId) return null;
2806
- const input = parseFunctionCallArguments(call.arguments);
2807
- return {
2808
- type: "tool_use",
2809
- id: toolId,
2810
- name: call.name,
2811
- input
2812
- };
2813
- };
2814
- const createCompactionThinkingBlock = (item) => {
2815
- if (!item.id || !item.encrypted_content) return null;
2816
- return {
2817
- type: "thinking",
2818
- thinking: THINKING_TEXT$1,
2819
- signature: encodeCompactionCarrierSignature({
2820
- id: item.id,
2821
- encrypted_content: item.encrypted_content
2822
- })
2823
- };
2824
- };
2825
- const parseFunctionCallArguments = (rawArguments) => {
2826
- if (typeof rawArguments !== "string" || rawArguments.trim().length === 0) return {};
2827
- try {
2828
- const parsed = JSON.parse(rawArguments);
2829
- if (Array.isArray(parsed)) return { arguments: parsed };
2830
- if (parsed && typeof parsed === "object") return parsed;
2831
- } catch (error) {
2832
- consola.warn("Failed to parse function call arguments", {
2833
- error,
2834
- rawArguments
2835
- });
2836
- }
2837
- return { raw_arguments: rawArguments };
2838
- };
2839
- const fallbackContentBlocks = (outputText) => {
2840
- if (!outputText) return [];
2841
- return [{
2842
- type: "text",
2843
- text: outputText
2844
- }];
2845
- };
2846
- const mapResponsesStopReason = (response) => {
2847
- const { status, incomplete_details: incompleteDetails } = response;
2848
- if (status === "completed") {
2849
- if (response.output.some((item) => item.type === "function_call")) return "tool_use";
2850
- return "end_turn";
2851
- }
2852
- if (status === "incomplete") {
2853
- if (incompleteDetails?.reason === "max_output_tokens") return "max_tokens";
2854
- if (incompleteDetails?.reason === "content_filter") return "end_turn";
2855
- }
2856
- return null;
2857
- };
2858
- const mapResponsesUsage = (response) => {
2859
- const inputTokens = response.usage?.input_tokens ?? 0;
2860
- const outputTokens = response.usage?.output_tokens ?? 0;
2861
- const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
2862
- return {
2863
- input_tokens: inputTokens - (inputCachedTokens ?? 0),
2864
- output_tokens: outputTokens,
2865
- ...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
2866
- };
2867
- };
2868
- const isRecord = (value) => typeof value === "object" && value !== null;
2869
- const isResponseOutputText = (block) => isRecord(block) && "type" in block && block.type === "output_text";
2870
- const isResponseOutputRefusal = (block) => isRecord(block) && "type" in block && block.type === "refusal";
2871
- const parseUserId = (userId) => {
2872
- if (!userId || typeof userId !== "string") return {
2873
- safetyIdentifier: null,
2874
- promptCacheKey: null
2875
- };
2876
- const userMatch = userId.match(/user_([^_]+)_account/);
2877
- const safetyIdentifier = userMatch ? userMatch[1] : null;
2878
- const sessionMatch = userId.match(/_session_(.+)$/);
2879
- const promptCacheKey = sessionMatch ? sessionMatch[1] : null;
2880
- return {
2881
- safetyIdentifier,
2882
- promptCacheKey
2883
- };
2884
- };
2885
- const convertToolResultContent = (content) => {
2886
- if (typeof content === "string") return content;
2887
- if (Array.isArray(content)) {
2888
- const result = [];
2889
- for (const block of content) switch (block.type) {
2890
- case "text":
2891
- result.push(createTextContent(block.text));
2892
- break;
2893
- case "image":
2894
- result.push(createImageContent(block));
2895
- break;
2896
- default: break;
2897
- }
2898
- return result;
2899
- }
2900
- return "";
2901
- };
2902
-
2903
- //#endregion
2904
- //#region src/services/copilot/create-chat-completions.ts
2905
- function isGpt5MiniFamily(modelId) {
2906
- return modelId === "gpt-5-mini" || modelId.startsWith("gpt-5-mini-");
2907
- }
2908
- function applyDefaultReasoningEffort(payload) {
2909
- if (!isGpt5MiniFamily(payload.model)) return payload;
2910
- if (payload.reasoning_effort !== null && payload.reasoning_effort !== void 0) return payload;
2911
- return {
2912
- ...payload,
2913
- reasoning_effort: getReasoningEffortForModel("gpt-5-mini")
2914
- };
2915
- }
2916
- const getChatInitiator = (messages) => {
2917
- if (isForceAgentEnabled()) return messages.some((msg) => ["assistant", "tool"].includes(msg.role)) ? "agent" : "user";
2918
- const lastMessage = messages.at(-1);
2919
- if (!lastMessage) return "user";
2920
- return ["assistant", "tool"].includes(lastMessage.role) ? "agent" : "user";
2921
- };
2922
- const createChatCompletions = async (payload, account, options) => {
2923
- const ctx = account ?? accountFromState();
2924
- if (!ctx.copilotToken) throw new Error("Copilot token not found");
2925
- const enableVision = payload.messages.some((x) => typeof x.content !== "string" && x.content?.some((x$1) => x$1.type === "image_url"));
2926
- const initiator = options?.initiator ?? getChatInitiator(payload.messages);
2927
- const headers = {
2928
- ...copilotHeaders(ctx, enableVision, options?.upstreamRequestId),
2929
- "x-initiator": options?.subagentMarker ? "agent" : initiator
2930
- };
2931
- prepareInteractionHeaders(options?.sessionId, Boolean(options?.subagentMarker), headers);
2932
- const upstreamPayload = applyDefaultReasoningEffort(payload);
2933
- prepareForCompact(headers, options?.isCompact);
2934
- const response = await fetch(`${copilotBaseUrl(ctx)}/chat/completions`, {
2935
- method: "POST",
2936
- headers,
2937
- body: JSON.stringify(upstreamPayload)
2938
- });
2939
- if (!response.ok) {
2940
- consola.error("Failed to create chat completions", response);
2941
- throw new HTTPError("Failed to create chat completions", response);
2942
- }
2943
- if (payload.stream) return events(response);
2944
- return await response.json();
2945
- };
2946
-
2947
- //#endregion
2948
- //#region src/routes/chat-completions/handler.ts
2949
- const logger$6 = createHandlerLogger("chat-completions-handler");
2950
- const CHAT_COMPLETIONS_ENDPOINT$1 = "/chat/completions";
2951
- async function handleCompletion$1(c) {
2952
- await checkRateLimit(state);
2953
- const store = getRequestHistoryStore();
2954
- const request = buildRequestContext$1(c);
2955
- const payload = await c.req.json();
2956
- const clientModel = payload.model;
2957
- const streamRequested = Boolean(payload.stream);
2958
- const initiator = getChatInitiator(payload.messages);
2959
- const userId = payload.user ?? void 0;
2960
- const { safetyIdentifier, promptCacheKey } = parseUserId(userId);
2961
- const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
2962
- const normalizedPromptCacheKey = promptCacheKey ?? void 0;
2963
- request.userId = userId;
2964
- request.safetyIdentifier = normalizedSafetyIdentifier;
2965
- request.promptCacheKey = normalizedPromptCacheKey;
2966
- request.initiator = initiator;
2967
- if (getAliasTargetSet().has(clientModel.toLowerCase())) {
2968
- recordSelectionFailure$2(store, {
2969
- request,
2970
- clientModel,
2971
- stream: streamRequested,
2972
- reason: "MODEL_NOT_SUPPORTED"
2973
- });
2974
- return selectionFailureResponse$2(c, {
2975
- clientModel,
2976
- reason: "MODEL_NOT_SUPPORTED"
2977
- });
2978
- }
2979
- logger$6.debug("Request payload:", JSON.stringify(payload).slice(-400));
2980
- const selection = await accountsManager.selectAccountForRequest([{
2981
- modelId: clientModel,
2982
- endpoint: CHAT_COMPLETIONS_ENDPOINT$1
2983
- }]);
2984
- if (!selection.ok) {
2985
- recordSelectionFailure$2(store, {
2986
- request,
2987
- clientModel,
2988
- stream: streamRequested,
2989
- reason: selection.reason
2990
- });
2991
- return selectionFailureResponse$2(c, {
2992
- clientModel,
2993
- reason: selection.reason
2994
- });
2995
- }
2996
- const { account, selectedModel } = selection;
2997
- const upstreamPayload = {
2998
- ...payload,
2999
- model: selectedModel.id
3000
- };
3001
- const premiumRemainingBefore = account.premiumRemaining;
3002
- const premiumUnlimitedBefore = account.unlimited;
3003
- await logTokenCountForRequest({
3004
- payload: upstreamPayload,
3005
- selectedModel
2534
+ const { account, selectedModel } = selection;
2535
+ const upstreamPayload = {
2536
+ ...payload,
2537
+ model: selectedModel.id
2538
+ };
2539
+ const premiumRemainingBefore = account.premiumRemaining;
2540
+ const premiumUnlimitedBefore = account.unlimited;
2541
+ await logTokenCountForRequest({
2542
+ payload: upstreamPayload,
2543
+ selectedModel
3006
2544
  });
3007
2545
  if (state.manualApprove) await awaitApproval();
3008
2546
  const payloadWithMaxTokens = applyDefaultMaxTokens(upstreamPayload, selectedModel);
@@ -3379,571 +2917,1030 @@ const createEmbeddings = async (payload, account) => {
3379
2917
  };
3380
2918
 
3381
2919
  //#endregion
3382
- //#region src/routes/embeddings/route.ts
3383
- const embeddingRoutes = new Hono();
3384
- const EMBEDDINGS_ENDPOINT = "/embeddings";
3385
- embeddingRoutes.post("/", async (c) => {
3386
- try {
3387
- const store = getRequestHistoryStore();
3388
- const requestId = randomUUID();
3389
- const startedAtMs = Date.now();
3390
- const method = c.req.raw.method;
3391
- const path$2 = new URL(c.req.url, "http://local").pathname;
3392
- const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
3393
- const userAgent = c.req.header("user-agent") ?? void 0;
3394
- const ctx = {
3395
- requestId,
3396
- startedAtMs,
3397
- method,
3398
- path: path$2,
3399
- clientIp,
3400
- clientIpSource,
3401
- userAgent
2920
+ //#region src/routes/embeddings/route.ts
2921
+ const embeddingRoutes = new Hono();
2922
+ const EMBEDDINGS_ENDPOINT = "/embeddings";
2923
+ embeddingRoutes.post("/", async (c) => {
2924
+ try {
2925
+ const store = getRequestHistoryStore();
2926
+ const requestId = randomUUID();
2927
+ const startedAtMs = Date.now();
2928
+ const method = c.req.raw.method;
2929
+ const path$2 = new URL(c.req.url, "http://local").pathname;
2930
+ const { ip: clientIp, source: clientIpSource } = getClientIpInfo(c);
2931
+ const userAgent = c.req.header("user-agent") ?? void 0;
2932
+ const ctx = {
2933
+ requestId,
2934
+ startedAtMs,
2935
+ method,
2936
+ path: path$2,
2937
+ clientIp,
2938
+ clientIpSource,
2939
+ userAgent
2940
+ };
2941
+ const payload = await c.req.json();
2942
+ const clientModel = payload.model;
2943
+ if (getAliasTargetSet().has(clientModel.toLowerCase())) {
2944
+ recordSelectionFailure$1(store, {
2945
+ ctx,
2946
+ clientModel,
2947
+ reason: "MODEL_NOT_SUPPORTED"
2948
+ });
2949
+ return selectionFailureResponse$1(c, clientModel, "MODEL_NOT_SUPPORTED");
2950
+ }
2951
+ const selection = await accountsManager.selectAccountForRequest([{
2952
+ modelId: clientModel,
2953
+ endpoint: EMBEDDINGS_ENDPOINT
2954
+ }]);
2955
+ if (!selection.ok) {
2956
+ recordSelectionFailure$1(store, {
2957
+ ctx,
2958
+ clientModel,
2959
+ reason: selection.reason
2960
+ });
2961
+ return selectionFailureResponse$1(c, clientModel, selection.reason);
2962
+ }
2963
+ const upstreamPayload = {
2964
+ ...payload,
2965
+ model: selection.selectedModel.id
2966
+ };
2967
+ return await runEmbeddingsWithAccount({
2968
+ c,
2969
+ store,
2970
+ ctx,
2971
+ payload: upstreamPayload,
2972
+ clientModel,
2973
+ selection
2974
+ });
2975
+ } catch (error) {
2976
+ return await forwardError(c, error);
2977
+ }
2978
+ });
2979
+ function recordSelectionFailure$1(store, params) {
2980
+ const { ctx, clientModel, reason } = params;
2981
+ const finishedAtMs = Date.now();
2982
+ store.insert({
2983
+ requestId: ctx.requestId,
2984
+ startedAtMs: ctx.startedAtMs,
2985
+ finishedAtMs,
2986
+ durationMs: finishedAtMs - ctx.startedAtMs,
2987
+ method: ctx.method,
2988
+ path: ctx.path,
2989
+ upstreamEndpoint: EMBEDDINGS_ENDPOINT,
2990
+ stream: false,
2991
+ clientModel,
2992
+ clientIp: ctx.clientIp,
2993
+ clientIpSource: ctx.clientIpSource,
2994
+ userAgent: ctx.userAgent,
2995
+ httpStatus: reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
2996
+ selectionFailureReason: reason
2997
+ });
2998
+ }
2999
+ function selectionFailureResponse$1(c, clientModel, reason) {
3000
+ if (reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
3001
+ message: `Model "${clientModel}" is not available for any configured account.`,
3002
+ type: "invalid_request_error"
3003
+ } }, 400);
3004
+ return c.json({ error: {
3005
+ message: "All accounts have exhausted their quota. Please wait for quota refresh or add additional accounts.",
3006
+ type: "rate_limit_error"
3007
+ } }, 429);
3008
+ }
3009
+ async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, selection }) {
3010
+ const { account, reservation, selectedModel, endpoint, costUnits } = selection;
3011
+ const premiumRemainingBefore = account.premiumRemaining;
3012
+ const premiumUnlimitedBefore = account.unlimited;
3013
+ let httpStatus = 200;
3014
+ let usage = {};
3015
+ let errorName;
3016
+ let errorStatus;
3017
+ let errorMessage;
3018
+ let finishedAtMs;
3019
+ try {
3020
+ const accountCtx = toAccountContext(account);
3021
+ const response = await createEmbeddings(payload, accountCtx);
3022
+ usage = normalizeEmbeddingsUsage(response.usage);
3023
+ finishedAtMs = Date.now();
3024
+ return c.json(response);
3025
+ } catch (error) {
3026
+ finishedAtMs = Date.now();
3027
+ const details = extractErrorDetails(error);
3028
+ httpStatus = details.httpStatus;
3029
+ errorName = details.errorName;
3030
+ errorStatus = details.errorStatus;
3031
+ errorMessage = details.errorMessage;
3032
+ if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
3033
+ throw error;
3034
+ } finally {
3035
+ const finishedAtMsFinal = finishedAtMs ?? Date.now();
3036
+ await accountsManager.finalizeQuota(account, reservation);
3037
+ const premiumRemainingAfter = account.premiumRemaining;
3038
+ const premiumUnlimitedAfter = account.unlimited;
3039
+ store.insert({
3040
+ requestId: ctx.requestId,
3041
+ startedAtMs: ctx.startedAtMs,
3042
+ finishedAtMs: finishedAtMsFinal,
3043
+ durationMs: finishedAtMsFinal - ctx.startedAtMs,
3044
+ method: ctx.method,
3045
+ path: ctx.path,
3046
+ upstreamEndpoint: endpoint,
3047
+ stream: false,
3048
+ accountId: account.id,
3049
+ accountType: account.accountType,
3050
+ costUnits,
3051
+ clientModel,
3052
+ upstreamModel: selectedModel.id,
3053
+ clientIp: ctx.clientIp,
3054
+ clientIpSource: ctx.clientIpSource,
3055
+ userAgent: ctx.userAgent,
3056
+ ...usage,
3057
+ premiumRemainingBefore,
3058
+ premiumRemainingAfter,
3059
+ premiumRemainingDiff: computeDiff(premiumRemainingBefore, premiumRemainingAfter),
3060
+ premiumUnlimitedBefore,
3061
+ premiumUnlimitedAfter,
3062
+ httpStatus,
3063
+ errorName,
3064
+ errorStatus,
3065
+ errorMessage
3066
+ });
3067
+ }
3068
+ }
3069
+
3070
+ //#endregion
3071
+ //#region src/lib/models.ts
3072
+ const findEndpointModel = (sdkModelId) => {
3073
+ const models = state.models?.data ?? [];
3074
+ const exactMatch = models.find((m) => m.id === sdkModelId);
3075
+ if (exactMatch) return exactMatch;
3076
+ const normalized = _normalizeSdkModelId(sdkModelId);
3077
+ if (!normalized) return;
3078
+ const modelName = `claude-${normalized.family}-${normalized.version}`;
3079
+ const model = models.find((m) => m.id === modelName);
3080
+ if (model) return model;
3081
+ };
3082
+ /**
3083
+ * Normalizes an SDK model ID to extract the model family and version.
3084
+ * this method from github copilot extension
3085
+ * Examples:
3086
+ * - "claude-opus-4-5-20251101" -> { family: "opus", version: "4.5" }
3087
+ * - "claude-3-5-sonnet-20241022" -> { family: "sonnet", version: "3.5" }
3088
+ * - "claude-sonnet-4-20250514" -> { family: "sonnet", version: "4" }
3089
+ * - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
3090
+ * - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
3091
+ */
3092
+ const _normalizeSdkModelId = (sdkModelId) => {
3093
+ const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
3094
+ const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
3095
+ if (pattern1) return {
3096
+ family: pattern1[1],
3097
+ version: `${pattern1[2]}.${pattern1[3]}`
3098
+ };
3099
+ const pattern2 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
3100
+ if (pattern2) return {
3101
+ family: pattern2[3],
3102
+ version: `${pattern2[1]}.${pattern2[2]}`
3103
+ };
3104
+ const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
3105
+ if (pattern3) return {
3106
+ family: pattern3[1],
3107
+ version: `${pattern3[2]}.${pattern3[3]}`
3108
+ };
3109
+ const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/);
3110
+ if (pattern4) return {
3111
+ family: pattern4[1],
3112
+ version: pattern4[2]
3113
+ };
3114
+ const pattern5 = withoutDate.match(/^claude-(\d+)-(\w+)$/);
3115
+ if (pattern5) return {
3116
+ family: pattern5[2],
3117
+ version: pattern5[1]
3118
+ };
3119
+ };
3120
+
3121
+ //#endregion
3122
+ //#region src/routes/messages/utils.ts
3123
+ function mapOpenAIStopReasonToAnthropic(finishReason) {
3124
+ if (finishReason === null) return null;
3125
+ return {
3126
+ stop: "end_turn",
3127
+ length: "max_tokens",
3128
+ tool_calls: "tool_use",
3129
+ content_filter: "end_turn"
3130
+ }[finishReason];
3131
+ }
3132
+ const mergeContentWithText = (toolResult, textBlock) => {
3133
+ if (typeof toolResult.content === "string") return {
3134
+ ...toolResult,
3135
+ content: `${toolResult.content}\n\n${textBlock.text}`
3136
+ };
3137
+ return {
3138
+ ...toolResult,
3139
+ content: [...toolResult.content, textBlock]
3140
+ };
3141
+ };
3142
+ const mergeContentWithTexts = (toolResult, textBlocks) => {
3143
+ if (typeof toolResult.content === "string") {
3144
+ const appendedTexts = textBlocks.map((tb) => tb.text).join("\n\n");
3145
+ return {
3146
+ ...toolResult,
3147
+ content: `${toolResult.content}\n\n${appendedTexts}`
3402
3148
  };
3403
- const payload = await c.req.json();
3404
- const clientModel = payload.model;
3405
- if (getAliasTargetSet().has(clientModel.toLowerCase())) {
3406
- recordSelectionFailure$1(store, {
3407
- ctx,
3408
- clientModel,
3409
- reason: "MODEL_NOT_SUPPORTED"
3410
- });
3411
- return selectionFailureResponse$1(c, clientModel, "MODEL_NOT_SUPPORTED");
3412
- }
3413
- const selection = await accountsManager.selectAccountForRequest([{
3414
- modelId: clientModel,
3415
- endpoint: EMBEDDINGS_ENDPOINT
3416
- }]);
3417
- if (!selection.ok) {
3418
- recordSelectionFailure$1(store, {
3419
- ctx,
3420
- clientModel,
3421
- reason: selection.reason
3422
- });
3423
- return selectionFailureResponse$1(c, clientModel, selection.reason);
3149
+ }
3150
+ return {
3151
+ ...toolResult,
3152
+ content: [...toolResult.content, ...textBlocks]
3153
+ };
3154
+ };
3155
+ const mergeToolResult = (toolResults, textBlocks) => {
3156
+ if (toolResults.length === textBlocks.length) return toolResults.map((toolResult, index) => mergeContentWithText(toolResult, textBlocks[index]));
3157
+ const lastIndex = toolResults.length - 1;
3158
+ return toolResults.map((toolResult, index) => index === lastIndex ? mergeContentWithTexts(toolResult, textBlocks) : toolResult);
3159
+ };
3160
+ const mergeToolResultForClaude = (anthropicPayload) => {
3161
+ for (const msg of anthropicPayload.messages) {
3162
+ if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
3163
+ const toolResults = [];
3164
+ const textBlocks = [];
3165
+ let valid = true;
3166
+ for (const block of msg.content) if (block.type === "tool_result") toolResults.push(block);
3167
+ else if (block.type === "text") textBlocks.push(block);
3168
+ else {
3169
+ valid = false;
3170
+ break;
3424
3171
  }
3425
- const upstreamPayload = {
3426
- ...payload,
3427
- model: selection.selectedModel.id
3428
- };
3429
- return await runEmbeddingsWithAccount({
3430
- c,
3431
- store,
3432
- ctx,
3433
- payload: upstreamPayload,
3434
- clientModel,
3435
- selection
3436
- });
3172
+ if (!valid || toolResults.length === 0 || textBlocks.length === 0) continue;
3173
+ msg.content = mergeToolResult(toolResults, textBlocks);
3174
+ }
3175
+ };
3176
+ const estimateInputTokens = async (payload, selectedModel, logger$7) => {
3177
+ try {
3178
+ return (await getTokenCount(payload, selectedModel)).input;
3437
3179
  } catch (error) {
3438
- return await forwardError(c, error);
3180
+ logger$7.warn("Failed to estimate input tokens for message_start", error);
3181
+ return;
3439
3182
  }
3440
- });
3441
- function recordSelectionFailure$1(store, params) {
3442
- const { ctx, clientModel, reason } = params;
3183
+ };
3184
+ const isWarmupProbeRequest = (payload) => {
3185
+ const lastMsg = payload.messages.at(-1);
3186
+ if (!lastMsg || lastMsg.role !== "user" || !Array.isArray(lastMsg.content)) return false;
3187
+ const lastBlock = lastMsg.content.at(-1);
3188
+ if (!lastBlock || lastBlock.type !== "text") return false;
3189
+ const text = lastBlock.text.trim().toLowerCase();
3190
+ if (!(lastBlock.cache_control?.type === "ephemeral")) return false;
3191
+ if (text === "warmup") return true;
3192
+ if (text === "hello") {
3193
+ const preludeBlocks = lastMsg.content.slice(0, -1);
3194
+ if (preludeBlocks.length === 0) return false;
3195
+ return preludeBlocks.every((block) => block.type === "text" && block.text.trimStart().toLowerCase().startsWith("<system-reminder"));
3196
+ }
3197
+ return false;
3198
+ };
3199
+ const handleSelectionFailure = (context) => {
3200
+ const { c, store, requestId, startedAtMs, method, path: path$2, streamRequested, clientModel, clientIp, clientIpSource, userAgent, userId, safetyIdentifier, promptCacheKey, initiator, selection } = context;
3443
3201
  const finishedAtMs = Date.now();
3444
3202
  store.insert({
3445
- requestId: ctx.requestId,
3446
- startedAtMs: ctx.startedAtMs,
3203
+ requestId,
3204
+ startedAtMs,
3447
3205
  finishedAtMs,
3448
- durationMs: finishedAtMs - ctx.startedAtMs,
3449
- method: ctx.method,
3450
- path: ctx.path,
3451
- upstreamEndpoint: EMBEDDINGS_ENDPOINT,
3452
- stream: false,
3206
+ durationMs: finishedAtMs - startedAtMs,
3207
+ method,
3208
+ path: path$2,
3209
+ stream: streamRequested,
3453
3210
  clientModel,
3454
- clientIp: ctx.clientIp,
3455
- clientIpSource: ctx.clientIpSource,
3456
- userAgent: ctx.userAgent,
3457
- httpStatus: reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
3458
- selectionFailureReason: reason
3211
+ clientIp,
3212
+ clientIpSource,
3213
+ userAgent,
3214
+ userId,
3215
+ safetyIdentifier,
3216
+ promptCacheKey,
3217
+ initiator,
3218
+ httpStatus: selection.reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
3219
+ selectionFailureReason: selection.reason
3220
+ });
3221
+ if (selection.reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
3222
+ message: `Model "${clientModel}" is not available for any configured account.`,
3223
+ type: "invalid_request_error"
3224
+ } }, 400);
3225
+ return c.json({ error: {
3226
+ message: "All accounts have exhausted their quota. Please wait for quota refresh or add additional accounts.",
3227
+ type: "rate_limit_error"
3228
+ } }, 429);
3229
+ };
3230
+ const maybeBlockOriginalModelName = (context) => {
3231
+ if (!getAliasTargetSet().has(context.clientModel.toLowerCase())) return null;
3232
+ return handleSelectionFailure({
3233
+ ...context,
3234
+ selection: {
3235
+ ok: false,
3236
+ reason: "MODEL_NOT_SUPPORTED"
3237
+ }
3238
+ });
3239
+ };
3240
+
3241
+ //#endregion
3242
+ //#region src/routes/messages/non-stream-translation.ts
3243
+ const THINKING_TEXT = "Thinking...";
3244
+ function translateToOpenAI(payload) {
3245
+ const modelId = payload.model;
3246
+ const model = state.models?.data.find((m) => m.id === modelId);
3247
+ const thinkingBudget = getThinkingBudget(payload, model);
3248
+ return {
3249
+ model: modelId,
3250
+ messages: translateAnthropicMessagesToOpenAI(payload, modelId, thinkingBudget),
3251
+ max_tokens: payload.max_tokens,
3252
+ stop: payload.stop_sequences,
3253
+ stream: payload.stream,
3254
+ temperature: payload.temperature,
3255
+ top_p: payload.top_p,
3256
+ user: payload.metadata?.user_id,
3257
+ tools: translateAnthropicToolsToOpenAI(payload.tools),
3258
+ tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice),
3259
+ thinking_budget: thinkingBudget
3260
+ };
3261
+ }
3262
+ function getThinkingBudget(payload, model) {
3263
+ const thinking = payload.thinking;
3264
+ if (model && thinking) {
3265
+ const maxThinkingBudget = Math.min(model.capabilities.supports.max_thinking_budget ?? 0, (model.capabilities.limits.max_output_tokens ?? 0) - 1);
3266
+ thinking.budget_tokens ??= maxThinkingBudget;
3267
+ if (maxThinkingBudget > 0) {
3268
+ const budgetTokens = Math.min(thinking.budget_tokens, maxThinkingBudget);
3269
+ return Math.max(budgetTokens, model.capabilities.supports.min_thinking_budget ?? 1024);
3270
+ }
3271
+ }
3272
+ }
3273
+ function translateAnthropicMessagesToOpenAI(payload, modelId, _thinkingBudget) {
3274
+ const systemMessages = handleSystemPrompt(payload.system);
3275
+ const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message) : handleAssistantMessage(message, modelId));
3276
+ return [...systemMessages, ...otherMessages];
3277
+ }
3278
+ function handleSystemPrompt(system) {
3279
+ if (!system) return [];
3280
+ if (typeof system === "string") return [{
3281
+ role: "system",
3282
+ content: system
3283
+ }];
3284
+ else return [{
3285
+ role: "system",
3286
+ content: system.map((block) => {
3287
+ return block.text;
3288
+ }).join("\n\n")
3289
+ }];
3290
+ }
3291
+ function handleUserMessage(message) {
3292
+ const newMessages = [];
3293
+ if (Array.isArray(message.content)) {
3294
+ const toolResultBlocks = message.content.filter((block) => block.type === "tool_result");
3295
+ const otherBlocks = message.content.filter((block) => block.type !== "tool_result");
3296
+ for (const block of toolResultBlocks) newMessages.push({
3297
+ role: "tool",
3298
+ tool_call_id: block.tool_use_id,
3299
+ content: mapContent(block.content)
3300
+ });
3301
+ if (otherBlocks.length > 0) newMessages.push({
3302
+ role: "user",
3303
+ content: mapContent(otherBlocks)
3304
+ });
3305
+ } else newMessages.push({
3306
+ role: "user",
3307
+ content: mapContent(message.content)
3459
3308
  });
3309
+ return newMessages;
3460
3310
  }
3461
- function selectionFailureResponse$1(c, clientModel, reason) {
3462
- if (reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
3463
- message: `Model "${clientModel}" is not available for any configured account.`,
3464
- type: "invalid_request_error"
3465
- } }, 400);
3466
- return c.json({ error: {
3467
- message: "All accounts have exhausted their quota. Please wait for quota refresh or add additional accounts.",
3468
- type: "rate_limit_error"
3469
- } }, 429);
3311
+ function handleAssistantMessage(message, modelId) {
3312
+ if (!Array.isArray(message.content)) return [{
3313
+ role: "assistant",
3314
+ content: mapContent(message.content)
3315
+ }];
3316
+ const toolUseBlocks = message.content.filter((block) => block.type === "tool_use");
3317
+ let thinkingBlocks = message.content.filter((block) => block.type === "thinking");
3318
+ if (modelId.startsWith("claude")) thinkingBlocks = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT && b.signature && !b.signature.includes("@"));
3319
+ const thinkingContents = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT).map((b) => b.thinking);
3320
+ const allThinkingContent = thinkingContents.length > 0 ? thinkingContents.join("\n\n") : void 0;
3321
+ const signature = thinkingBlocks.find((b) => b.signature)?.signature;
3322
+ return toolUseBlocks.length > 0 ? [{
3323
+ role: "assistant",
3324
+ content: mapContent(message.content),
3325
+ reasoning_text: allThinkingContent,
3326
+ reasoning_opaque: signature,
3327
+ tool_calls: toolUseBlocks.map((toolUse) => ({
3328
+ id: toolUse.id,
3329
+ type: "function",
3330
+ function: {
3331
+ name: toolUse.name,
3332
+ arguments: JSON.stringify(toolUse.input)
3333
+ }
3334
+ }))
3335
+ }] : [{
3336
+ role: "assistant",
3337
+ content: mapContent(message.content),
3338
+ reasoning_text: allThinkingContent,
3339
+ reasoning_opaque: signature
3340
+ }];
3470
3341
  }
3471
- async function runEmbeddingsWithAccount({ c, store, ctx, payload, clientModel, selection }) {
3472
- const { account, reservation, selectedModel, endpoint, costUnits } = selection;
3473
- const premiumRemainingBefore = account.premiumRemaining;
3474
- const premiumUnlimitedBefore = account.unlimited;
3475
- let httpStatus = 200;
3476
- let usage = {};
3477
- let errorName;
3478
- let errorStatus;
3479
- let errorMessage;
3480
- let finishedAtMs;
3481
- try {
3482
- const accountCtx = toAccountContext(account);
3483
- const response = await createEmbeddings(payload, accountCtx);
3484
- usage = normalizeEmbeddingsUsage(response.usage);
3485
- finishedAtMs = Date.now();
3486
- return c.json(response);
3487
- } catch (error) {
3488
- finishedAtMs = Date.now();
3489
- const details = extractErrorDetails(error);
3490
- httpStatus = details.httpStatus;
3491
- errorName = details.errorName;
3492
- errorStatus = details.errorStatus;
3493
- errorMessage = details.errorMessage;
3494
- if (details.unauthorized) accountsManager.markAccountFailed(account.id, "Unauthorized (401)");
3495
- throw error;
3496
- } finally {
3497
- const finishedAtMsFinal = finishedAtMs ?? Date.now();
3498
- await accountsManager.finalizeQuota(account, reservation);
3499
- const premiumRemainingAfter = account.premiumRemaining;
3500
- const premiumUnlimitedAfter = account.unlimited;
3501
- store.insert({
3502
- requestId: ctx.requestId,
3503
- startedAtMs: ctx.startedAtMs,
3504
- finishedAtMs: finishedAtMsFinal,
3505
- durationMs: finishedAtMsFinal - ctx.startedAtMs,
3506
- method: ctx.method,
3507
- path: ctx.path,
3508
- upstreamEndpoint: endpoint,
3509
- stream: false,
3510
- accountId: account.id,
3511
- accountType: account.accountType,
3512
- costUnits,
3513
- clientModel,
3514
- upstreamModel: selectedModel.id,
3515
- clientIp: ctx.clientIp,
3516
- clientIpSource: ctx.clientIpSource,
3517
- userAgent: ctx.userAgent,
3518
- ...usage,
3519
- premiumRemainingBefore,
3520
- premiumRemainingAfter,
3521
- premiumRemainingDiff: computeDiff(premiumRemainingBefore, premiumRemainingAfter),
3522
- premiumUnlimitedBefore,
3523
- premiumUnlimitedAfter,
3524
- httpStatus,
3525
- errorName,
3526
- errorStatus,
3527
- errorMessage
3528
- });
3342
+ function mapContent(content) {
3343
+ if (typeof content === "string") return content;
3344
+ if (!Array.isArray(content)) return null;
3345
+ if (!content.some((block) => block.type === "image")) return content.filter((block) => block.type === "text").map((block) => block.text).join("\n\n");
3346
+ const contentParts = [];
3347
+ for (const block of content) switch (block.type) {
3348
+ case "text":
3349
+ contentParts.push({
3350
+ type: "text",
3351
+ text: block.text
3352
+ });
3353
+ break;
3354
+ case "image":
3355
+ contentParts.push({
3356
+ type: "image_url",
3357
+ image_url: { url: `data:${block.source.media_type};base64,${block.source.data}` }
3358
+ });
3359
+ break;
3529
3360
  }
3361
+ return contentParts;
3362
+ }
3363
+ function translateAnthropicToolsToOpenAI(anthropicTools) {
3364
+ if (!anthropicTools) return;
3365
+ return anthropicTools.map((tool) => ({
3366
+ type: "function",
3367
+ function: {
3368
+ name: tool.name,
3369
+ description: tool.description,
3370
+ parameters: normalizeToolSchema(tool.input_schema)
3371
+ }
3372
+ }));
3530
3373
  }
3531
-
3532
- //#endregion
3533
- //#region src/lib/models.ts
3534
- const findEndpointModel = (sdkModelId) => {
3535
- const models = state.models?.data ?? [];
3536
- const exactMatch = models.find((m) => m.id === sdkModelId);
3537
- if (exactMatch) return exactMatch;
3538
- const normalized = _normalizeSdkModelId(sdkModelId);
3539
- if (!normalized) return;
3540
- const modelName = `claude-${normalized.family}-${normalized.version}`;
3541
- const model = models.find((m) => m.id === modelName);
3542
- if (model) return model;
3543
- };
3544
3374
  /**
3545
- * Normalizes an SDK model ID to extract the model family and version.
3546
- * this method from github copilot extension
3547
- * Examples:
3548
- * - "claude-opus-4-5-20251101" -> { family: "opus", version: "4.5" }
3549
- * - "claude-3-5-sonnet-20241022" -> { family: "sonnet", version: "3.5" }
3550
- * - "claude-sonnet-4-20250514" -> { family: "sonnet", version: "4" }
3551
- * - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
3552
- * - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
3375
+ * Ensures `type: "object"` schema has a `properties` field.
3376
+ * OpenAI's API rejects object schemas without it.
3553
3377
  */
3554
- const _normalizeSdkModelId = (sdkModelId) => {
3555
- const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
3556
- const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
3557
- if (pattern1) return {
3558
- family: pattern1[1],
3559
- version: `${pattern1[2]}.${pattern1[3]}`
3560
- };
3561
- const pattern2 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
3562
- if (pattern2) return {
3563
- family: pattern2[3],
3564
- version: `${pattern2[1]}.${pattern2[2]}`
3565
- };
3566
- const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
3567
- if (pattern3) return {
3568
- family: pattern3[1],
3569
- version: `${pattern3[2]}.${pattern3[3]}`
3570
- };
3571
- const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/);
3572
- if (pattern4) return {
3573
- family: pattern4[1],
3574
- version: pattern4[2]
3575
- };
3576
- const pattern5 = withoutDate.match(/^claude-(\d+)-(\w+)$/);
3577
- if (pattern5) return {
3578
- family: pattern5[2],
3579
- version: pattern5[1]
3378
+ const normalizeToolSchema = (schema) => {
3379
+ if (schema.type === "object" && !schema.properties) return {
3380
+ ...schema,
3381
+ properties: {}
3580
3382
  };
3383
+ return schema;
3581
3384
  };
3385
+ function translateAnthropicToolChoiceToOpenAI(anthropicToolChoice) {
3386
+ if (!anthropicToolChoice) return;
3387
+ switch (anthropicToolChoice.type) {
3388
+ case "auto": return "auto";
3389
+ case "any": return "required";
3390
+ case "tool":
3391
+ if (anthropicToolChoice.name) return {
3392
+ type: "function",
3393
+ function: { name: anthropicToolChoice.name }
3394
+ };
3395
+ return;
3396
+ case "none": return "none";
3397
+ default: return;
3398
+ }
3399
+ }
3400
+ function translateToAnthropic(response) {
3401
+ const assistantContentBlocks = [];
3402
+ let stopReason = response.choices[0]?.finish_reason ?? null;
3403
+ for (const choice of response.choices) {
3404
+ const textBlocks = getAnthropicTextBlocks(choice.message.content);
3405
+ const thinkBlocks = getAnthropicThinkBlocks(choice.message.reasoning_text, choice.message.reasoning_opaque);
3406
+ const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls);
3407
+ assistantContentBlocks.push(...thinkBlocks, ...textBlocks, ...toolUseBlocks);
3408
+ if (choice.finish_reason === "tool_calls" || stopReason === "stop") stopReason = choice.finish_reason;
3409
+ }
3410
+ return {
3411
+ id: response.id,
3412
+ type: "message",
3413
+ role: "assistant",
3414
+ model: response.model,
3415
+ content: assistantContentBlocks,
3416
+ stop_reason: mapOpenAIStopReasonToAnthropic(stopReason),
3417
+ stop_sequence: null,
3418
+ usage: {
3419
+ input_tokens: (response.usage?.prompt_tokens ?? 0) - (response.usage?.prompt_tokens_details?.cached_tokens ?? 0),
3420
+ output_tokens: response.usage?.completion_tokens ?? 0,
3421
+ ...response.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.prompt_tokens_details.cached_tokens }
3422
+ }
3423
+ };
3424
+ }
3425
+ function getAnthropicTextBlocks(messageContent) {
3426
+ if (typeof messageContent === "string" && messageContent.length > 0) return [{
3427
+ type: "text",
3428
+ text: messageContent
3429
+ }];
3430
+ if (Array.isArray(messageContent)) return messageContent.filter((part) => part.type === "text").map((part) => ({
3431
+ type: "text",
3432
+ text: part.text
3433
+ }));
3434
+ return [];
3435
+ }
3436
+ function getAnthropicThinkBlocks(reasoningText, reasoningOpaque) {
3437
+ if (reasoningText && reasoningText.length > 0) return [{
3438
+ type: "thinking",
3439
+ thinking: reasoningText,
3440
+ signature: reasoningOpaque || ""
3441
+ }];
3442
+ if (reasoningOpaque && reasoningOpaque.length > 0) return [{
3443
+ type: "thinking",
3444
+ thinking: THINKING_TEXT,
3445
+ signature: reasoningOpaque
3446
+ }];
3447
+ return [];
3448
+ }
3449
+ function getAnthropicToolUseBlocks(toolCalls) {
3450
+ if (!toolCalls) return [];
3451
+ return toolCalls.map((toolCall) => ({
3452
+ type: "tool_use",
3453
+ id: toolCall.id,
3454
+ name: toolCall.function.name,
3455
+ input: JSON.parse(toolCall.function.arguments)
3456
+ }));
3457
+ }
3582
3458
 
3583
3459
  //#endregion
3584
- //#region src/routes/messages/utils.ts
3585
- function mapOpenAIStopReasonToAnthropic(finishReason) {
3586
- if (finishReason === null) return null;
3587
- return {
3588
- stop: "end_turn",
3589
- length: "max_tokens",
3590
- tool_calls: "tool_use",
3591
- content_filter: "end_turn"
3592
- }[finishReason];
3460
+ //#region src/routes/messages/count-tokens-handler.ts
3461
+ /**
3462
+ * Handles token counting for Anthropic messages
3463
+ */
3464
+ async function handleCountTokens(c) {
3465
+ try {
3466
+ const anthropicBeta = c.req.header("anthropic-beta");
3467
+ const anthropicPayload = await c.req.json();
3468
+ const openAIPayload = translateToOpenAI(anthropicPayload);
3469
+ const selectedModel = findEndpointModel(anthropicPayload.model);
3470
+ anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
3471
+ if (!selectedModel) {
3472
+ consola.warn("Model not found, returning default token count");
3473
+ return c.json({ input_tokens: 1 });
3474
+ }
3475
+ const tokenCount = await getTokenCount(openAIPayload, selectedModel);
3476
+ if (anthropicPayload.tools && anthropicPayload.tools.length > 0) {
3477
+ let addToolSystemPromptCount = false;
3478
+ if (anthropicBeta) {
3479
+ const toolsLength = anthropicPayload.tools.length;
3480
+ addToolSystemPromptCount = !anthropicPayload.tools.some((tool) => tool.name.startsWith("mcp__") || tool.name === "Skill" && toolsLength === 1);
3481
+ }
3482
+ if (addToolSystemPromptCount) {
3483
+ if (anthropicPayload.model.startsWith("claude")) tokenCount.input = tokenCount.input + 346;
3484
+ else if (anthropicPayload.model.startsWith("grok")) tokenCount.input = tokenCount.input + 120;
3485
+ }
3486
+ }
3487
+ let finalTokenCount = tokenCount.input + tokenCount.output;
3488
+ if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * 1.15);
3489
+ consola.info("Token count:", finalTokenCount);
3490
+ return c.json({ input_tokens: finalTokenCount });
3491
+ } catch (error) {
3492
+ consola.error("Error counting tokens:", error);
3493
+ return c.json({ input_tokens: 1 });
3494
+ }
3593
3495
  }
3594
- const mergeContentWithText = (toolResult, textBlock) => {
3595
- if (typeof toolResult.content === "string") return {
3596
- ...toolResult,
3597
- content: `${toolResult.content}\n\n${textBlock.text}`
3496
+
3497
+ //#endregion
3498
+ //#region src/services/copilot/create-responses.ts
3499
+ const createResponses = async (payload, { vision, initiator, upstreamRequestId, subagentMarker, sessionId, isCompact }, account) => {
3500
+ const ctx = account ?? accountFromState();
3501
+ if (!ctx.copilotToken) throw new Error("Copilot token not found");
3502
+ const headers = {
3503
+ ...copilotHeaders(ctx, vision, upstreamRequestId),
3504
+ "x-initiator": initiator
3598
3505
  };
3506
+ prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
3507
+ prepareForCompact(headers, isCompact);
3508
+ payload.service_tier = null;
3509
+ const response = await fetch(`${copilotBaseUrl(ctx)}/responses`, {
3510
+ method: "POST",
3511
+ headers,
3512
+ body: JSON.stringify(payload)
3513
+ });
3514
+ if (!response.ok) {
3515
+ consola.error("Failed to create responses", response);
3516
+ throw new HTTPError("Failed to create responses", response);
3517
+ }
3518
+ if (payload.stream) return events(response);
3519
+ return await response.json();
3520
+ };
3521
+
3522
+ //#endregion
3523
+ //#region src/routes/messages/responses-translation.ts
3524
+ const MESSAGE_TYPE = "message";
3525
+ const COMPACTION_SIGNATURE_PREFIX = "cm1#";
3526
+ const COMPACTION_SIGNATURE_SEPARATOR = "@";
3527
+ const THINKING_TEXT$1 = "Thinking...";
3528
+ const translateAnthropicMessagesToResponsesPayload = (payload, modelOverride) => {
3529
+ const model = modelOverride ?? payload.model;
3530
+ const input = [];
3531
+ const applyPhase = shouldApplyPhase(payload.model);
3532
+ for (const message of payload.messages) input.push(...translateMessage(message, payload.model, applyPhase));
3533
+ const translatedTools = convertAnthropicTools(payload.tools);
3534
+ const toolChoice = convertAnthropicToolChoice(payload.tool_choice);
3535
+ const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(payload.metadata?.user_id);
3599
3536
  return {
3600
- ...toolResult,
3601
- content: [...toolResult.content, textBlock]
3537
+ model,
3538
+ input,
3539
+ instructions: translateSystemPrompt(payload.system, model),
3540
+ temperature: 1,
3541
+ top_p: payload.top_p ?? null,
3542
+ max_output_tokens: Math.max(payload.max_tokens, 12800),
3543
+ tools: translatedTools,
3544
+ tool_choice: toolChoice,
3545
+ metadata: payload.metadata ? { ...payload.metadata } : null,
3546
+ safety_identifier: safetyIdentifier,
3547
+ prompt_cache_key: promptCacheKey,
3548
+ stream: payload.stream ?? null,
3549
+ store: false,
3550
+ parallel_tool_calls: true,
3551
+ reasoning: {
3552
+ effort: getReasoningEffortForModel(model),
3553
+ summary: "auto"
3554
+ },
3555
+ include: ["reasoning.encrypted_content"]
3602
3556
  };
3603
3557
  };
3604
- const mergeContentWithTexts = (toolResult, textBlocks) => {
3605
- if (typeof toolResult.content === "string") {
3606
- const appendedTexts = textBlocks.map((tb) => tb.text).join("\n\n");
3558
+ const encodeCompactionCarrierSignature = (compaction) => {
3559
+ return `${COMPACTION_SIGNATURE_PREFIX}${compaction.encrypted_content}${COMPACTION_SIGNATURE_SEPARATOR}${compaction.id}`;
3560
+ };
3561
+ const decodeCompactionCarrierSignature = (signature) => {
3562
+ if (signature.startsWith(COMPACTION_SIGNATURE_PREFIX)) {
3563
+ const raw = signature.slice(4);
3564
+ const separatorIndex = raw.indexOf(COMPACTION_SIGNATURE_SEPARATOR);
3565
+ if (separatorIndex <= 0 || separatorIndex === raw.length - 1) return;
3566
+ const encrypted_content = raw.slice(0, separatorIndex);
3567
+ const id = raw.slice(separatorIndex + 1);
3568
+ if (!encrypted_content) return;
3607
3569
  return {
3608
- ...toolResult,
3609
- content: `${toolResult.content}\n\n${appendedTexts}`
3570
+ id,
3571
+ encrypted_content
3610
3572
  };
3611
3573
  }
3612
- return {
3613
- ...toolResult,
3614
- content: [...toolResult.content, ...textBlocks]
3615
- };
3616
3574
  };
3617
- const mergeToolResult = (toolResults, textBlocks) => {
3618
- if (toolResults.length === textBlocks.length) return toolResults.map((toolResult, index) => mergeContentWithText(toolResult, textBlocks[index]));
3619
- const lastIndex = toolResults.length - 1;
3620
- return toolResults.map((toolResult, index) => index === lastIndex ? mergeContentWithTexts(toolResult, textBlocks) : toolResult);
3575
+ const translateMessage = (message, model, applyPhase) => {
3576
+ if (message.role === "user") return translateUserMessage(message);
3577
+ return translateAssistantMessage(message, model, applyPhase);
3621
3578
  };
3622
- const mergeToolResultForClaude = (anthropicPayload) => {
3623
- for (const msg of anthropicPayload.messages) {
3624
- if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
3625
- const toolResults = [];
3626
- const textBlocks = [];
3627
- let valid = true;
3628
- for (const block of msg.content) if (block.type === "tool_result") toolResults.push(block);
3629
- else if (block.type === "text") textBlocks.push(block);
3630
- else {
3631
- valid = false;
3632
- break;
3579
+ const translateUserMessage = (message) => {
3580
+ if (typeof message.content === "string") return [createMessage("user", message.content)];
3581
+ if (!Array.isArray(message.content)) return [];
3582
+ const items = [];
3583
+ const pendingContent = [];
3584
+ for (const block of message.content) {
3585
+ if (block.type === "tool_result") {
3586
+ flushPendingContent(pendingContent, items, { role: "user" });
3587
+ items.push(createFunctionCallOutput(block));
3588
+ continue;
3633
3589
  }
3634
- if (!valid || toolResults.length === 0 || textBlocks.length === 0) continue;
3635
- msg.content = mergeToolResult(toolResults, textBlocks);
3590
+ const converted = translateUserContentBlock(block);
3591
+ if (converted) pendingContent.push(converted);
3636
3592
  }
3593
+ flushPendingContent(pendingContent, items, { role: "user" });
3594
+ return items;
3637
3595
  };
3638
- const estimateInputTokens = async (payload, selectedModel, logger$7) => {
3639
- try {
3640
- return (await getTokenCount(payload, selectedModel)).input;
3641
- } catch (error) {
3642
- logger$7.warn("Failed to estimate input tokens for message_start", error);
3643
- return;
3596
+ const translateAssistantMessage = (message, model, applyPhase) => {
3597
+ const assistantPhase = resolveAssistantPhase(model, message.content, applyPhase);
3598
+ if (typeof message.content === "string") return [createMessage("assistant", message.content, assistantPhase)];
3599
+ if (!Array.isArray(message.content)) return [];
3600
+ const items = [];
3601
+ const pendingContent = [];
3602
+ for (const block of message.content) {
3603
+ if (block.type === "tool_use") {
3604
+ flushPendingContent(pendingContent, items, {
3605
+ role: "assistant",
3606
+ phase: assistantPhase
3607
+ });
3608
+ items.push(createFunctionToolCall(block));
3609
+ continue;
3610
+ }
3611
+ if (block.type === "thinking" && block.signature) {
3612
+ const compactionContent = createCompactionContent(block);
3613
+ if (compactionContent) {
3614
+ flushPendingContent(pendingContent, items, {
3615
+ role: "assistant",
3616
+ phase: assistantPhase
3617
+ });
3618
+ items.push(compactionContent);
3619
+ continue;
3620
+ }
3621
+ if (block.signature.includes("@")) {
3622
+ flushPendingContent(pendingContent, items, {
3623
+ role: "assistant",
3624
+ phase: assistantPhase
3625
+ });
3626
+ items.push(createReasoningContent(block));
3627
+ continue;
3628
+ }
3629
+ }
3630
+ const converted = translateAssistantContentBlock(block);
3631
+ if (converted) pendingContent.push(converted);
3644
3632
  }
3633
+ flushPendingContent(pendingContent, items, {
3634
+ role: "assistant",
3635
+ phase: assistantPhase
3636
+ });
3637
+ return items;
3645
3638
  };
3646
- const isWarmupProbeRequest = (payload) => {
3647
- const lastMsg = payload.messages.at(-1);
3648
- if (!lastMsg || lastMsg.role !== "user" || !Array.isArray(lastMsg.content)) return false;
3649
- const lastBlock = lastMsg.content.at(-1);
3650
- if (!lastBlock || lastBlock.type !== "text") return false;
3651
- const text = lastBlock.text.trim().toLowerCase();
3652
- if (!(lastBlock.cache_control?.type === "ephemeral")) return false;
3653
- if (text === "warmup") return true;
3654
- if (text === "hello") {
3655
- const preludeBlocks = lastMsg.content.slice(0, -1);
3656
- if (preludeBlocks.length === 0) return false;
3657
- return preludeBlocks.every((block) => block.type === "text" && block.text.trimStart().toLowerCase().startsWith("<system-reminder"));
3639
+ const translateUserContentBlock = (block) => {
3640
+ switch (block.type) {
3641
+ case "text": return createTextContent(block.text);
3642
+ case "image": return createImageContent(block);
3643
+ default: return;
3658
3644
  }
3659
- return false;
3660
3645
  };
3661
- const handleSelectionFailure = (context) => {
3662
- const { c, store, requestId, startedAtMs, method, path: path$2, streamRequested, clientModel, clientIp, clientIpSource, userAgent, userId, safetyIdentifier, promptCacheKey, initiator, selection } = context;
3663
- const finishedAtMs = Date.now();
3664
- store.insert({
3665
- requestId,
3666
- startedAtMs,
3667
- finishedAtMs,
3668
- durationMs: finishedAtMs - startedAtMs,
3669
- method,
3670
- path: path$2,
3671
- stream: streamRequested,
3672
- clientModel,
3673
- clientIp,
3674
- clientIpSource,
3675
- userAgent,
3676
- userId,
3677
- safetyIdentifier,
3678
- promptCacheKey,
3679
- initiator,
3680
- httpStatus: selection.reason === "MODEL_NOT_SUPPORTED" ? 400 : 429,
3681
- selectionFailureReason: selection.reason
3682
- });
3683
- if (selection.reason === "MODEL_NOT_SUPPORTED") return c.json({ error: {
3684
- message: `Model "${clientModel}" is not available for any configured account.`,
3685
- type: "invalid_request_error"
3686
- } }, 400);
3687
- return c.json({ error: {
3688
- message: "All accounts have exhausted their quota. Please wait for quota refresh or add additional accounts.",
3689
- type: "rate_limit_error"
3690
- } }, 429);
3646
+ const translateAssistantContentBlock = (block) => {
3647
+ switch (block.type) {
3648
+ case "text": return createOutPutTextContent(block.text);
3649
+ default: return;
3650
+ }
3651
+ };
3652
+ const flushPendingContent = (pendingContent, target, message) => {
3653
+ if (pendingContent.length === 0) return;
3654
+ const messageContent = [...pendingContent];
3655
+ target.push(createMessage(message.role, messageContent, message.phase));
3656
+ pendingContent.length = 0;
3657
+ };
3658
+ const createMessage = (role, content, phase) => ({
3659
+ type: MESSAGE_TYPE,
3660
+ role,
3661
+ content,
3662
+ ...role === "assistant" && phase ? { phase } : {}
3663
+ });
3664
+ const resolveAssistantPhase = (_model, content, applyPhase) => {
3665
+ if (!applyPhase) return;
3666
+ if (typeof content === "string") return "final_answer";
3667
+ if (!Array.isArray(content)) return;
3668
+ if (!content.some((block) => block.type === "text")) return;
3669
+ return content.some((block) => block.type === "tool_use") ? "commentary" : "final_answer";
3670
+ };
3671
+ const shouldApplyPhase = (model) => {
3672
+ return getExtraPromptForModel(model).includes("## Intermediary updates");
3673
+ };
3674
+ const createTextContent = (text) => ({
3675
+ type: "input_text",
3676
+ text
3677
+ });
3678
+ const createOutPutTextContent = (text) => ({
3679
+ type: "output_text",
3680
+ text
3681
+ });
3682
+ const createImageContent = (block) => ({
3683
+ type: "input_image",
3684
+ image_url: `data:${block.source.media_type};base64,${block.source.data}`,
3685
+ detail: "auto"
3686
+ });
3687
+ const createReasoningContent = (block) => {
3688
+ const { encryptedContent, id } = parseReasoningSignature(block.signature);
3689
+ const thinking = block.thinking === THINKING_TEXT$1 ? "" : block.thinking;
3690
+ return {
3691
+ id,
3692
+ type: "reasoning",
3693
+ summary: thinking ? [{
3694
+ type: "summary_text",
3695
+ text: thinking
3696
+ }] : [],
3697
+ encrypted_content: encryptedContent
3698
+ };
3691
3699
  };
3692
- const maybeBlockOriginalModelName = (context) => {
3693
- if (!getAliasTargetSet().has(context.clientModel.toLowerCase())) return null;
3694
- return handleSelectionFailure({
3695
- ...context,
3696
- selection: {
3697
- ok: false,
3698
- reason: "MODEL_NOT_SUPPORTED"
3699
- }
3700
- });
3700
+ const createCompactionContent = (block) => {
3701
+ const compaction = decodeCompactionCarrierSignature(block.signature);
3702
+ if (!compaction) return;
3703
+ return {
3704
+ id: compaction.id,
3705
+ type: "compaction",
3706
+ encrypted_content: compaction.encrypted_content
3707
+ };
3701
3708
  };
3702
-
3703
- //#endregion
3704
- //#region src/routes/messages/non-stream-translation.ts
3705
- const THINKING_TEXT = "Thinking...";
3706
- function translateToOpenAI(payload) {
3707
- const modelId = payload.model;
3708
- const model = state.models?.data.find((m) => m.id === modelId);
3709
- const thinkingBudget = getThinkingBudget(payload, model);
3709
+ const parseReasoningSignature = (signature) => {
3710
+ const splitIndex = signature.lastIndexOf("@");
3711
+ if (splitIndex <= 0 || splitIndex === signature.length - 1) return {
3712
+ encryptedContent: signature,
3713
+ id: ""
3714
+ };
3710
3715
  return {
3711
- model: modelId,
3712
- messages: translateAnthropicMessagesToOpenAI(payload, modelId, thinkingBudget),
3713
- max_tokens: payload.max_tokens,
3714
- stop: payload.stop_sequences,
3715
- stream: payload.stream,
3716
- temperature: payload.temperature,
3717
- top_p: payload.top_p,
3718
- user: payload.metadata?.user_id,
3719
- tools: translateAnthropicToolsToOpenAI(payload.tools),
3720
- tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice),
3721
- thinking_budget: thinkingBudget
3716
+ encryptedContent: signature.slice(0, splitIndex),
3717
+ id: signature.slice(splitIndex + 1)
3722
3718
  };
3723
- }
3724
- function getThinkingBudget(payload, model) {
3725
- const thinking = payload.thinking;
3726
- if (model && thinking) {
3727
- const maxThinkingBudget = Math.min(model.capabilities.supports.max_thinking_budget ?? 0, (model.capabilities.limits.max_output_tokens ?? 0) - 1);
3728
- thinking.budget_tokens ??= maxThinkingBudget;
3729
- if (maxThinkingBudget > 0) {
3730
- const budgetTokens = Math.min(thinking.budget_tokens, maxThinkingBudget);
3731
- return Math.max(budgetTokens, model.capabilities.supports.min_thinking_budget ?? 1024);
3732
- }
3733
- }
3734
- }
3735
- function translateAnthropicMessagesToOpenAI(payload, modelId, _thinkingBudget) {
3736
- const systemMessages = handleSystemPrompt(payload.system);
3737
- const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message) : handleAssistantMessage(message, modelId));
3738
- return [...systemMessages, ...otherMessages];
3739
- }
3740
- function handleSystemPrompt(system) {
3741
- if (!system) return [];
3742
- if (typeof system === "string") return [{
3743
- role: "system",
3744
- content: system
3745
- }];
3746
- else return [{
3747
- role: "system",
3748
- content: system.map((block) => {
3749
- return block.text;
3750
- }).join("\n\n")
3751
- }];
3752
- }
3753
- function handleUserMessage(message) {
3754
- const newMessages = [];
3755
- if (Array.isArray(message.content)) {
3756
- const toolResultBlocks = message.content.filter((block) => block.type === "tool_result");
3757
- const otherBlocks = message.content.filter((block) => block.type !== "tool_result");
3758
- for (const block of toolResultBlocks) newMessages.push({
3759
- role: "tool",
3760
- tool_call_id: block.tool_use_id,
3761
- content: mapContent(block.content)
3762
- });
3763
- if (otherBlocks.length > 0) newMessages.push({
3764
- role: "user",
3765
- content: mapContent(otherBlocks)
3766
- });
3767
- } else newMessages.push({
3768
- role: "user",
3769
- content: mapContent(message.content)
3770
- });
3771
- return newMessages;
3772
- }
3773
- function handleAssistantMessage(message, modelId) {
3774
- if (!Array.isArray(message.content)) return [{
3775
- role: "assistant",
3776
- content: mapContent(message.content)
3777
- }];
3778
- const toolUseBlocks = message.content.filter((block) => block.type === "tool_use");
3779
- let thinkingBlocks = message.content.filter((block) => block.type === "thinking");
3780
- if (modelId.startsWith("claude")) thinkingBlocks = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT && b.signature && !b.signature.includes("@"));
3781
- const thinkingContents = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT).map((b) => b.thinking);
3782
- const allThinkingContent = thinkingContents.length > 0 ? thinkingContents.join("\n\n") : void 0;
3783
- const signature = thinkingBlocks.find((b) => b.signature)?.signature;
3784
- return toolUseBlocks.length > 0 ? [{
3785
- role: "assistant",
3786
- content: mapContent(message.content),
3787
- reasoning_text: allThinkingContent,
3788
- reasoning_opaque: signature,
3789
- tool_calls: toolUseBlocks.map((toolUse) => ({
3790
- id: toolUse.id,
3791
- type: "function",
3792
- function: {
3793
- name: toolUse.name,
3794
- arguments: JSON.stringify(toolUse.input)
3795
- }
3796
- }))
3797
- }] : [{
3798
- role: "assistant",
3799
- content: mapContent(message.content),
3800
- reasoning_text: allThinkingContent,
3801
- reasoning_opaque: signature
3802
- }];
3803
- }
3804
- function mapContent(content) {
3805
- if (typeof content === "string") return content;
3806
- if (!Array.isArray(content)) return null;
3807
- if (!content.some((block) => block.type === "image")) return content.filter((block) => block.type === "text").map((block) => block.text).join("\n\n");
3808
- const contentParts = [];
3809
- for (const block of content) switch (block.type) {
3810
- case "text":
3811
- contentParts.push({
3812
- type: "text",
3813
- text: block.text
3814
- });
3815
- break;
3816
- case "image":
3817
- contentParts.push({
3818
- type: "image_url",
3819
- image_url: { url: `data:${block.source.media_type};base64,${block.source.data}` }
3820
- });
3821
- break;
3822
- }
3823
- return contentParts;
3824
- }
3825
- function translateAnthropicToolsToOpenAI(anthropicTools) {
3826
- if (!anthropicTools) return;
3827
- return anthropicTools.map((tool) => ({
3719
+ };
3720
+ const createFunctionToolCall = (block) => ({
3721
+ type: "function_call",
3722
+ call_id: block.id,
3723
+ name: block.name,
3724
+ arguments: JSON.stringify(block.input),
3725
+ status: "completed"
3726
+ });
3727
+ const createFunctionCallOutput = (block) => ({
3728
+ type: "function_call_output",
3729
+ call_id: block.tool_use_id,
3730
+ output: convertToolResultContent(block.content),
3731
+ status: block.is_error ? "incomplete" : "completed"
3732
+ });
3733
+ const translateSystemPrompt = (system, model) => {
3734
+ if (!system) return null;
3735
+ const extraPrompt = getExtraPromptForModel(model);
3736
+ if (typeof system === "string") return system + extraPrompt;
3737
+ const text = system.map((block, index) => {
3738
+ if (index === 0) return block.text + extraPrompt;
3739
+ return block.text;
3740
+ }).join(" ");
3741
+ return text.length > 0 ? text : null;
3742
+ };
3743
+ const convertAnthropicTools = (tools) => {
3744
+ if (!tools || tools.length === 0) return null;
3745
+ return tools.map((tool) => ({
3828
3746
  type: "function",
3829
- function: {
3830
- name: tool.name,
3831
- description: tool.description,
3832
- parameters: tool.input_schema
3833
- }
3747
+ name: tool.name,
3748
+ parameters: normalizeToolSchema(tool.input_schema),
3749
+ strict: false,
3750
+ ...tool.description ? { description: tool.description } : {}
3834
3751
  }));
3835
- }
3836
- function translateAnthropicToolChoiceToOpenAI(anthropicToolChoice) {
3837
- if (!anthropicToolChoice) return;
3838
- switch (anthropicToolChoice.type) {
3752
+ };
3753
+ const convertAnthropicToolChoice = (choice) => {
3754
+ if (!choice) return "auto";
3755
+ switch (choice.type) {
3839
3756
  case "auto": return "auto";
3840
3757
  case "any": return "required";
3841
- case "tool":
3842
- if (anthropicToolChoice.name) return {
3843
- type: "function",
3844
- function: { name: anthropicToolChoice.name }
3845
- };
3846
- return;
3758
+ case "tool": return choice.name ? {
3759
+ type: "function",
3760
+ name: choice.name
3761
+ } : "auto";
3847
3762
  case "none": return "none";
3848
- default: return;
3849
- }
3850
- }
3851
- function translateToAnthropic(response) {
3852
- const assistantContentBlocks = [];
3853
- let stopReason = response.choices[0]?.finish_reason ?? null;
3854
- for (const choice of response.choices) {
3855
- const textBlocks = getAnthropicTextBlocks(choice.message.content);
3856
- const thinkBlocks = getAnthropicThinkBlocks(choice.message.reasoning_text, choice.message.reasoning_opaque);
3857
- const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls);
3858
- assistantContentBlocks.push(...thinkBlocks, ...textBlocks, ...toolUseBlocks);
3859
- if (choice.finish_reason === "tool_calls" || stopReason === "stop") stopReason = choice.finish_reason;
3763
+ default: return "auto";
3860
3764
  }
3765
+ };
3766
+ const translateResponsesResultToAnthropic = (response) => {
3767
+ const contentBlocks = mapOutputToAnthropicContent(response.output);
3768
+ const usage = mapResponsesUsage(response);
3769
+ let anthropicContent = fallbackContentBlocks(response.output_text);
3770
+ if (contentBlocks.length > 0) anthropicContent = contentBlocks;
3771
+ const stopReason = mapResponsesStopReason(response);
3861
3772
  return {
3862
3773
  id: response.id,
3863
3774
  type: "message",
3864
3775
  role: "assistant",
3776
+ content: anthropicContent,
3865
3777
  model: response.model,
3866
- content: assistantContentBlocks,
3867
- stop_reason: mapOpenAIStopReasonToAnthropic(stopReason),
3778
+ stop_reason: stopReason,
3868
3779
  stop_sequence: null,
3869
- usage: {
3870
- input_tokens: (response.usage?.prompt_tokens ?? 0) - (response.usage?.prompt_tokens_details?.cached_tokens ?? 0),
3871
- output_tokens: response.usage?.completion_tokens ?? 0,
3872
- ...response.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.prompt_tokens_details.cached_tokens }
3780
+ usage
3781
+ };
3782
+ };
3783
+ const mapOutputToAnthropicContent = (output) => {
3784
+ const contentBlocks = [];
3785
+ for (const item of output) switch (item.type) {
3786
+ case "reasoning": {
3787
+ const thinkingText = extractReasoningText(item);
3788
+ if (thinkingText.length > 0) contentBlocks.push({
3789
+ type: "thinking",
3790
+ thinking: thinkingText,
3791
+ signature: (item.encrypted_content ?? "") + "@" + item.id
3792
+ });
3793
+ break;
3794
+ }
3795
+ case "function_call": {
3796
+ const toolUseBlock = createToolUseContentBlock(item);
3797
+ if (toolUseBlock) contentBlocks.push(toolUseBlock);
3798
+ break;
3799
+ }
3800
+ case "message": {
3801
+ const combinedText = combineMessageTextContent(item.content);
3802
+ if (combinedText.length > 0) contentBlocks.push({
3803
+ type: "text",
3804
+ text: combinedText
3805
+ });
3806
+ break;
3807
+ }
3808
+ case "compaction": {
3809
+ const compactionBlock = createCompactionThinkingBlock(item);
3810
+ if (compactionBlock) contentBlocks.push(compactionBlock);
3811
+ break;
3812
+ }
3813
+ default: {
3814
+ const combinedText = combineMessageTextContent(item.content);
3815
+ if (combinedText.length > 0) contentBlocks.push({
3816
+ type: "text",
3817
+ text: combinedText
3818
+ });
3819
+ }
3820
+ }
3821
+ return contentBlocks;
3822
+ };
3823
+ const combineMessageTextContent = (content) => {
3824
+ if (!Array.isArray(content)) return "";
3825
+ let aggregated = "";
3826
+ for (const block of content) {
3827
+ if (isResponseOutputText(block)) {
3828
+ aggregated += block.text;
3829
+ continue;
3830
+ }
3831
+ if (isResponseOutputRefusal(block)) {
3832
+ aggregated += block.refusal;
3833
+ continue;
3834
+ }
3835
+ if (typeof block.text === "string") {
3836
+ aggregated += block.text;
3837
+ continue;
3838
+ }
3839
+ if (typeof block.reasoning === "string") {
3840
+ aggregated += block.reasoning;
3841
+ continue;
3842
+ }
3843
+ }
3844
+ return aggregated;
3845
+ };
3846
+ const extractReasoningText = (item) => {
3847
+ const segments = [];
3848
+ const collectFromBlocks = (blocks) => {
3849
+ if (!Array.isArray(blocks)) return;
3850
+ for (const block of blocks) if (typeof block.text === "string") {
3851
+ segments.push(block.text);
3852
+ continue;
3873
3853
  }
3874
3854
  };
3875
- }
3876
- function getAnthropicTextBlocks(messageContent) {
3877
- if (typeof messageContent === "string" && messageContent.length > 0) return [{
3878
- type: "text",
3879
- text: messageContent
3880
- }];
3881
- if (Array.isArray(messageContent)) return messageContent.filter((part) => part.type === "text").map((part) => ({
3882
- type: "text",
3883
- text: part.text
3884
- }));
3885
- return [];
3886
- }
3887
- function getAnthropicThinkBlocks(reasoningText, reasoningOpaque) {
3888
- if (reasoningText && reasoningText.length > 0) return [{
3889
- type: "thinking",
3890
- thinking: reasoningText,
3891
- signature: reasoningOpaque || ""
3892
- }];
3893
- if (reasoningOpaque && reasoningOpaque.length > 0) return [{
3894
- type: "thinking",
3895
- thinking: THINKING_TEXT,
3896
- signature: reasoningOpaque
3897
- }];
3898
- return [];
3899
- }
3900
- function getAnthropicToolUseBlocks(toolCalls) {
3901
- if (!toolCalls) return [];
3902
- return toolCalls.map((toolCall) => ({
3855
+ if (!item.summary || item.summary.length === 0) return THINKING_TEXT$1;
3856
+ collectFromBlocks(item.summary);
3857
+ return segments.join("").trim();
3858
+ };
3859
+ const createToolUseContentBlock = (call) => {
3860
+ const toolId = call.call_id;
3861
+ if (!call.name || !toolId) return null;
3862
+ const input = parseFunctionCallArguments(call.arguments);
3863
+ return {
3903
3864
  type: "tool_use",
3904
- id: toolCall.id,
3905
- name: toolCall.function.name,
3906
- input: JSON.parse(toolCall.function.arguments)
3907
- }));
3908
- }
3909
-
3910
- //#endregion
3911
- //#region src/routes/messages/count-tokens-handler.ts
3912
- /**
3913
- * Handles token counting for Anthropic messages
3914
- */
3915
- async function handleCountTokens(c) {
3865
+ id: toolId,
3866
+ name: call.name,
3867
+ input
3868
+ };
3869
+ };
3870
+ const createCompactionThinkingBlock = (item) => {
3871
+ if (!item.id || !item.encrypted_content) return null;
3872
+ return {
3873
+ type: "thinking",
3874
+ thinking: THINKING_TEXT$1,
3875
+ signature: encodeCompactionCarrierSignature({
3876
+ id: item.id,
3877
+ encrypted_content: item.encrypted_content
3878
+ })
3879
+ };
3880
+ };
3881
+ const parseFunctionCallArguments = (rawArguments) => {
3882
+ if (typeof rawArguments !== "string" || rawArguments.trim().length === 0) return {};
3916
3883
  try {
3917
- const anthropicBeta = c.req.header("anthropic-beta");
3918
- const anthropicPayload = await c.req.json();
3919
- const openAIPayload = translateToOpenAI(anthropicPayload);
3920
- const selectedModel = findEndpointModel(anthropicPayload.model);
3921
- anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
3922
- if (!selectedModel) {
3923
- consola.warn("Model not found, returning default token count");
3924
- return c.json({ input_tokens: 1 });
3925
- }
3926
- const tokenCount = await getTokenCount(openAIPayload, selectedModel);
3927
- if (anthropicPayload.tools && anthropicPayload.tools.length > 0) {
3928
- let addToolSystemPromptCount = false;
3929
- if (anthropicBeta) {
3930
- const toolsLength = anthropicPayload.tools.length;
3931
- addToolSystemPromptCount = !anthropicPayload.tools.some((tool) => tool.name.startsWith("mcp__") || tool.name === "Skill" && toolsLength === 1);
3932
- }
3933
- if (addToolSystemPromptCount) {
3934
- if (anthropicPayload.model.startsWith("claude")) tokenCount.input = tokenCount.input + 346;
3935
- else if (anthropicPayload.model.startsWith("grok")) tokenCount.input = tokenCount.input + 120;
3936
- }
3937
- }
3938
- let finalTokenCount = tokenCount.input + tokenCount.output;
3939
- if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * 1.15);
3940
- consola.info("Token count:", finalTokenCount);
3941
- return c.json({ input_tokens: finalTokenCount });
3884
+ const parsed = JSON.parse(rawArguments);
3885
+ if (Array.isArray(parsed)) return { arguments: parsed };
3886
+ if (parsed && typeof parsed === "object") return parsed;
3942
3887
  } catch (error) {
3943
- consola.error("Error counting tokens:", error);
3944
- return c.json({ input_tokens: 1 });
3888
+ consola.warn("Failed to parse function call arguments", {
3889
+ error,
3890
+ rawArguments
3891
+ });
3945
3892
  }
3946
- }
3893
+ return { raw_arguments: rawArguments };
3894
+ };
3895
+ const fallbackContentBlocks = (outputText) => {
3896
+ if (!outputText) return [];
3897
+ return [{
3898
+ type: "text",
3899
+ text: outputText
3900
+ }];
3901
+ };
3902
+ const mapResponsesStopReason = (response) => {
3903
+ const { status, incomplete_details: incompleteDetails } = response;
3904
+ if (status === "completed") {
3905
+ if (response.output.some((item) => item.type === "function_call")) return "tool_use";
3906
+ return "end_turn";
3907
+ }
3908
+ if (status === "incomplete") {
3909
+ if (incompleteDetails?.reason === "max_output_tokens") return "max_tokens";
3910
+ if (incompleteDetails?.reason === "content_filter") return "end_turn";
3911
+ }
3912
+ return null;
3913
+ };
3914
+ const mapResponsesUsage = (response) => {
3915
+ const inputTokens = response.usage?.input_tokens ?? 0;
3916
+ const outputTokens = response.usage?.output_tokens ?? 0;
3917
+ const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
3918
+ return {
3919
+ input_tokens: inputTokens - (inputCachedTokens ?? 0),
3920
+ output_tokens: outputTokens,
3921
+ ...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
3922
+ };
3923
+ };
3924
+ const isRecord = (value) => typeof value === "object" && value !== null;
3925
+ const isResponseOutputText = (block) => isRecord(block) && "type" in block && block.type === "output_text";
3926
+ const isResponseOutputRefusal = (block) => isRecord(block) && "type" in block && block.type === "refusal";
3927
+ const convertToolResultContent = (content) => {
3928
+ if (typeof content === "string") return content;
3929
+ if (Array.isArray(content)) {
3930
+ const result = [];
3931
+ for (const block of content) switch (block.type) {
3932
+ case "text":
3933
+ result.push(createTextContent(block.text));
3934
+ break;
3935
+ case "image":
3936
+ result.push(createImageContent(block));
3937
+ break;
3938
+ default: break;
3939
+ }
3940
+ return result;
3941
+ }
3942
+ return "";
3943
+ };
3947
3944
 
3948
3945
  //#endregion
3949
3946
  //#region src/routes/messages/responses-stream-translation.ts
@@ -4834,7 +4831,7 @@ async function handleCompletion(c) {
4834
4831
  const streamRequested = Boolean(anthropicPayload.stream);
4835
4832
  const rawUserId = anthropicPayload.metadata?.user_id;
4836
4833
  const userId = typeof rawUserId === "string" ? rawUserId : void 0;
4837
- const { safetyIdentifier, promptCacheKey } = parseUserId(userId);
4834
+ const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
4838
4835
  const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
4839
4836
  const normalizedPromptCacheKey = promptCacheKey ?? void 0;
4840
4837
  const blockedResponse = maybeBlockOriginalModelName({
@@ -5865,7 +5862,7 @@ const handleResponses = async (c) => {
5865
5862
  const streamRequested = Boolean(payload.stream);
5866
5863
  const { initiator: initialInitiator } = getResponsesRequestOptions(payload);
5867
5864
  const userId = payload.metadata?.user_id;
5868
- const { safetyIdentifier, promptCacheKey } = parseUserId(userId);
5865
+ const { safetyIdentifier, sessionId: promptCacheKey } = parseUserIdMetadata(userId);
5869
5866
  const normalizedSafetyIdentifier = safetyIdentifier ?? void 0;
5870
5867
  const normalizedPromptCacheKey = promptCacheKey ?? void 0;
5871
5868
  request.userId = userId;
@@ -6398,4 +6395,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
6398
6395
 
6399
6396
  //#endregion
6400
6397
  export { server };
6401
- //# sourceMappingURL=server-COWbIpDR.js.map
6398
+ //# sourceMappingURL=server-D3sySKxC.js.map