@jeffreycao/copilot-api 1.9.4 → 1.9.6

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,6 +1,6 @@
1
1
  import { PATHS } from "./paths-Cla6y5eD.js";
2
2
  import { COMPACT_AUTO_CONTINUE, COMPACT_REQUEST, HTTPError, cacheModels, compactAutoContinuePromptStarts, compactMessageSections, compactSummaryPromptStart, compactSystemPromptStarts, compactTextOnlyGuard, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, generateTraceId, getCopilotUsage, getRootSessionId, getUUID, isNullish, parseUserIdMetadata, prepareForCompact, prepareInteractionHeaders, prepareMessageProxyHeaders, requestContext, resolveTraceId as resolveTraceId$1, sleep, state } from "./utils-DEJvF68W.js";
3
- import { getAnthropicApiKey, getClaudeTokenMultiplier, getConfig, getExtraPromptForModel, getProviderConfig, getReasoningEffortForModel, getSmallModel, isMessagesApiEnabled, isResponsesApiContextManagementModel, isResponsesApiWebSearchEnabled } from "./config-BQvWqYh_.js";
3
+ import { getAnthropicApiKey, getClaudeTokenMultiplier, getConfig, getExtraPromptForModel, getProviderConfig, getReasoningEffortForModel, getSmallModel, isMessagesApiEnabled, isResponsesApiContextManagementModel, isResponsesApiWebSearchEnabled } from "./config-BJt9unC0.js";
4
4
  import consola from "consola";
5
5
  import fs from "node:fs/promises";
6
6
  import path from "node:path";
@@ -1052,7 +1052,10 @@ const calculateToolCallsTokens = (toolCalls, encoder, constants) => {
1052
1052
  const calculateContentPartsTokens = (contentParts, encoder) => {
1053
1053
  let tokens = 0;
1054
1054
  for (const part of contentParts) if (part.type === "image_url") tokens += encoder.encode(part.image_url.url).length + 85;
1055
- else if (part.text) tokens += encoder.encode(part.text).length;
1055
+ else if (part.type === "file") {
1056
+ tokens += encoder.encode(part.file.file_data).length;
1057
+ if (part.file.filename) tokens += encoder.encode(part.file.filename).length;
1058
+ } else if (part.text) tokens += encoder.encode(part.text).length;
1056
1059
  return tokens;
1057
1060
  };
1058
1061
  /**
@@ -1304,13 +1307,19 @@ function mapOpenAIStopReasonToAnthropic(finishReason) {
1304
1307
  //#endregion
1305
1308
  //#region src/routes/messages/non-stream-translation.ts
1306
1309
  const THINKING_TEXT = "Thinking...";
1307
- function translateToOpenAI(payload) {
1310
+ const RICH_TOOL_RESULT_MOVED_TEXT = "Rich tool result content was moved to a user message because this upstream does not support it in tool messages.";
1311
+ const COPILOT_TOOL_CONTENT_SUPPORT_TYPE = ["array", "image"];
1312
+ function translateToOpenAI(payload, options = {}) {
1308
1313
  const modelId = payload.model;
1309
1314
  const model = state.models?.data.find((m) => m.id === modelId);
1310
1315
  const thinkingBudget = getThinkingBudget(payload, model);
1316
+ const capabilities = {
1317
+ supportPdf: options.supportPdf ?? false,
1318
+ toolContentSupportType: options.toolContentSupportType ?? COPILOT_TOOL_CONTENT_SUPPORT_TYPE
1319
+ };
1311
1320
  return {
1312
1321
  model: modelId,
1313
- messages: translateAnthropicMessagesToOpenAI(payload, modelId, thinkingBudget),
1322
+ messages: translateAnthropicMessagesToOpenAI(payload, modelId, capabilities),
1314
1323
  max_tokens: payload.max_tokens,
1315
1324
  stop: payload.stop_sequences,
1316
1325
  stream: payload.stream,
@@ -1333,9 +1342,9 @@ function getThinkingBudget(payload, model) {
1333
1342
  }
1334
1343
  }
1335
1344
  }
1336
- function translateAnthropicMessagesToOpenAI(payload, modelId, _thinkingBudget) {
1345
+ function translateAnthropicMessagesToOpenAI(payload, modelId, capabilities) {
1337
1346
  const systemMessages = handleSystemPrompt(payload.system);
1338
- const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message) : handleAssistantMessage(message, modelId));
1347
+ const otherMessages = payload.messages.flatMap((message) => message.role === "user" ? handleUserMessage(message, capabilities) : handleAssistantMessage(message, modelId, capabilities));
1339
1348
  return [...systemMessages, ...otherMessages];
1340
1349
  }
1341
1350
  function handleSystemPrompt(system) {
@@ -1351,19 +1360,21 @@ function handleSystemPrompt(system) {
1351
1360
  }).join("\n\n")
1352
1361
  }];
1353
1362
  }
1354
- function handleUserMessage(message) {
1363
+ function handleUserMessage(message, capabilities) {
1355
1364
  const newMessages = [];
1356
1365
  if (Array.isArray(message.content)) {
1357
1366
  const toolResultBlocks = message.content.filter((block) => block.type === "tool_result");
1358
1367
  const otherBlocks = message.content.filter((block) => block.type !== "tool_result");
1359
- for (const block of toolResultBlocks) newMessages.push({
1360
- role: "tool",
1361
- tool_call_id: block.tool_use_id,
1362
- content: mapContent(block.content)
1363
- });
1368
+ const movedToolResultUserMessages = [];
1369
+ for (const block of toolResultBlocks) {
1370
+ const result = handleToolResultBlock(block, capabilities);
1371
+ newMessages.push(result.toolMessage);
1372
+ if (result.movedUserMessage) movedToolResultUserMessages.push(result.movedUserMessage);
1373
+ }
1374
+ newMessages.push(...movedToolResultUserMessages);
1364
1375
  if (otherBlocks.length > 0) newMessages.push({
1365
1376
  role: "user",
1366
- content: mapContent(otherBlocks)
1377
+ content: mapContent(otherBlocks, { supportPdf: capabilities.supportPdf })
1367
1378
  });
1368
1379
  } else newMessages.push({
1369
1380
  role: "user",
@@ -1371,7 +1382,61 @@ function handleUserMessage(message) {
1371
1382
  });
1372
1383
  return newMessages;
1373
1384
  }
1374
- function handleAssistantMessage(message, modelId) {
1385
+ function handleToolResultBlock(block, capabilities) {
1386
+ if (typeof block.content === "string") return { toolMessage: createToolMessage(block.tool_use_id, block.content) };
1387
+ if (!Array.isArray(block.content)) return { toolMessage: createToolMessage(block.tool_use_id, "") };
1388
+ const support = getToolContentSupport(capabilities);
1389
+ const hasImage = block.content.some((block$1) => block$1.type === "image");
1390
+ const hasDocument = block.content.some((block$1) => block$1.type === "document");
1391
+ const content = mapContent(block.content, { supportPdf: capabilities.supportPdf });
1392
+ const hasPdfFile = hasDocument && capabilities.supportPdf;
1393
+ const shouldMoveImageToUserMessage = hasImage && !support.image;
1394
+ const shouldMovePdfToUserMessage = hasPdfFile && !support.pdf;
1395
+ if (shouldMoveImageToUserMessage || shouldMovePdfToUserMessage) return {
1396
+ movedUserMessage: createToolResultUserMessage(block, capabilities.supportPdf),
1397
+ toolMessage: createToolMessage(block.tool_use_id, getTextToolContent(content) || RICH_TOOL_RESULT_MOVED_TEXT)
1398
+ };
1399
+ const hasRichContent = hasImage || hasPdfFile;
1400
+ if (support.array || hasRichContent) return { toolMessage: createToolMessage(block.tool_use_id, content) };
1401
+ return { toolMessage: createToolMessage(block.tool_use_id, getTextToolContent(content)) };
1402
+ }
1403
+ function getTextToolContent(content) {
1404
+ if (!Array.isArray(content)) return content ?? "";
1405
+ return content.flatMap((part) => part.type === "text" && part.text.length > 0 ? [part.text] : []).join("\n");
1406
+ }
1407
+ function getToolContentSupport(capabilities) {
1408
+ return {
1409
+ array: capabilities.toolContentSupportType.includes("array"),
1410
+ image: capabilities.toolContentSupportType.includes("image"),
1411
+ pdf: capabilities.supportPdf && capabilities.toolContentSupportType.includes("pdf")
1412
+ };
1413
+ }
1414
+ function createToolMessage(toolCallId, content) {
1415
+ return {
1416
+ role: "tool",
1417
+ tool_call_id: toolCallId,
1418
+ content
1419
+ };
1420
+ }
1421
+ function createToolResultUserMessage(block, supportPdf) {
1422
+ const prefix = {
1423
+ type: "text",
1424
+ text: `Tool result for ${block.tool_use_id}:`
1425
+ };
1426
+ const content = mapContent(block.content, { supportPdf });
1427
+ if (Array.isArray(content)) return {
1428
+ role: "user",
1429
+ content: [prefix, ...content]
1430
+ };
1431
+ return {
1432
+ role: "user",
1433
+ content: [prefix, {
1434
+ type: "text",
1435
+ text: content ?? ""
1436
+ }]
1437
+ };
1438
+ }
1439
+ function handleAssistantMessage(message, modelId, capabilities) {
1375
1440
  if (!Array.isArray(message.content)) return [{
1376
1441
  role: "assistant",
1377
1442
  content: mapContent(message.content)
@@ -1384,7 +1449,7 @@ function handleAssistantMessage(message, modelId) {
1384
1449
  const signature = thinkingBlocks.find((b) => b.signature)?.signature;
1385
1450
  return toolUseBlocks.length > 0 ? [{
1386
1451
  role: "assistant",
1387
- content: mapContent(message.content),
1452
+ content: mapContent(message.content, { supportPdf: capabilities.supportPdf }),
1388
1453
  reasoning_text: allThinkingContent,
1389
1454
  reasoning_opaque: signature,
1390
1455
  tool_calls: toolUseBlocks.map((toolUse) => ({
@@ -1397,12 +1462,12 @@ function handleAssistantMessage(message, modelId) {
1397
1462
  }))
1398
1463
  }] : [{
1399
1464
  role: "assistant",
1400
- content: mapContent(message.content),
1465
+ content: mapContent(message.content, { supportPdf: capabilities.supportPdf }),
1401
1466
  reasoning_text: allThinkingContent,
1402
1467
  reasoning_opaque: signature
1403
1468
  }];
1404
1469
  }
1405
- function mapContent(content) {
1470
+ function mapContent(content, options = {}) {
1406
1471
  if (typeof content === "string") return content;
1407
1472
  if (!Array.isArray(content)) return null;
1408
1473
  const contentParts = [];
@@ -1420,7 +1485,7 @@ function mapContent(content) {
1420
1485
  });
1421
1486
  break;
1422
1487
  case "document":
1423
- contentParts.push(createDocumentTextPart());
1488
+ contentParts.push(options.supportPdf ? createDocumentFilePart(block) : createDocumentTextPart());
1424
1489
  break;
1425
1490
  case "tool_reference":
1426
1491
  contentParts.push({
@@ -1434,7 +1499,16 @@ function mapContent(content) {
1434
1499
  function createDocumentTextPart() {
1435
1500
  return {
1436
1501
  type: "text",
1437
- text: "A PDF document was attached, but this api cannot send PDF inputs directly. Analyze using other tools."
1502
+ text: "PDF/document content is not supported by this Chat Completions upstream. Use the available text extracted from the document."
1503
+ };
1504
+ }
1505
+ function createDocumentFilePart(block) {
1506
+ return {
1507
+ type: "file",
1508
+ file: {
1509
+ file_data: `data:${block.source.media_type};base64,${block.source.data}`,
1510
+ filename: block.title ?? "document.pdf"
1511
+ }
1438
1512
  };
1439
1513
  }
1440
1514
  function translateAnthropicToolsToOpenAI(anthropicTools) {
@@ -1479,7 +1553,7 @@ function translateToAnthropic(response) {
1479
1553
  let stopReason = response.choices[0]?.finish_reason ?? null;
1480
1554
  for (const choice of response.choices) {
1481
1555
  const textBlocks = getAnthropicTextBlocks(choice.message.content);
1482
- const thinkBlocks = getAnthropicThinkBlocks(choice.message.reasoning_text, choice.message.reasoning_opaque);
1556
+ const thinkBlocks = getAnthropicThinkBlocks(getOpenAIReasoningText(choice.message), choice.message.reasoning_opaque);
1483
1557
  const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls);
1484
1558
  assistantContentBlocks.push(...thinkBlocks, ...textBlocks, ...toolUseBlocks);
1485
1559
  if (choice.finish_reason === "tool_calls" || stopReason === "stop") stopReason = choice.finish_reason;
@@ -1499,6 +1573,9 @@ function translateToAnthropic(response) {
1499
1573
  }
1500
1574
  };
1501
1575
  }
1576
+ function getOpenAIReasoningText(message) {
1577
+ return message.reasoning_text ?? message.reasoning_content;
1578
+ }
1502
1579
  function getAnthropicTextBlocks(messageContent) {
1503
1580
  if (typeof messageContent === "string" && messageContent.length > 0) return [{
1504
1581
  type: "text",
@@ -2860,7 +2937,10 @@ function isToolBlockOpen(state$1) {
2860
2937
  }
2861
2938
  function translateChunkToAnthropicEvents(chunk, state$1) {
2862
2939
  const events$1 = [];
2863
- if (chunk.choices.length === 0) return events$1;
2940
+ if (chunk.choices.length === 0) {
2941
+ completePendingMessage(state$1, events$1, chunk);
2942
+ return events$1;
2943
+ }
2864
2944
  const choice = chunk.choices[0];
2865
2945
  const { delta } = choice;
2866
2946
  handleMessageStart(state$1, events$1, chunk);
@@ -2873,6 +2953,17 @@ function translateChunkToAnthropicEvents(chunk, state$1) {
2873
2953
  });
2874
2954
  return events$1;
2875
2955
  }
2956
+ function flushPendingAnthropicStreamEvents(state$1) {
2957
+ const events$1 = [];
2958
+ completePendingMessage(state$1, events$1);
2959
+ return events$1;
2960
+ }
2961
+ function completePendingMessage(state$1, events$1, chunk) {
2962
+ if (!state$1.pendingMessageDelta) return;
2963
+ if (chunk?.usage) state$1.pendingMessageDelta.usage = getAnthropicUsageFromOpenAIChunk(chunk);
2964
+ events$1.push(state$1.pendingMessageDelta, { type: "message_stop" });
2965
+ state$1.pendingMessageDelta = void 0;
2966
+ }
2876
2967
  function handleFinish(choice, state$1, context) {
2877
2968
  const { events: events$1, chunk } = context;
2878
2969
  if (choice.finish_reason && choice.finish_reason.length > 0) {
@@ -2886,20 +2977,24 @@ function handleFinish(choice, state$1, context) {
2886
2977
  state$1.contentBlockIndex++;
2887
2978
  if (!toolBlockOpen) handleReasoningOpaque(choice.delta, events$1, state$1);
2888
2979
  }
2889
- events$1.push({
2980
+ state$1.pendingMessageDelta = {
2890
2981
  type: "message_delta",
2891
2982
  delta: {
2892
2983
  stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),
2893
2984
  stop_sequence: null
2894
2985
  },
2895
- usage: {
2896
- input_tokens: (chunk.usage?.prompt_tokens ?? 0) - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),
2897
- output_tokens: chunk.usage?.completion_tokens ?? 0,
2898
- ...chunk.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: chunk.usage.prompt_tokens_details.cached_tokens }
2899
- }
2900
- }, { type: "message_stop" });
2986
+ usage: getAnthropicUsageFromOpenAIChunk(chunk)
2987
+ };
2988
+ if (chunk.usage) completePendingMessage(state$1, events$1, chunk);
2901
2989
  }
2902
2990
  }
2991
+ function getAnthropicUsageFromOpenAIChunk(chunk) {
2992
+ return {
2993
+ input_tokens: (chunk.usage?.prompt_tokens ?? 0) - (chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0),
2994
+ output_tokens: chunk.usage?.completion_tokens ?? 0,
2995
+ ...chunk.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: chunk.usage.prompt_tokens_details.cached_tokens }
2996
+ };
2997
+ }
2903
2998
  function handleToolCalls(delta, state$1, events$1) {
2904
2999
  if (delta.tool_calls && delta.tool_calls.length > 0) {
2905
3000
  closeThinkingBlockIfOpen(state$1, events$1);
@@ -3057,10 +3152,12 @@ function handleReasoningOpaque(delta, events$1, state$1) {
3057
3152
  }
3058
3153
  }
3059
3154
  function handleThinkingText(delta, state$1, events$1) {
3060
- if (delta.reasoning_text && delta.reasoning_text.length > 0) {
3155
+ const reasoningText = delta.reasoning_text ?? delta.reasoning_content;
3156
+ if (reasoningText && reasoningText.length > 0) {
3061
3157
  if (state$1.contentBlockOpen) {
3062
- delta.content = delta.reasoning_text;
3158
+ delta.content = reasoningText;
3063
3159
  delta.reasoning_text = void 0;
3160
+ delta.reasoning_content = void 0;
3064
3161
  return;
3065
3162
  }
3066
3163
  if (!state$1.thinkingBlockOpen) {
@@ -3079,7 +3176,7 @@ function handleThinkingText(delta, state$1, events$1) {
3079
3176
  index: state$1.contentBlockIndex,
3080
3177
  delta: {
3081
3178
  type: "thinking_delta",
3082
- thinking: delta.reasoning_text
3179
+ thinking: reasoningText
3083
3180
  }
3084
3181
  });
3085
3182
  }
@@ -3153,6 +3250,14 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
3153
3250
  });
3154
3251
  }
3155
3252
  }
3253
+ for (const event of flushPendingAnthropicStreamEvents(streamState)) {
3254
+ const eventData = JSON.stringify(event);
3255
+ debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
3256
+ await stream.writeSSE({
3257
+ event: event.type,
3258
+ data: eventData
3259
+ });
3260
+ }
3156
3261
  recordUsage(usage);
3157
3262
  });
3158
3263
  };
@@ -3419,16 +3524,19 @@ const modelRoutes = new Hono();
3419
3524
  modelRoutes.get("/", async (c) => {
3420
3525
  try {
3421
3526
  if (!state.models) await cacheModels();
3422
- const models = state.models?.data.map((model) => ({
3423
- ...model,
3424
- id: model.id,
3425
- object: "model",
3426
- type: "model",
3427
- created: 0,
3428
- created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
3429
- owned_by: model.vendor,
3430
- display_name: model.name
3431
- }));
3527
+ const models = state.models?.data.map((model) => {
3528
+ const is1m = model.capabilities.limits?.max_context_window_tokens === 1e6;
3529
+ return {
3530
+ ...model,
3531
+ id: is1m ? `${model.id}[1m]` : model.id,
3532
+ object: "model",
3533
+ type: "model",
3534
+ created: 0,
3535
+ created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
3536
+ owned_by: model.vendor,
3537
+ display_name: model.name
3538
+ };
3539
+ });
3432
3540
  return c.json({
3433
3541
  object: "list",
3434
3542
  data: models,
@@ -3463,8 +3571,14 @@ async function handleProviderCountTokens(c) {
3463
3571
  const provider = c.req.param("provider");
3464
3572
  try {
3465
3573
  const anthropicPayload = await c.req.json();
3466
- const openAIPayload = translateToOpenAI(anthropicPayload);
3467
3574
  const modelId = anthropicPayload.model.trim();
3575
+ const providerConfig = getProviderConfig(provider);
3576
+ const modelConfig = providerConfig?.models?.[modelId];
3577
+ const translationOptions = providerConfig?.type === "openai-compatible" ? {
3578
+ supportPdf: modelConfig?.supportPdf,
3579
+ toolContentSupportType: modelConfig?.toolContentSupportType ?? []
3580
+ } : void 0;
3581
+ const openAIPayload = translateToOpenAI(anthropicPayload, translationOptions);
3468
3582
  let selectedModel = state.models?.data.find((model) => model.id === modelId);
3469
3583
  if (!selectedModel && modelId) selectedModel = createFallbackModel(modelId);
3470
3584
  if (!selectedModel) {
@@ -3493,12 +3607,8 @@ async function handleProviderCountTokens(c) {
3493
3607
 
3494
3608
  //#endregion
3495
3609
  //#region src/services/providers/anthropic-proxy.ts
3496
- const FORWARDABLE_HEADERS = [
3497
- "anthropic-version",
3498
- "anthropic-beta",
3499
- "accept",
3500
- "user-agent"
3501
- ];
3610
+ const SHARED_FORWARDABLE_HEADERS = ["accept", "user-agent"];
3611
+ const ANTHROPIC_FORWARDABLE_HEADERS = ["anthropic-version", "anthropic-beta"];
3502
3612
  const STRIPPED_RESPONSE_HEADERS = [
3503
3613
  "connection",
3504
3614
  "content-encoding",
@@ -3520,7 +3630,12 @@ function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
3520
3630
  accept: "application/json",
3521
3631
  ...authHeaders
3522
3632
  };
3523
- for (const headerName of FORWARDABLE_HEADERS) {
3633
+ for (const headerName of SHARED_FORWARDABLE_HEADERS) {
3634
+ const headerValue = requestHeaders.get(headerName);
3635
+ if (headerValue) headers[headerName] = headerValue;
3636
+ }
3637
+ if (providerConfig.type !== "anthropic") return headers;
3638
+ for (const headerName of ANTHROPIC_FORWARDABLE_HEADERS) {
3524
3639
  const headerValue = requestHeaders.get(headerName);
3525
3640
  if (headerValue) headers[headerName] = headerValue;
3526
3641
  }
@@ -3542,6 +3657,13 @@ async function forwardProviderMessages(providerConfig, payload, requestHeaders)
3542
3657
  body: JSON.stringify(payload)
3543
3658
  });
3544
3659
  }
3660
+ async function forwardProviderChatCompletions(providerConfig, payload, requestHeaders) {
3661
+ return await fetch(`${providerConfig.baseUrl}/v1/chat/completions`, {
3662
+ method: "POST",
3663
+ headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
3664
+ body: JSON.stringify(payload)
3665
+ });
3666
+ }
3545
3667
  async function forwardProviderModels(providerConfig, requestHeaders) {
3546
3668
  return await fetch(`${providerConfig.baseUrl}/v1/models`, {
3547
3669
  method: "GET",
@@ -3562,13 +3684,18 @@ async function handleProviderMessages(c) {
3562
3684
  try {
3563
3685
  const payload = await c.req.json();
3564
3686
  const modelConfig = providerConfig.models?.[payload.model];
3565
- payload.temperature ??= modelConfig?.temperature;
3566
- payload.top_p ??= modelConfig?.topP;
3567
- payload.top_k ??= modelConfig?.topK;
3687
+ applyModelDefaults(payload, modelConfig);
3568
3688
  debugJson(logger$3, "provider.messages.request", {
3569
3689
  payload,
3570
3690
  provider
3571
3691
  });
3692
+ if (providerConfig.type === "openai-compatible") return await handleOpenAICompatibleProviderMessages(c, {
3693
+ modelConfig,
3694
+ payload,
3695
+ provider,
3696
+ providerConfig
3697
+ });
3698
+ applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
3572
3699
  const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
3573
3700
  if (!upstreamResponse.ok) {
3574
3701
  logger$3.error("Failed to create responses", upstreamResponse);
@@ -3597,6 +3724,68 @@ async function handleProviderMessages(c) {
3597
3724
  throw error;
3598
3725
  }
3599
3726
  }
3727
+ const applyModelDefaults = (payload, modelConfig) => {
3728
+ payload.temperature ??= modelConfig?.temperature;
3729
+ payload.top_p ??= modelConfig?.topP;
3730
+ payload.top_k ??= modelConfig?.topK;
3731
+ };
3732
+ const applyMissingExtraBody = (payload, options) => {
3733
+ for (const [key, value] of Object.entries(options.extraBody ?? {})) if (!Object.hasOwn(payload, key)) payload[key] = value;
3734
+ };
3735
+ const handleOpenAICompatibleProviderMessages = async (c, options) => {
3736
+ const { modelConfig, payload, provider, providerConfig } = options;
3737
+ const openAIPayload = createOpenAICompatiblePayload(payload, modelConfig);
3738
+ debugJson(logger$3, "provider.messages.openai_compatible.request", {
3739
+ payload: openAIPayload,
3740
+ provider
3741
+ });
3742
+ const upstreamResponse = await forwardProviderChatCompletions(providerConfig, openAIPayload, c.req.raw.headers);
3743
+ if (!upstreamResponse.ok) {
3744
+ logger$3.error("Failed to create openai-compatible responses", upstreamResponse);
3745
+ throw new HTTPError("Failed to create openai-compatible responses", upstreamResponse);
3746
+ }
3747
+ const contentType = upstreamResponse.headers.get("content-type") ?? "";
3748
+ if (Boolean(openAIPayload.stream) && contentType.includes("text/event-stream")) return streamOpenAICompatibleProviderMessages({
3749
+ c,
3750
+ payload,
3751
+ provider,
3752
+ upstreamResponse
3753
+ });
3754
+ const jsonBody = await upstreamResponse.json();
3755
+ return respondOpenAICompatibleProviderMessagesJson(c, {
3756
+ body: jsonBody,
3757
+ payload,
3758
+ provider
3759
+ });
3760
+ };
3761
+ const createOpenAICompatiblePayload = (payload, modelConfig) => {
3762
+ const openAIPayload = translateToOpenAI(payload, {
3763
+ supportPdf: modelConfig?.supportPdf,
3764
+ toolContentSupportType: modelConfig?.toolContentSupportType ?? []
3765
+ });
3766
+ if (payload.top_k !== void 0) openAIPayload.top_k = payload.top_k;
3767
+ if (openAIPayload.stream) openAIPayload.stream_options = { include_usage: true };
3768
+ normalizeOpenAICompatibleReasoningContent(openAIPayload);
3769
+ applyOpenAICompatibleRequestOverrides(openAIPayload, {
3770
+ extraBody: modelConfig?.extraBody,
3771
+ source: payload
3772
+ });
3773
+ applyMissingExtraBody(openAIPayload, { extraBody: modelConfig?.extraBody });
3774
+ if (!Object.hasOwn(openAIPayload, "parallel_tool_calls")) openAIPayload.parallel_tool_calls = true;
3775
+ return openAIPayload;
3776
+ };
3777
+ const normalizeOpenAICompatibleReasoningContent = (payload) => {
3778
+ for (const message of payload.messages) {
3779
+ if (message.role !== "assistant") continue;
3780
+ if (message.reasoning_content === void 0 && message.reasoning_text !== void 0) message.reasoning_content = message.reasoning_text;
3781
+ delete message.reasoning_text;
3782
+ delete message.reasoning_opaque;
3783
+ }
3784
+ };
3785
+ const applyOpenAICompatibleRequestOverrides = (payload, options) => {
3786
+ const allowedKeys = new Set(Object.keys(options.extraBody ?? {}));
3787
+ for (const key of allowedKeys) if (Object.hasOwn(options.source, key)) payload[key] = options.source[key];
3788
+ };
3600
3789
  const streamProviderMessages = ({ c, payload, provider, providerConfig, upstreamResponse }) => {
3601
3790
  logger$3.debug("provider.messages.streaming");
3602
3791
  const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
@@ -3628,6 +3817,66 @@ const streamProviderMessages = ({ c, payload, provider, providerConfig, upstream
3628
3817
  recordUsage(usage);
3629
3818
  });
3630
3819
  };
3820
+ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
3821
+ logger$3.debug("provider.messages.openai_compatible.streaming");
3822
+ const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
3823
+ return streamSSE(c, async (stream) => {
3824
+ let usage = {};
3825
+ const streamState = {
3826
+ messageStartSent: false,
3827
+ contentBlockIndex: 0,
3828
+ contentBlockOpen: false,
3829
+ toolCalls: {},
3830
+ thinkingBlockOpen: false
3831
+ };
3832
+ for await (const chunk of events(upstreamResponse)) {
3833
+ logger$3.debug("provider.messages.openai_compatible.raw_stream_event:", chunk.data);
3834
+ if (chunk.event === "ping") {
3835
+ await stream.writeSSE({
3836
+ event: "ping",
3837
+ data: "{\"type\":\"ping\"}"
3838
+ });
3839
+ continue;
3840
+ }
3841
+ if (!chunk.data || chunk.data === "[DONE]") {
3842
+ if (chunk.data === "[DONE]") break;
3843
+ continue;
3844
+ }
3845
+ const parsed = parseOpenAICompatibleStreamChunk(chunk.data);
3846
+ if (!parsed) continue;
3847
+ if (parsed.usage) usage = normalizeOpenAIUsage(parsed.usage);
3848
+ const events$1 = translateChunkToAnthropicEvents(parsed, streamState);
3849
+ for (const event of events$1) {
3850
+ const eventData = JSON.stringify(event);
3851
+ debugLazy(logger$3, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
3852
+ await stream.writeSSE({
3853
+ event: event.type,
3854
+ data: eventData
3855
+ });
3856
+ }
3857
+ }
3858
+ for (const event of flushPendingAnthropicStreamEvents(streamState)) {
3859
+ const eventData = JSON.stringify(event);
3860
+ debugLazy(logger$3, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
3861
+ await stream.writeSSE({
3862
+ event: event.type,
3863
+ data: eventData
3864
+ });
3865
+ }
3866
+ recordUsage(usage);
3867
+ });
3868
+ };
3869
+ const parseOpenAICompatibleStreamChunk = (data) => {
3870
+ try {
3871
+ return JSON.parse(data);
3872
+ } catch (error) {
3873
+ logger$3.error("provider.messages.openai_compatible.parse_chunk_error", {
3874
+ data,
3875
+ error
3876
+ });
3877
+ return null;
3878
+ }
3879
+ };
3631
3880
  const parseProviderStreamEvent = (data, providerConfig) => {
3632
3881
  try {
3633
3882
  const parsed = JSON.parse(data);
@@ -3666,6 +3915,13 @@ const respondProviderMessagesJson = (c, options) => {
3666
3915
  debugJson(logger$3, "provider.messages.no_stream result:", body);
3667
3916
  return c.json(body);
3668
3917
  };
3918
+ const respondOpenAICompatibleProviderMessagesJson = (c, options) => {
3919
+ const { body, payload, provider } = options;
3920
+ createProviderMessagesUsageRecorder(payload, provider)(normalizeOpenAIUsage(body.usage));
3921
+ const anthropicResponse = translateToAnthropic(body);
3922
+ debugJson(logger$3, "provider.messages.openai_compatible.no_stream result:", anthropicResponse);
3923
+ return c.json(anthropicResponse);
3924
+ };
3669
3925
  const createProviderMessagesUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
3670
3926
  endpoint: "provider_messages",
3671
3927
  model: payload.model,
@@ -3985,4 +4241,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
3985
4241
 
3986
4242
  //#endregion
3987
4243
  export { server };
3988
- //# sourceMappingURL=server-D1nq9oGf.js.map
4244
+ //# sourceMappingURL=server-BiAUjFEP.js.map