@jeffreycao/copilot-api 1.9.10 → 1.9.11

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.
@@ -1024,6 +1024,37 @@ embeddingRoutes.post("/", async (c) => {
1024
1024
  }
1025
1025
  });
1026
1026
 
1027
+ //#endregion
1028
+ //#region src/lib/provider-model.ts
1029
+ const parseProviderModelAlias = (model) => {
1030
+ const separatorIndex = model.indexOf("/");
1031
+ if (separatorIndex <= 0 || separatorIndex === model.length - 1) return null;
1032
+ const provider = model.slice(0, separatorIndex).trim();
1033
+ const providerModel = model.slice(separatorIndex + 1).trim();
1034
+ if (!provider || !providerModel) return null;
1035
+ return {
1036
+ model: providerModel,
1037
+ provider
1038
+ };
1039
+ };
1040
+ const createFallbackModel = (modelId) => ({
1041
+ capabilities: {
1042
+ family: "provider",
1043
+ limits: {},
1044
+ object: "model_capabilities",
1045
+ supports: {},
1046
+ tokenizer: "o200k_base",
1047
+ type: "chat"
1048
+ },
1049
+ id: modelId,
1050
+ model_picker_enabled: false,
1051
+ name: modelId,
1052
+ object: "model",
1053
+ preview: false,
1054
+ vendor: "provider",
1055
+ version: "unknown"
1056
+ });
1057
+
1027
1058
  //#endregion
1028
1059
  //#region src/lib/tokenizer.ts
1029
1060
  const ENCODING_MAP = {
@@ -1243,57 +1274,6 @@ const getTokenCount = async (payload, model) => {
1243
1274
  };
1244
1275
  };
1245
1276
 
1246
- //#endregion
1247
- //#region src/lib/models.ts
1248
- const findEndpointModel = (sdkModelId) => {
1249
- const models = state.models?.data ?? [];
1250
- const exactMatch = models.find((m) => m.id === sdkModelId);
1251
- if (exactMatch) return exactMatch;
1252
- const normalized = _normalizeSdkModelId(sdkModelId);
1253
- if (!normalized) return;
1254
- const modelName = `claude-${normalized.family}-${normalized.version}`;
1255
- const model = models.find((m) => m.id === modelName);
1256
- if (model) return model;
1257
- };
1258
- /**
1259
- * Normalizes an SDK model ID to extract the model family and version.
1260
- * this method from github copilot extension
1261
- * Examples:
1262
- * - "claude-opus-4-5-20251101" -> { family: "opus", version: "4.5" }
1263
- * - "claude-3-5-sonnet-20241022" -> { family: "sonnet", version: "3.5" }
1264
- * - "claude-sonnet-4-20250514" -> { family: "sonnet", version: "4" }
1265
- * - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
1266
- * - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
1267
- */
1268
- const _normalizeSdkModelId = (sdkModelId) => {
1269
- const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
1270
- const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
1271
- if (pattern1) return {
1272
- family: pattern1[1],
1273
- version: `${pattern1[2]}.${pattern1[3]}`
1274
- };
1275
- const pattern2 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
1276
- if (pattern2) return {
1277
- family: pattern2[3],
1278
- version: `${pattern2[1]}.${pattern2[2]}`
1279
- };
1280
- const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
1281
- if (pattern3) return {
1282
- family: pattern3[1],
1283
- version: `${pattern3[2]}.${pattern3[3]}`
1284
- };
1285
- const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/);
1286
- if (pattern4) return {
1287
- family: pattern4[1],
1288
- version: pattern4[2]
1289
- };
1290
- const pattern5 = withoutDate.match(/^claude-(\d+)-(\w+)$/);
1291
- if (pattern5) return {
1292
- family: pattern5[2],
1293
- version: pattern5[1]
1294
- };
1295
- };
1296
-
1297
1277
  //#endregion
1298
1278
  //#region src/routes/messages/utils.ts
1299
1279
  function mapOpenAIStopReasonToAnthropic(finishReason) {
@@ -1308,7 +1288,7 @@ function mapOpenAIStopReasonToAnthropic(finishReason) {
1308
1288
 
1309
1289
  //#endregion
1310
1290
  //#region src/routes/messages/non-stream-translation.ts
1311
- const THINKING_TEXT = "Thinking...";
1291
+ const THINKING_TEXT$1 = "Thinking...";
1312
1292
  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.";
1313
1293
  const COPILOT_TOOL_CONTENT_SUPPORT_TYPE = ["array", "image"];
1314
1294
  function translateToOpenAI(payload, options = {}) {
@@ -1445,8 +1425,8 @@ function handleAssistantMessage(message, modelId, capabilities) {
1445
1425
  }];
1446
1426
  const toolUseBlocks = message.content.filter((block) => block.type === "tool_use");
1447
1427
  let thinkingBlocks = message.content.filter((block) => block.type === "thinking");
1448
- if (modelId.startsWith("claude")) thinkingBlocks = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT && b.signature && !b.signature.includes("@"));
1449
- const thinkingContents = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT).map((b) => b.thinking);
1428
+ if (modelId.startsWith("claude")) thinkingBlocks = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT$1 && b.signature && !b.signature.includes("@"));
1429
+ const thinkingContents = thinkingBlocks.filter((b) => b.thinking && b.thinking !== THINKING_TEXT$1).map((b) => b.thinking);
1450
1430
  const allThinkingContent = thinkingContents.length > 0 ? thinkingContents.join("\n\n") : void 0;
1451
1431
  const signature = thinkingBlocks.find((b) => b.signature)?.signature;
1452
1432
  return toolUseBlocks.length > 0 ? [{
@@ -1607,7 +1587,7 @@ function getAnthropicThinkBlocks(reasoningText, reasoningOpaque) {
1607
1587
  }];
1608
1588
  if (reasoningOpaque && reasoningOpaque.length > 0) return [{
1609
1589
  type: "thinking",
1610
- thinking: THINKING_TEXT,
1590
+ thinking: THINKING_TEXT$1,
1611
1591
  signature: reasoningOpaque
1612
1592
  }];
1613
1593
  return [];
@@ -1622,8 +1602,106 @@ function getAnthropicToolUseBlocks(toolCalls) {
1622
1602
  }));
1623
1603
  }
1624
1604
 
1605
+ //#endregion
1606
+ //#region src/routes/provider/messages/count-tokens-handler.ts
1607
+ const logger$5 = createHandlerLogger("provider-count-tokens-handler");
1608
+ async function handleProviderCountTokens(c) {
1609
+ const provider = c.req.param("provider");
1610
+ const payload = await c.req.json();
1611
+ return await handleProviderCountTokensForProvider(c, {
1612
+ payload,
1613
+ provider
1614
+ });
1615
+ }
1616
+ async function handleProviderCountTokensForProvider(c, options) {
1617
+ const { payload: anthropicPayload, provider } = options;
1618
+ const modelId = anthropicPayload.model.trim();
1619
+ const providerConfig = getProviderConfig(provider);
1620
+ if (!providerConfig) return c.json({ error: {
1621
+ message: `Provider '${provider}' not found or disabled`,
1622
+ type: "invalid_request_error"
1623
+ } }, 404);
1624
+ const modelConfig = providerConfig.models?.[modelId];
1625
+ const translationOptions = providerConfig.type === "openai-compatible" ? {
1626
+ supportPdf: modelConfig?.supportPdf,
1627
+ toolContentSupportType: modelConfig?.toolContentSupportType ?? []
1628
+ } : void 0;
1629
+ const openAIPayload = translateToOpenAI(anthropicPayload, translationOptions);
1630
+ const selectedModel = createFallbackModel(modelId);
1631
+ const tokenCount = await getTokenCount(openAIPayload, selectedModel);
1632
+ const finalTokenCount = tokenCount.input + tokenCount.output;
1633
+ logger$5.debug("provider.count_tokens.success", {
1634
+ provider,
1635
+ model: anthropicPayload.model,
1636
+ input_tokens: finalTokenCount
1637
+ });
1638
+ return c.json({ input_tokens: finalTokenCount });
1639
+ }
1640
+
1641
+ //#endregion
1642
+ //#region src/lib/models.ts
1643
+ const findEndpointModel = (sdkModelId) => {
1644
+ const models = state.models?.data ?? [];
1645
+ const exactMatch = models.find((m) => m.id === sdkModelId);
1646
+ if (exactMatch) return exactMatch;
1647
+ const normalized = _normalizeSdkModelId(sdkModelId);
1648
+ if (!normalized) return;
1649
+ const modelName = `claude-${normalized.family}-${normalized.version}`;
1650
+ const model = models.find((m) => m.id === modelName);
1651
+ if (model) return model;
1652
+ };
1653
+ /**
1654
+ * Normalizes an SDK model ID to extract the model family and version.
1655
+ * this method from github copilot extension
1656
+ * Examples:
1657
+ * - "claude-opus-4-5-20251101" -> { family: "opus", version: "4.5" }
1658
+ * - "claude-3-5-sonnet-20241022" -> { family: "sonnet", version: "3.5" }
1659
+ * - "claude-sonnet-4-20250514" -> { family: "sonnet", version: "4" }
1660
+ * - "claude-haiku-3-5-20250514" -> { family: "haiku", version: "3.5" }
1661
+ * - "claude-haiku-4.5" -> { family: "haiku", version: "4.5" }
1662
+ */
1663
+ const _normalizeSdkModelId = (sdkModelId) => {
1664
+ const withoutDate = sdkModelId.toLowerCase().replace(/-\d{8}$/, "");
1665
+ const pattern1 = withoutDate.match(/^claude-(\w+)-(\d+)-(\d+)$/);
1666
+ if (pattern1) return {
1667
+ family: pattern1[1],
1668
+ version: `${pattern1[2]}.${pattern1[3]}`
1669
+ };
1670
+ const pattern2 = withoutDate.match(/^claude-(\d+)-(\d+)-(\w+)$/);
1671
+ if (pattern2) return {
1672
+ family: pattern2[3],
1673
+ version: `${pattern2[1]}.${pattern2[2]}`
1674
+ };
1675
+ const pattern3 = withoutDate.match(/^claude-(\w+)-(\d+)\.(\d+)$/);
1676
+ if (pattern3) return {
1677
+ family: pattern3[1],
1678
+ version: `${pattern3[2]}.${pattern3[3]}`
1679
+ };
1680
+ const pattern4 = withoutDate.match(/^claude-(\w+)-(\d+)$/);
1681
+ if (pattern4) return {
1682
+ family: pattern4[1],
1683
+ version: pattern4[2]
1684
+ };
1685
+ const pattern5 = withoutDate.match(/^claude-(\d+)-(\w+)$/);
1686
+ if (pattern5) return {
1687
+ family: pattern5[2],
1688
+ version: pattern5[1]
1689
+ };
1690
+ };
1691
+
1625
1692
  //#endregion
1626
1693
  //#region src/routes/messages/count-tokens-handler.ts
1694
+ const resolveCountTokensModel = (modelId, findModel = findEndpointModel) => {
1695
+ const selectedModel = findModel(modelId);
1696
+ if (selectedModel) return {
1697
+ fallback: false,
1698
+ model: selectedModel
1699
+ };
1700
+ return {
1701
+ fallback: true,
1702
+ model: createFallbackModel(modelId.trim())
1703
+ };
1704
+ };
1627
1705
  /**
1628
1706
  * Forwards token counting to Anthropic's real /v1/messages/count_tokens endpoint.
1629
1707
  * Returns the result on success, or null to fall through to estimation.
@@ -1662,2262 +1740,1980 @@ async function countTokensViaAnthropic(c, payload) {
1662
1740
  * endpoint for accurate counts. Otherwise falls back to GPT tokenizer estimation.
1663
1741
  */
1664
1742
  async function handleCountTokens(c) {
1665
- try {
1666
- const anthropicPayload = await c.req.json();
1667
- const anthropicResult = await countTokensViaAnthropic(c, anthropicPayload);
1668
- if (anthropicResult) return anthropicResult;
1669
- const anthropicBeta = c.req.header("anthropic-beta");
1670
- const openAIPayload = translateToOpenAI(anthropicPayload);
1671
- const selectedModel = findEndpointModel(anthropicPayload.model);
1672
- anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
1673
- if (!selectedModel) {
1674
- consola.warn("Model not found, returning default token count");
1675
- return c.json({ input_tokens: 1 });
1743
+ const anthropicPayload = await c.req.json();
1744
+ const providerModelAlias = parseProviderModelAlias(anthropicPayload.model);
1745
+ if (providerModelAlias) {
1746
+ anthropicPayload.model = providerModelAlias.model;
1747
+ return await handleProviderCountTokensForProvider(c, {
1748
+ payload: anthropicPayload,
1749
+ provider: providerModelAlias.provider
1750
+ });
1751
+ }
1752
+ const anthropicResult = await countTokensViaAnthropic(c, anthropicPayload);
1753
+ if (anthropicResult) return anthropicResult;
1754
+ const anthropicBeta = c.req.header("anthropic-beta");
1755
+ const openAIPayload = translateToOpenAI(anthropicPayload);
1756
+ const requestedModel = anthropicPayload.model;
1757
+ const resolve = resolveCountTokensModel(requestedModel);
1758
+ const selectedModel = resolve.model;
1759
+ anthropicPayload.model = selectedModel.id;
1760
+ if (resolve.fallback) consola.warn(`Model '${requestedModel}' not found, using o200k_base fallback tokenizer`);
1761
+ const tokenCount = await getTokenCount(openAIPayload, selectedModel);
1762
+ if (anthropicPayload.tools && anthropicPayload.tools.length > 0) {
1763
+ let addToolSystemPromptCount = false;
1764
+ if (anthropicBeta) {
1765
+ const toolsLength = anthropicPayload.tools.length;
1766
+ addToolSystemPromptCount = !anthropicPayload.tools.some((tool) => tool.name.startsWith("mcp__") || tool.name === "Skill" && toolsLength === 1);
1676
1767
  }
1677
- const tokenCount = await getTokenCount(openAIPayload, selectedModel);
1678
- if (anthropicPayload.tools && anthropicPayload.tools.length > 0) {
1679
- let addToolSystemPromptCount = false;
1680
- if (anthropicBeta) {
1681
- const toolsLength = anthropicPayload.tools.length;
1682
- addToolSystemPromptCount = !anthropicPayload.tools.some((tool) => tool.name.startsWith("mcp__") || tool.name === "Skill" && toolsLength === 1);
1683
- }
1684
- if (addToolSystemPromptCount) {
1685
- if (anthropicPayload.model.startsWith("claude")) tokenCount.input = tokenCount.input + 346;
1686
- else if (anthropicPayload.model.startsWith("grok")) tokenCount.input = tokenCount.input + 120;
1687
- }
1768
+ if (addToolSystemPromptCount) {
1769
+ if (anthropicPayload.model.startsWith("claude")) tokenCount.input = tokenCount.input + 346;
1770
+ else if (anthropicPayload.model.startsWith("grok")) tokenCount.input = tokenCount.input + 120;
1688
1771
  }
1689
- let finalTokenCount = tokenCount.input + tokenCount.output;
1690
- if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * getClaudeTokenMultiplier());
1691
- consola.info("Token count:", finalTokenCount);
1692
- return c.json({ input_tokens: finalTokenCount });
1693
- } catch (error) {
1694
- consola.error("Error counting tokens:", error);
1695
- return c.json({ input_tokens: 1 });
1696
1772
  }
1773
+ let finalTokenCount = tokenCount.input + tokenCount.output;
1774
+ if (anthropicPayload.model.startsWith("claude")) finalTokenCount = Math.round(finalTokenCount * getClaudeTokenMultiplier());
1775
+ consola.info("Token count:", finalTokenCount);
1776
+ return c.json({ input_tokens: finalTokenCount });
1697
1777
  }
1698
1778
 
1699
1779
  //#endregion
1700
- //#region src/services/copilot/create-responses.ts
1701
- const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId, compactType }) => {
1702
- if (!state.copilotToken) throw new Error("Copilot token not found");
1703
- const headers = {
1704
- ...copilotHeaders(state, requestId, vision),
1705
- "x-initiator": initiator
1706
- };
1707
- prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
1708
- prepareForCompact(headers, compactType);
1709
- payload.service_tier = void 0;
1710
- consola.log(`<-- model: ${payload.model}`);
1711
- const response = await fetch(`${copilotBaseUrl(state)}/responses`, {
1712
- method: "POST",
1713
- headers,
1714
- body: JSON.stringify(payload)
1780
+ //#region src/routes/messages/stream-translation.ts
1781
+ function isToolBlockOpen(state$1) {
1782
+ if (!state$1.contentBlockOpen) return false;
1783
+ return Object.values(state$1.toolCalls).some((tc) => tc.anthropicBlockIndex === state$1.contentBlockIndex);
1784
+ }
1785
+ function translateChunkToAnthropicEvents(chunk, state$1) {
1786
+ const events$1 = [];
1787
+ if (chunk.choices.length === 0) {
1788
+ completePendingMessage(state$1, events$1, chunk);
1789
+ return events$1;
1790
+ }
1791
+ const choice = chunk.choices[0];
1792
+ const { delta } = choice;
1793
+ handleMessageStart(state$1, events$1, chunk);
1794
+ handleThinkingText(delta, state$1, events$1);
1795
+ handleContent(delta, state$1, events$1);
1796
+ handleToolCalls(delta, state$1, events$1);
1797
+ handleFinish(choice, state$1, {
1798
+ events: events$1,
1799
+ chunk
1715
1800
  });
1716
- logCopilotRateLimits(response.headers);
1717
- if (!response.ok) {
1718
- consola.error("Failed to create responses", response);
1719
- throw new HTTPError("Failed to create responses", response);
1801
+ return events$1;
1802
+ }
1803
+ function flushPendingAnthropicStreamEvents(state$1) {
1804
+ const events$1 = [];
1805
+ completePendingMessage(state$1, events$1);
1806
+ return events$1;
1807
+ }
1808
+ function completePendingMessage(state$1, events$1, chunk) {
1809
+ if (!state$1.pendingMessageDelta) return;
1810
+ if (chunk?.usage) state$1.pendingMessageDelta.usage = getAnthropicUsageFromOpenAIChunk(chunk);
1811
+ events$1.push(state$1.pendingMessageDelta, { type: "message_stop" });
1812
+ state$1.pendingMessageDelta = void 0;
1813
+ }
1814
+ function handleFinish(choice, state$1, context) {
1815
+ const { events: events$1, chunk } = context;
1816
+ if (choice.finish_reason && choice.finish_reason.length > 0) {
1817
+ if (state$1.contentBlockOpen) {
1818
+ const toolBlockOpen = isToolBlockOpen(state$1);
1819
+ context.events.push({
1820
+ type: "content_block_stop",
1821
+ index: state$1.contentBlockIndex
1822
+ });
1823
+ state$1.contentBlockOpen = false;
1824
+ state$1.contentBlockIndex++;
1825
+ if (!toolBlockOpen) handleReasoningOpaque(choice.delta, events$1, state$1);
1826
+ }
1827
+ state$1.pendingMessageDelta = {
1828
+ type: "message_delta",
1829
+ delta: {
1830
+ stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),
1831
+ stop_sequence: null
1832
+ },
1833
+ usage: getAnthropicUsageFromOpenAIChunk(chunk)
1834
+ };
1835
+ if (chunk.usage) completePendingMessage(state$1, events$1, chunk);
1720
1836
  }
1721
- if (payload.stream) return events(response);
1722
- return await response.json();
1723
- };
1724
-
1725
- //#endregion
1726
- //#region src/routes/messages/responses-translation.ts
1727
- const MESSAGE_TYPE = "message";
1728
- const COMPACTION_SIGNATURE_PREFIX = "cm1#";
1729
- const COMPACTION_SIGNATURE_SEPARATOR = "@";
1730
- const THINKING_TEXT$1 = "Thinking...";
1731
- const translateAnthropicMessagesToResponsesPayload = (payload) => {
1732
- const input = [];
1733
- const applyPhase = shouldApplyPhase(payload.model);
1734
- for (const message of payload.messages) input.push(...translateMessage(message, payload.model, applyPhase));
1735
- const translatedTools = convertAnthropicTools(payload.tools);
1736
- const toolChoice = convertAnthropicToolChoice(payload.tool_choice);
1737
- const { sessionId: promptCacheKey } = parseUserIdMetadata(payload.metadata?.user_id);
1738
- return {
1739
- model: payload.model,
1740
- input,
1741
- instructions: translateSystemPrompt(payload.system, payload.model),
1742
- temperature: 1,
1743
- top_p: payload.top_p ?? null,
1744
- max_output_tokens: Math.max(payload.max_tokens, 12800),
1745
- tools: translatedTools,
1746
- tool_choice: toolChoice,
1747
- metadata: payload.metadata ? { ...payload.metadata } : null,
1748
- prompt_cache_key: promptCacheKey,
1749
- stream: payload.stream ?? null,
1750
- store: false,
1751
- parallel_tool_calls: true,
1752
- reasoning: {
1753
- effort: getReasoningEffortForModel(payload.model),
1754
- summary: "detailed"
1755
- },
1756
- include: ["reasoning.encrypted_content"]
1757
- };
1758
- };
1759
- const encodeCompactionCarrierSignature = (compaction) => {
1760
- return `${COMPACTION_SIGNATURE_PREFIX}${compaction.encrypted_content}${COMPACTION_SIGNATURE_SEPARATOR}${compaction.id}`;
1761
- };
1762
- const decodeCompactionCarrierSignature = (signature) => {
1763
- if (signature.startsWith(COMPACTION_SIGNATURE_PREFIX)) {
1764
- const raw = signature.slice(4);
1765
- const separatorIndex = raw.indexOf(COMPACTION_SIGNATURE_SEPARATOR);
1766
- if (separatorIndex <= 0 || separatorIndex === raw.length - 1) return;
1767
- const encrypted_content = raw.slice(0, separatorIndex);
1768
- const id = raw.slice(separatorIndex + 1);
1769
- if (!encrypted_content) return;
1770
- return {
1771
- id,
1772
- encrypted_content
1773
- };
1774
- }
1775
- };
1776
- const translateMessage = (message, model, applyPhase) => {
1777
- if (message.role === "user") return translateUserMessage(message);
1778
- return translateAssistantMessage(message, model, applyPhase);
1779
- };
1780
- const translateUserMessage = (message) => {
1781
- if (typeof message.content === "string") return [createMessage("user", message.content)];
1782
- if (!Array.isArray(message.content)) return [];
1783
- const items = [];
1784
- const pendingContent = [];
1785
- for (const block of message.content) {
1786
- if (block.type === "tool_result") {
1787
- flushPendingContent(pendingContent, items, { role: "user" });
1788
- items.push(createFunctionCallOutput(block));
1789
- continue;
1790
- }
1791
- const converted = translateUserContentBlock(block);
1792
- if (converted.length > 0) pendingContent.push(...converted);
1793
- }
1794
- flushPendingContent(pendingContent, items, { role: "user" });
1795
- return items;
1796
- };
1797
- const translateAssistantMessage = (message, model, applyPhase) => {
1798
- const assistantPhase = resolveAssistantPhase(model, message.content, applyPhase);
1799
- if (typeof message.content === "string") return [createMessage("assistant", message.content, assistantPhase)];
1800
- if (!Array.isArray(message.content)) return [];
1801
- const items = [];
1802
- const pendingContent = [];
1803
- for (const block of message.content) {
1804
- if (block.type === "tool_use") {
1805
- flushPendingContent(pendingContent, items, {
1806
- role: "assistant",
1807
- phase: assistantPhase
1808
- });
1809
- items.push(createFunctionToolCall(block));
1810
- continue;
1811
- }
1812
- if (block.type === "thinking" && block.signature) {
1813
- const compactionContent = createCompactionContent(block);
1814
- if (compactionContent) {
1815
- flushPendingContent(pendingContent, items, {
1816
- role: "assistant",
1817
- phase: assistantPhase
1818
- });
1819
- items.push(compactionContent);
1820
- continue;
1821
- }
1822
- if (block.signature.includes("@")) {
1823
- flushPendingContent(pendingContent, items, {
1824
- role: "assistant",
1825
- phase: assistantPhase
1826
- });
1827
- items.push(createReasoningContent(block));
1828
- continue;
1829
- }
1830
- }
1831
- const converted = translateAssistantContentBlock(block);
1832
- if (converted) pendingContent.push(converted);
1833
- }
1834
- flushPendingContent(pendingContent, items, {
1835
- role: "assistant",
1836
- phase: assistantPhase
1837
- });
1838
- return items;
1839
- };
1840
- const translateUserContentBlock = (block) => {
1841
- switch (block.type) {
1842
- case "text": return [createTextContent(block.text)];
1843
- case "image": return [createImageContent(block)];
1844
- case "document": return [createFileContent(block)];
1845
- default: return [];
1846
- }
1847
- };
1848
- const translateAssistantContentBlock = (block) => {
1849
- switch (block.type) {
1850
- case "text": return createOutPutTextContent(block.text);
1851
- default: return;
1852
- }
1853
- };
1854
- const flushPendingContent = (pendingContent, target, message) => {
1855
- if (pendingContent.length === 0) return;
1856
- const messageContent = [...pendingContent];
1857
- target.push(createMessage(message.role, messageContent, message.phase));
1858
- pendingContent.length = 0;
1859
- };
1860
- const createMessage = (role, content, phase) => ({
1861
- type: MESSAGE_TYPE,
1862
- role,
1863
- content,
1864
- ...role === "assistant" && phase ? { phase } : {}
1865
- });
1866
- const resolveAssistantPhase = (_model, content, applyPhase) => {
1867
- if (!applyPhase) return;
1868
- if (typeof content === "string") return "final_answer";
1869
- if (!Array.isArray(content)) return;
1870
- if (!content.some((block) => block.type === "text")) return;
1871
- return content.some((block) => block.type === "tool_use") ? "commentary" : "final_answer";
1872
- };
1873
- const shouldApplyPhase = (model) => {
1874
- return getExtraPromptForModel(model).includes("## Intermediary updates");
1875
- };
1876
- const createTextContent = (text) => ({
1877
- type: "input_text",
1878
- text
1879
- });
1880
- const createOutPutTextContent = (text) => ({
1881
- type: "output_text",
1882
- text
1883
- });
1884
- const createImageContent = (block) => ({
1885
- type: "input_image",
1886
- image_url: `data:${block.source.media_type};base64,${block.source.data}`,
1887
- detail: "auto"
1888
- });
1889
- const createFileContent = (block) => ({
1890
- type: "input_file",
1891
- file_data: `data:${block.source.media_type};base64,${block.source.data}`,
1892
- filename: block.title ?? "document.pdf"
1893
- });
1894
- const createReasoningContent = (block) => {
1895
- const { encryptedContent, id } = parseReasoningSignature(block.signature);
1896
- const thinking = block.thinking === THINKING_TEXT$1 ? "" : block.thinking;
1897
- return {
1898
- id,
1899
- type: "reasoning",
1900
- summary: thinking ? [{
1901
- type: "summary_text",
1902
- text: thinking
1903
- }] : [],
1904
- encrypted_content: encryptedContent
1905
- };
1906
- };
1907
- const createCompactionContent = (block) => {
1908
- const compaction = decodeCompactionCarrierSignature(block.signature);
1909
- if (!compaction) return;
1910
- return {
1911
- id: compaction.id,
1912
- type: "compaction",
1913
- encrypted_content: compaction.encrypted_content
1914
- };
1915
- };
1916
- const parseReasoningSignature = (signature) => {
1917
- const splitIndex = signature.lastIndexOf("@");
1918
- if (splitIndex <= 0 || splitIndex === signature.length - 1) return {
1919
- encryptedContent: signature,
1920
- id: ""
1921
- };
1922
- return {
1923
- encryptedContent: signature.slice(0, splitIndex),
1924
- id: signature.slice(splitIndex + 1)
1925
- };
1926
- };
1927
- const createFunctionToolCall = (block) => ({
1928
- type: "function_call",
1929
- call_id: block.id,
1930
- name: block.name,
1931
- arguments: JSON.stringify(block.input),
1932
- status: "completed"
1933
- });
1934
- const createFunctionCallOutput = (block) => ({
1935
- type: "function_call_output",
1936
- call_id: block.tool_use_id,
1937
- output: convertToolResultContent(block.content),
1938
- status: block.is_error ? "incomplete" : "completed"
1939
- });
1940
- const translateSystemPrompt = (system, model) => {
1941
- if (!system) return null;
1942
- const extraPrompt = getExtraPromptForModel(model);
1943
- if (typeof system === "string") return system + extraPrompt;
1944
- const text = system.map((block, index) => {
1945
- if (index === 0) return block.text + "\n\n" + extraPrompt + "\n\n";
1946
- return block.text;
1947
- }).join(" ");
1948
- return text.length > 0 ? text : null;
1949
- };
1950
- const convertAnthropicTools = (tools) => {
1951
- if (!tools || tools.length === 0) return null;
1952
- return tools.map((tool) => ({
1953
- type: "function",
1954
- name: tool.name,
1955
- parameters: normalizeToolSchema(tool.input_schema),
1956
- strict: false,
1957
- ...tool.description ? { description: tool.description } : {}
1958
- }));
1959
- };
1960
- const convertAnthropicToolChoice = (choice) => {
1961
- if (!choice) return "auto";
1962
- switch (choice.type) {
1963
- case "auto": return "auto";
1964
- case "any": return "required";
1965
- case "tool": return choice.name ? {
1966
- type: "function",
1967
- name: choice.name
1968
- } : "auto";
1969
- case "none": return "none";
1970
- default: return "auto";
1971
- }
1972
- };
1973
- const translateResponsesResultToAnthropic = (response) => {
1974
- const contentBlocks = mapOutputToAnthropicContent(response.output);
1975
- const usage = mapResponsesUsage(response);
1976
- let anthropicContent = fallbackContentBlocks(response.output_text);
1977
- if (contentBlocks.length > 0) anthropicContent = contentBlocks;
1978
- const stopReason = mapResponsesStopReason(response);
1979
- return {
1980
- id: response.id,
1981
- type: "message",
1982
- role: "assistant",
1983
- content: anthropicContent,
1984
- model: response.model,
1985
- stop_reason: stopReason,
1986
- stop_sequence: null,
1987
- usage
1988
- };
1989
- };
1990
- const mapOutputToAnthropicContent = (output) => {
1991
- const contentBlocks = [];
1992
- for (const item of output) switch (item.type) {
1993
- case "reasoning": {
1994
- const thinkingText = extractReasoningText(item);
1995
- if (thinkingText.length > 0) contentBlocks.push({
1996
- type: "thinking",
1997
- thinking: thinkingText,
1998
- signature: (item.encrypted_content ?? "") + "@" + item.id
1999
- });
2000
- break;
2001
- }
2002
- case "function_call": {
2003
- const toolUseBlock = createToolUseContentBlock(item);
2004
- if (toolUseBlock) contentBlocks.push(toolUseBlock);
2005
- break;
2006
- }
2007
- case "message": {
2008
- const combinedText = combineMessageTextContent(item.content);
2009
- if (combinedText.length > 0) contentBlocks.push({
2010
- type: "text",
2011
- text: combinedText
2012
- });
2013
- break;
2014
- }
2015
- case "compaction": {
2016
- const compactionBlock = createCompactionThinkingBlock(item);
2017
- if (compactionBlock) contentBlocks.push(compactionBlock);
2018
- break;
2019
- }
2020
- default: {
2021
- const combinedText = combineMessageTextContent(item.content);
2022
- if (combinedText.length > 0) contentBlocks.push({
2023
- type: "text",
2024
- text: combinedText
2025
- });
2026
- }
2027
- }
2028
- return contentBlocks;
2029
- };
2030
- const combineMessageTextContent = (content) => {
2031
- if (!Array.isArray(content)) return "";
2032
- let aggregated = "";
2033
- for (const block of content) {
2034
- if (isResponseOutputText(block)) {
2035
- aggregated += block.text;
2036
- continue;
2037
- }
2038
- if (isResponseOutputRefusal(block)) {
2039
- aggregated += block.refusal;
2040
- continue;
2041
- }
2042
- if (typeof block.text === "string") {
2043
- aggregated += block.text;
2044
- continue;
2045
- }
2046
- if (typeof block.reasoning === "string") {
2047
- aggregated += block.reasoning;
2048
- continue;
2049
- }
2050
- }
2051
- return aggregated;
2052
- };
2053
- const extractReasoningText = (item) => {
2054
- const segments = [];
2055
- const collectFromBlocks = (blocks) => {
2056
- if (!Array.isArray(blocks)) return;
2057
- for (const block of blocks) if (typeof block.text === "string") {
2058
- segments.push(block.text);
2059
- continue;
2060
- }
2061
- };
2062
- if (!item.summary || item.summary.length === 0) return THINKING_TEXT$1;
2063
- collectFromBlocks(item.summary);
2064
- return segments.join("").trim();
2065
- };
2066
- const createToolUseContentBlock = (call) => {
2067
- const toolId = call.call_id;
2068
- if (!call.name || !toolId) return null;
2069
- const input = parseFunctionCallArguments(call.arguments);
2070
- return {
2071
- type: "tool_use",
2072
- id: toolId,
2073
- name: call.name,
2074
- input
2075
- };
2076
- };
2077
- const createCompactionThinkingBlock = (item) => {
2078
- if (!item.id || !item.encrypted_content) return null;
1837
+ }
1838
+ function getAnthropicUsageFromOpenAIChunk(chunk) {
1839
+ const { cachedTokens, cacheCreationTokens, inputTokens } = getOpenAIChunkUsageTokens(chunk);
2079
1840
  return {
2080
- type: "thinking",
2081
- thinking: THINKING_TEXT$1,
2082
- signature: encodeCompactionCarrierSignature({
2083
- id: item.id,
2084
- encrypted_content: item.encrypted_content
2085
- })
1841
+ input_tokens: inputTokens,
1842
+ output_tokens: chunk.usage?.completion_tokens ?? 0,
1843
+ ...chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens !== void 0 && { cache_creation_input_tokens: cacheCreationTokens },
1844
+ ...chunk.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: cachedTokens }
2086
1845
  };
2087
- };
2088
- const parseFunctionCallArguments = (rawArguments) => {
2089
- if (typeof rawArguments !== "string" || rawArguments.trim().length === 0) return {};
2090
- try {
2091
- const parsed = JSON.parse(rawArguments);
2092
- if (Array.isArray(parsed)) return { arguments: parsed };
2093
- if (parsed && typeof parsed === "object") return parsed;
2094
- } catch (error) {
2095
- consola.warn("Failed to parse function call arguments", {
2096
- error,
2097
- rawArguments
2098
- });
2099
- }
2100
- return { raw_arguments: rawArguments };
2101
- };
2102
- const fallbackContentBlocks = (outputText) => {
2103
- if (!outputText) return [];
2104
- return [{
2105
- type: "text",
2106
- text: outputText
2107
- }];
2108
- };
2109
- const mapResponsesStopReason = (response) => {
2110
- const { status, incomplete_details: incompleteDetails } = response;
2111
- if (status === "completed") {
2112
- if (response.output.some((item) => item.type === "function_call")) return "tool_use";
2113
- return "end_turn";
2114
- }
2115
- if (status === "incomplete") {
2116
- if (incompleteDetails?.reason === "max_output_tokens") return "max_tokens";
2117
- if (incompleteDetails?.reason === "content_filter") return "end_turn";
2118
- }
2119
- return null;
2120
- };
2121
- const mapResponsesUsage = (response) => {
2122
- const inputTokens = response.usage?.input_tokens ?? 0;
2123
- const outputTokens = response.usage?.output_tokens ?? 0;
2124
- const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
1846
+ }
1847
+ function getOpenAIChunkUsageTokens(chunk) {
1848
+ const promptTokens = chunk.usage?.prompt_tokens ?? 0;
1849
+ const cachedTokens = chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0;
1850
+ const cacheCreationTokens = chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens ?? 0;
2125
1851
  return {
2126
- input_tokens: inputTokens - (inputCachedTokens ?? 0),
2127
- output_tokens: outputTokens,
2128
- ...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
1852
+ cacheCreationTokens,
1853
+ cachedTokens,
1854
+ inputTokens: Math.max(0, promptTokens - cachedTokens - cacheCreationTokens)
2129
1855
  };
2130
- };
2131
- const isRecord = (value) => typeof value === "object" && value !== null;
2132
- const isResponseOutputText = (block) => isRecord(block) && "type" in block && block.type === "output_text";
2133
- const isResponseOutputRefusal = (block) => isRecord(block) && "type" in block && block.type === "refusal";
2134
- const convertToolResultContent = (content) => {
2135
- if (typeof content === "string") return content;
2136
- if (Array.isArray(content)) {
2137
- const result = [];
2138
- for (const block of content) switch (block.type) {
2139
- case "text":
2140
- result.push(createTextContent(block.text));
2141
- break;
2142
- case "image":
2143
- result.push(createImageContent(block));
2144
- break;
2145
- case "document":
2146
- result.push(createFileContent(block));
2147
- break;
2148
- case "tool_reference":
2149
- result.push(createTextContent(`Tool ${block.tool_name} loaded`));
2150
- break;
2151
- default: break;
1856
+ }
1857
+ function handleToolCalls(delta, state$1, events$1) {
1858
+ if (delta.tool_calls && delta.tool_calls.length > 0) {
1859
+ closeThinkingBlockIfOpen(state$1, events$1);
1860
+ handleReasoningOpaqueInToolCalls(state$1, events$1, delta);
1861
+ for (const toolCall of delta.tool_calls) {
1862
+ if (toolCall.id && toolCall.function?.name) {
1863
+ if (state$1.contentBlockOpen) {
1864
+ events$1.push({
1865
+ type: "content_block_stop",
1866
+ index: state$1.contentBlockIndex
1867
+ });
1868
+ state$1.contentBlockIndex++;
1869
+ state$1.contentBlockOpen = false;
1870
+ }
1871
+ const anthropicBlockIndex = state$1.contentBlockIndex;
1872
+ state$1.toolCalls[toolCall.index] = {
1873
+ id: toolCall.id,
1874
+ name: toolCall.function.name,
1875
+ anthropicBlockIndex
1876
+ };
1877
+ events$1.push({
1878
+ type: "content_block_start",
1879
+ index: anthropicBlockIndex,
1880
+ content_block: {
1881
+ type: "tool_use",
1882
+ id: toolCall.id,
1883
+ name: toolCall.function.name,
1884
+ input: {}
1885
+ }
1886
+ });
1887
+ state$1.contentBlockOpen = true;
1888
+ }
1889
+ if (toolCall.function?.arguments) {
1890
+ const toolCallInfo = state$1.toolCalls[toolCall.index];
1891
+ if (toolCallInfo) events$1.push({
1892
+ type: "content_block_delta",
1893
+ index: toolCallInfo.anthropicBlockIndex,
1894
+ delta: {
1895
+ type: "input_json_delta",
1896
+ partial_json: toolCall.function.arguments
1897
+ }
1898
+ });
1899
+ }
2152
1900
  }
2153
- return result;
2154
1901
  }
2155
- return "";
2156
- };
2157
-
2158
- //#endregion
2159
- //#region src/routes/messages/responses-stream-translation.ts
2160
- const MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE = 20;
2161
- var FunctionCallArgumentsValidationError = class extends Error {
2162
- constructor(message) {
2163
- super(message);
2164
- this.name = "FunctionCallArgumentsValidationError";
1902
+ }
1903
+ function handleReasoningOpaqueInToolCalls(state$1, events$1, delta) {
1904
+ if (state$1.contentBlockOpen && !isToolBlockOpen(state$1)) {
1905
+ events$1.push({
1906
+ type: "content_block_stop",
1907
+ index: state$1.contentBlockIndex
1908
+ });
1909
+ state$1.contentBlockIndex++;
1910
+ state$1.contentBlockOpen = false;
2165
1911
  }
2166
- };
2167
- const updateWhitespaceRunState = (previousCount, chunk) => {
2168
- let count = previousCount;
2169
- for (const char of chunk) {
2170
- if (char === "\r" || char === "\n" || char === " ") {
2171
- count += 1;
2172
- if (count > MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE) return {
2173
- nextCount: count,
2174
- exceeded: true
2175
- };
2176
- continue;
1912
+ handleReasoningOpaque(delta, events$1, state$1);
1913
+ }
1914
+ function handleContent(delta, state$1, events$1) {
1915
+ if (delta.content && delta.content.length > 0) {
1916
+ closeThinkingBlockIfOpen(state$1, events$1);
1917
+ if (isToolBlockOpen(state$1)) {
1918
+ events$1.push({
1919
+ type: "content_block_stop",
1920
+ index: state$1.contentBlockIndex
1921
+ });
1922
+ state$1.contentBlockIndex++;
1923
+ state$1.contentBlockOpen = false;
2177
1924
  }
2178
- if (char !== " ") count = 0;
2179
- }
2180
- return {
2181
- nextCount: count,
2182
- exceeded: false
2183
- };
2184
- };
2185
- const createResponsesStreamState = () => ({
2186
- messageStartSent: false,
2187
- messageCompleted: false,
2188
- nextContentBlockIndex: 0,
2189
- blockIndexByKey: /* @__PURE__ */ new Map(),
2190
- openBlocks: /* @__PURE__ */ new Set(),
2191
- blockHasDelta: /* @__PURE__ */ new Set(),
2192
- functionCallStateByOutputIndex: /* @__PURE__ */ new Map()
2193
- });
2194
- const translateResponsesStreamEvent = (rawEvent, state$1) => {
2195
- switch (rawEvent.type) {
2196
- case "response.created": return handleResponseCreated(rawEvent, state$1);
2197
- case "response.output_item.added": return handleOutputItemAdded$1(rawEvent, state$1);
2198
- case "response.reasoning_summary_text.delta": return handleReasoningSummaryTextDelta(rawEvent, state$1);
2199
- case "response.output_text.delta": return handleOutputTextDelta(rawEvent, state$1);
2200
- case "response.reasoning_summary_text.done": return handleReasoningSummaryTextDone(rawEvent, state$1);
2201
- case "response.output_text.done": return handleOutputTextDone(rawEvent, state$1);
2202
- case "response.output_item.done": return handleOutputItemDone$1(rawEvent, state$1);
2203
- case "response.function_call_arguments.delta": return handleFunctionCallArgumentsDelta(rawEvent, state$1);
2204
- case "response.function_call_arguments.done": return handleFunctionCallArgumentsDone(rawEvent, state$1);
2205
- case "response.completed":
2206
- case "response.incomplete": return handleResponseCompleted(rawEvent, state$1);
2207
- case "response.failed": return handleResponseFailed(rawEvent, state$1);
2208
- case "error": return handleErrorEvent(rawEvent, state$1);
2209
- default: return [];
1925
+ if (!state$1.contentBlockOpen) {
1926
+ events$1.push({
1927
+ type: "content_block_start",
1928
+ index: state$1.contentBlockIndex,
1929
+ content_block: {
1930
+ type: "text",
1931
+ text: ""
1932
+ }
1933
+ });
1934
+ state$1.contentBlockOpen = true;
1935
+ }
1936
+ events$1.push({
1937
+ type: "content_block_delta",
1938
+ index: state$1.contentBlockIndex,
1939
+ delta: {
1940
+ type: "text_delta",
1941
+ text: delta.content
1942
+ }
1943
+ });
2210
1944
  }
2211
- };
2212
- const handleResponseCreated = (rawEvent, state$1) => {
2213
- return messageStart(state$1, rawEvent.response);
2214
- };
2215
- const handleOutputItemAdded$1 = (rawEvent, state$1) => {
2216
- const events$1 = new Array();
2217
- const functionCallDetails = extractFunctionCallDetails(rawEvent);
2218
- if (!functionCallDetails) return events$1;
2219
- const { outputIndex, toolCallId, name, initialArguments } = functionCallDetails;
2220
- const blockIndex = openFunctionCallBlock(state$1, {
2221
- outputIndex,
2222
- toolCallId,
2223
- name,
2224
- events: events$1
2225
- });
2226
- if (initialArguments !== void 0 && initialArguments.length > 0) {
1945
+ if (delta.content === "" && delta.reasoning_opaque && delta.reasoning_opaque.length > 0 && state$1.thinkingBlockOpen) {
2227
1946
  events$1.push({
2228
1947
  type: "content_block_delta",
2229
- index: blockIndex,
1948
+ index: state$1.contentBlockIndex,
2230
1949
  delta: {
2231
- type: "input_json_delta",
2232
- partial_json: initialArguments
1950
+ type: "signature_delta",
1951
+ signature: delta.reasoning_opaque
1952
+ }
1953
+ }, {
1954
+ type: "content_block_stop",
1955
+ index: state$1.contentBlockIndex
1956
+ });
1957
+ state$1.contentBlockIndex++;
1958
+ state$1.thinkingBlockOpen = false;
1959
+ }
1960
+ }
1961
+ function handleMessageStart(state$1, events$1, chunk) {
1962
+ if (!state$1.messageStartSent) {
1963
+ const { cachedTokens, cacheCreationTokens, inputTokens } = getOpenAIChunkUsageTokens(chunk);
1964
+ events$1.push({
1965
+ type: "message_start",
1966
+ message: {
1967
+ id: chunk.id,
1968
+ type: "message",
1969
+ role: "assistant",
1970
+ content: [],
1971
+ model: chunk.model,
1972
+ stop_reason: null,
1973
+ stop_sequence: null,
1974
+ usage: {
1975
+ input_tokens: inputTokens,
1976
+ output_tokens: 0,
1977
+ ...chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens !== void 0 && { cache_creation_input_tokens: cacheCreationTokens },
1978
+ ...chunk.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: cachedTokens }
1979
+ }
2233
1980
  }
2234
1981
  });
2235
- state$1.blockHasDelta.add(blockIndex);
1982
+ state$1.messageStartSent = true;
2236
1983
  }
2237
- return events$1;
2238
- };
2239
- const handleOutputItemDone$1 = (rawEvent, state$1) => {
2240
- const events$1 = new Array();
2241
- const item = rawEvent.item;
2242
- const itemType = item.type;
2243
- const outputIndex = rawEvent.output_index;
2244
- if (itemType === "compaction") {
2245
- if (!item.id || !item.encrypted_content) return events$1;
2246
- const blockIndex$1 = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
2247
- if (!state$1.blockHasDelta.has(blockIndex$1)) events$1.push({
1984
+ }
1985
+ function handleReasoningOpaque(delta, events$1, state$1) {
1986
+ if (delta.reasoning_opaque && delta.reasoning_opaque.length > 0) {
1987
+ events$1.push({
1988
+ type: "content_block_start",
1989
+ index: state$1.contentBlockIndex,
1990
+ content_block: {
1991
+ type: "thinking",
1992
+ thinking: ""
1993
+ }
1994
+ }, {
2248
1995
  type: "content_block_delta",
2249
- index: blockIndex$1,
1996
+ index: state$1.contentBlockIndex,
2250
1997
  delta: {
2251
1998
  type: "thinking_delta",
2252
1999
  thinking: THINKING_TEXT$1
2253
2000
  }
2254
- });
2255
- events$1.push({
2001
+ }, {
2256
2002
  type: "content_block_delta",
2257
- index: blockIndex$1,
2003
+ index: state$1.contentBlockIndex,
2258
2004
  delta: {
2259
2005
  type: "signature_delta",
2260
- signature: encodeCompactionCarrierSignature({
2261
- id: item.id,
2262
- encrypted_content: item.encrypted_content
2263
- })
2006
+ signature: delta.reasoning_opaque
2264
2007
  }
2008
+ }, {
2009
+ type: "content_block_stop",
2010
+ index: state$1.contentBlockIndex
2265
2011
  });
2266
- state$1.blockHasDelta.add(blockIndex$1);
2267
- return events$1;
2012
+ state$1.contentBlockIndex++;
2268
2013
  }
2269
- if (itemType !== "reasoning") return events$1;
2270
- const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
2271
- const signature = (item.encrypted_content ?? "") + "@" + item.id;
2272
- if (signature) {
2273
- if (!item.summary || item.summary.length === 0) events$1.push({
2014
+ }
2015
+ function handleThinkingText(delta, state$1, events$1) {
2016
+ const reasoningText = delta.reasoning_text ?? delta.reasoning_content;
2017
+ if (reasoningText && reasoningText.length > 0) {
2018
+ if (state$1.contentBlockOpen) {
2019
+ delta.content = reasoningText;
2020
+ delta.reasoning_text = void 0;
2021
+ delta.reasoning_content = void 0;
2022
+ return;
2023
+ }
2024
+ if (!state$1.thinkingBlockOpen) {
2025
+ events$1.push({
2026
+ type: "content_block_start",
2027
+ index: state$1.contentBlockIndex,
2028
+ content_block: {
2029
+ type: "thinking",
2030
+ thinking: ""
2031
+ }
2032
+ });
2033
+ state$1.thinkingBlockOpen = true;
2034
+ }
2035
+ events$1.push({
2274
2036
  type: "content_block_delta",
2275
- index: blockIndex,
2037
+ index: state$1.contentBlockIndex,
2276
2038
  delta: {
2277
2039
  type: "thinking_delta",
2278
- thinking: THINKING_TEXT$1
2040
+ thinking: reasoningText
2279
2041
  }
2280
2042
  });
2043
+ }
2044
+ }
2045
+ function closeThinkingBlockIfOpen(state$1, events$1) {
2046
+ if (state$1.thinkingBlockOpen) {
2281
2047
  events$1.push({
2282
2048
  type: "content_block_delta",
2283
- index: blockIndex,
2049
+ index: state$1.contentBlockIndex,
2284
2050
  delta: {
2285
2051
  type: "signature_delta",
2286
- signature
2052
+ signature: ""
2287
2053
  }
2054
+ }, {
2055
+ type: "content_block_stop",
2056
+ index: state$1.contentBlockIndex
2288
2057
  });
2289
- state$1.blockHasDelta.add(blockIndex);
2058
+ state$1.contentBlockIndex++;
2059
+ state$1.thinkingBlockOpen = false;
2290
2060
  }
2291
- return events$1;
2292
- };
2293
- const handleFunctionCallArgumentsDelta = (rawEvent, state$1) => {
2294
- const events$1 = new Array();
2295
- const outputIndex = rawEvent.output_index;
2296
- const deltaText = rawEvent.delta;
2297
- if (!deltaText) return events$1;
2298
- const blockIndex = openFunctionCallBlock(state$1, {
2299
- outputIndex,
2300
- events: events$1
2061
+ }
2062
+
2063
+ //#endregion
2064
+ //#region src/services/providers/anthropic-proxy.ts
2065
+ const SHARED_FORWARDABLE_HEADERS = ["accept", "user-agent"];
2066
+ const ANTHROPIC_FORWARDABLE_HEADERS = ["anthropic-version", "anthropic-beta"];
2067
+ const STRIPPED_RESPONSE_HEADERS = [
2068
+ "connection",
2069
+ "content-encoding",
2070
+ "content-length",
2071
+ "keep-alive",
2072
+ "proxy-authenticate",
2073
+ "proxy-authorization",
2074
+ "te",
2075
+ "trailer",
2076
+ "transfer-encoding",
2077
+ "upgrade"
2078
+ ];
2079
+ function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
2080
+ const authHeaders = {};
2081
+ if (providerConfig.authType === "authorization") authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
2082
+ else authHeaders["x-api-key"] = providerConfig.apiKey;
2083
+ const headers = {
2084
+ "content-type": "application/json",
2085
+ accept: "application/json",
2086
+ ...authHeaders
2087
+ };
2088
+ for (const headerName of SHARED_FORWARDABLE_HEADERS) {
2089
+ const headerValue = requestHeaders.get(headerName);
2090
+ if (headerValue) headers[headerName] = headerValue;
2091
+ }
2092
+ if (providerConfig.type !== "anthropic") return headers;
2093
+ for (const headerName of ANTHROPIC_FORWARDABLE_HEADERS) {
2094
+ const headerValue = requestHeaders.get(headerName);
2095
+ if (headerValue) headers[headerName] = headerValue;
2096
+ }
2097
+ return headers;
2098
+ }
2099
+ function createProviderProxyResponse(upstreamResponse) {
2100
+ const headers = new Headers(upstreamResponse.headers);
2101
+ for (const headerName of STRIPPED_RESPONSE_HEADERS) headers.delete(headerName);
2102
+ return new Response(upstreamResponse.body, {
2103
+ headers,
2104
+ status: upstreamResponse.status,
2105
+ statusText: upstreamResponse.statusText
2301
2106
  });
2302
- const functionCallState = state$1.functionCallStateByOutputIndex.get(outputIndex);
2303
- if (!functionCallState) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta without an open tool call block."), state$1, events$1);
2304
- const { nextCount, exceeded } = updateWhitespaceRunState(functionCallState.consecutiveWhitespaceCount, deltaText);
2305
- if (exceeded) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta containing more than 20 consecutive whitespace characters."), state$1, events$1);
2306
- functionCallState.consecutiveWhitespaceCount = nextCount;
2307
- events$1.push({
2308
- type: "content_block_delta",
2309
- index: blockIndex,
2310
- delta: {
2311
- type: "input_json_delta",
2312
- partial_json: deltaText
2313
- }
2107
+ }
2108
+ async function forwardProviderMessages(providerConfig, payload, requestHeaders) {
2109
+ return await fetch(`${providerConfig.baseUrl}/v1/messages`, {
2110
+ method: "POST",
2111
+ headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
2112
+ body: JSON.stringify(payload)
2314
2113
  });
2315
- state$1.blockHasDelta.add(blockIndex);
2316
- return events$1;
2317
- };
2318
- const handleFunctionCallArgumentsDone = (rawEvent, state$1) => {
2319
- const events$1 = new Array();
2320
- const outputIndex = rawEvent.output_index;
2321
- const blockIndex = openFunctionCallBlock(state$1, {
2322
- outputIndex,
2323
- events: events$1
2114
+ }
2115
+ async function forwardProviderChatCompletions(providerConfig, payload, requestHeaders) {
2116
+ return await fetch(`${providerConfig.baseUrl}/v1/chat/completions`, {
2117
+ method: "POST",
2118
+ headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
2119
+ body: JSON.stringify(payload)
2324
2120
  });
2325
- const finalArguments = typeof rawEvent.arguments === "string" ? rawEvent.arguments : void 0;
2326
- if (!state$1.blockHasDelta.has(blockIndex) && finalArguments) {
2327
- events$1.push({
2328
- type: "content_block_delta",
2329
- index: blockIndex,
2330
- delta: {
2331
- type: "input_json_delta",
2332
- partial_json: finalArguments
2333
- }
2334
- });
2335
- state$1.blockHasDelta.add(blockIndex);
2336
- }
2337
- state$1.functionCallStateByOutputIndex.delete(outputIndex);
2338
- return events$1;
2339
- };
2340
- const handleOutputTextDelta = (rawEvent, state$1) => {
2341
- const events$1 = new Array();
2342
- const outputIndex = rawEvent.output_index;
2343
- const contentIndex = rawEvent.content_index;
2344
- const deltaText = rawEvent.delta;
2345
- if (!deltaText) return events$1;
2346
- const blockIndex = openTextBlockIfNeeded(state$1, {
2347
- outputIndex,
2348
- contentIndex,
2349
- events: events$1
2121
+ }
2122
+ async function forwardProviderModels(providerConfig, requestHeaders) {
2123
+ return await fetch(`${providerConfig.baseUrl}/v1/models`, {
2124
+ method: "GET",
2125
+ headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders)
2350
2126
  });
2351
- events$1.push({
2352
- type: "content_block_delta",
2353
- index: blockIndex,
2354
- delta: {
2355
- type: "text_delta",
2356
- text: deltaText
2357
- }
2127
+ }
2128
+
2129
+ //#endregion
2130
+ //#region src/routes/provider/messages/handler.ts
2131
+ const logger$4 = createHandlerLogger("provider-messages-handler");
2132
+ const OPENAI_COMPATIBLE_CONTEXT_CACHE_MARKER_LIMIT = 4;
2133
+ const OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
2134
+ const OPENAI_COMPATIBLE_CONTEXT_CACHE_ROLES = new Set([
2135
+ "system",
2136
+ "user",
2137
+ "assistant",
2138
+ "tool"
2139
+ ]);
2140
+ async function handleProviderMessages(c) {
2141
+ const provider = c.req.param("provider");
2142
+ const payload = await c.req.json();
2143
+ return await handleProviderMessagesForProvider(c, {
2144
+ payload,
2145
+ provider
2358
2146
  });
2359
- state$1.blockHasDelta.add(blockIndex);
2360
- return events$1;
2361
- };
2362
- const handleReasoningSummaryTextDelta = (rawEvent, state$1) => {
2363
- const outputIndex = rawEvent.output_index;
2364
- const deltaText = rawEvent.delta;
2365
- const events$1 = new Array();
2366
- const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
2367
- events$1.push({
2368
- type: "content_block_delta",
2369
- index: blockIndex,
2370
- delta: {
2371
- type: "thinking_delta",
2372
- thinking: deltaText
2147
+ }
2148
+ async function handleProviderMessagesForProvider(c, options) {
2149
+ const { payload, provider } = options;
2150
+ const providerConfig = getProviderConfig(provider);
2151
+ if (!providerConfig) return c.json({ error: {
2152
+ message: `Provider '${provider}' not found or disabled`,
2153
+ type: "invalid_request_error"
2154
+ } }, 404);
2155
+ try {
2156
+ const modelConfig = providerConfig.models?.[payload.model];
2157
+ applyModelDefaults(payload, modelConfig);
2158
+ debugJson(logger$4, "provider.messages.request", {
2159
+ payload,
2160
+ provider
2161
+ });
2162
+ if (providerConfig.type === "openai-compatible") return await handleOpenAICompatibleProviderMessages(c, {
2163
+ modelConfig,
2164
+ payload,
2165
+ provider,
2166
+ providerConfig
2167
+ });
2168
+ applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
2169
+ const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
2170
+ if (!upstreamResponse.ok) {
2171
+ logger$4.error("Failed to create responses", upstreamResponse);
2172
+ throw new HTTPError("Failed to create responses", upstreamResponse);
2373
2173
  }
2374
- });
2375
- state$1.blockHasDelta.add(blockIndex);
2376
- return events$1;
2174
+ const contentType = upstreamResponse.headers.get("content-type") ?? "";
2175
+ if (Boolean(payload.stream) && contentType.includes("text/event-stream")) return streamProviderMessages({
2176
+ c,
2177
+ payload,
2178
+ provider,
2179
+ providerConfig,
2180
+ upstreamResponse
2181
+ });
2182
+ const jsonBody = await upstreamResponse.json();
2183
+ return respondProviderMessagesJson(c, {
2184
+ body: jsonBody,
2185
+ payload,
2186
+ provider,
2187
+ providerConfig
2188
+ });
2189
+ } catch (error) {
2190
+ logger$4.error("provider.messages.error", {
2191
+ provider,
2192
+ error
2193
+ });
2194
+ throw error;
2195
+ }
2196
+ }
2197
+ const applyModelDefaults = (payload, modelConfig) => {
2198
+ payload.temperature ??= modelConfig?.temperature;
2199
+ payload.top_p ??= modelConfig?.topP;
2200
+ payload.top_k ??= modelConfig?.topK;
2377
2201
  };
2378
- const handleReasoningSummaryTextDone = (rawEvent, state$1) => {
2379
- const outputIndex = rawEvent.output_index;
2380
- const text = rawEvent.text;
2381
- const events$1 = new Array();
2382
- const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
2383
- if (text && !state$1.blockHasDelta.has(blockIndex)) events$1.push({
2384
- type: "content_block_delta",
2385
- index: blockIndex,
2386
- delta: {
2387
- type: "thinking_delta",
2388
- thinking: text
2389
- }
2202
+ const applyMissingExtraBody = (payload, options) => {
2203
+ for (const [key, value] of Object.entries(options.extraBody ?? {})) if (!Object.hasOwn(payload, key)) payload[key] = value;
2204
+ };
2205
+ const handleOpenAICompatibleProviderMessages = async (c, options) => {
2206
+ const { modelConfig, payload, provider, providerConfig } = options;
2207
+ const openAIPayload = createOpenAICompatiblePayload(payload, modelConfig);
2208
+ debugJson(logger$4, "provider.messages.openai_compatible.request", {
2209
+ payload: openAIPayload,
2210
+ provider
2211
+ });
2212
+ const upstreamResponse = await forwardProviderChatCompletions(providerConfig, openAIPayload, c.req.raw.headers);
2213
+ if (!upstreamResponse.ok) {
2214
+ logger$4.error("Failed to create openai-compatible responses", upstreamResponse);
2215
+ throw new HTTPError("Failed to create openai-compatible responses", upstreamResponse);
2216
+ }
2217
+ const contentType = upstreamResponse.headers.get("content-type") ?? "";
2218
+ if (Boolean(openAIPayload.stream) && contentType.includes("text/event-stream")) return streamOpenAICompatibleProviderMessages({
2219
+ c,
2220
+ payload,
2221
+ provider,
2222
+ upstreamResponse
2223
+ });
2224
+ const jsonBody = await upstreamResponse.json();
2225
+ return respondOpenAICompatibleProviderMessagesJson(c, {
2226
+ body: jsonBody,
2227
+ payload,
2228
+ provider
2390
2229
  });
2391
- return events$1;
2392
2230
  };
2393
- const handleOutputTextDone = (rawEvent, state$1) => {
2394
- const events$1 = new Array();
2395
- const outputIndex = rawEvent.output_index;
2396
- const contentIndex = rawEvent.content_index;
2397
- const text = rawEvent.text;
2398
- const blockIndex = openTextBlockIfNeeded(state$1, {
2399
- outputIndex,
2400
- contentIndex,
2401
- events: events$1
2231
+ const createOpenAICompatiblePayload = (payload, modelConfig) => {
2232
+ const openAIPayload = translateToOpenAI(payload, {
2233
+ supportPdf: modelConfig?.supportPdf,
2234
+ toolContentSupportType: modelConfig?.toolContentSupportType ?? []
2402
2235
  });
2403
- if (text && !state$1.blockHasDelta.has(blockIndex)) events$1.push({
2404
- type: "content_block_delta",
2405
- index: blockIndex,
2406
- delta: {
2407
- type: "text_delta",
2408
- text
2409
- }
2236
+ if (payload.top_k !== void 0) openAIPayload.top_k = payload.top_k;
2237
+ if (openAIPayload.stream) openAIPayload.stream_options = { include_usage: true };
2238
+ normalizeOpenAICompatibleReasoningContent(openAIPayload);
2239
+ applyOpenAICompatibleRequestOverrides(openAIPayload, {
2240
+ extraBody: modelConfig?.extraBody,
2241
+ source: payload
2410
2242
  });
2411
- return events$1;
2243
+ applyMissingExtraBody(openAIPayload, { extraBody: modelConfig?.extraBody });
2244
+ if (!Object.hasOwn(openAIPayload, "parallel_tool_calls")) openAIPayload.parallel_tool_calls = true;
2245
+ if (modelConfig?.contextCache !== false) applyOpenAICompatibleContextCache(openAIPayload);
2246
+ return openAIPayload;
2412
2247
  };
2413
- const handleResponseCompleted = (rawEvent, state$1) => {
2414
- const response = rawEvent.response;
2415
- const events$1 = new Array();
2416
- closeAllOpenBlocks(state$1, events$1);
2417
- const anthropic = translateResponsesResultToAnthropic(response);
2418
- events$1.push({
2419
- type: "message_delta",
2420
- delta: {
2421
- stop_reason: anthropic.stop_reason,
2422
- stop_sequence: anthropic.stop_sequence
2423
- },
2424
- usage: anthropic.usage
2425
- }, { type: "message_stop" });
2426
- state$1.messageCompleted = true;
2427
- return events$1;
2248
+ const normalizeOpenAICompatibleReasoningContent = (payload) => {
2249
+ for (const message of payload.messages) {
2250
+ if (message.role !== "assistant") continue;
2251
+ if (message.reasoning_content === void 0 && message.reasoning_text !== void 0) message.reasoning_content = message.reasoning_text;
2252
+ delete message.reasoning_text;
2253
+ delete message.reasoning_opaque;
2254
+ }
2428
2255
  };
2429
- const handleResponseFailed = (rawEvent, state$1) => {
2430
- const response = rawEvent.response;
2431
- const events$1 = new Array();
2432
- closeAllOpenBlocks(state$1, events$1);
2433
- const message = response.error?.message ?? "The response failed due to an unknown error.";
2434
- events$1.push(buildErrorEvent(message));
2435
- state$1.messageCompleted = true;
2436
- return events$1;
2256
+ const applyOpenAICompatibleRequestOverrides = (payload, options) => {
2257
+ const allowedKeys = new Set(Object.keys(options.extraBody ?? {}));
2258
+ for (const key of allowedKeys) if (Object.hasOwn(options.source, key)) payload[key] = options.source[key];
2437
2259
  };
2438
- const handleErrorEvent = (rawEvent, state$1) => {
2439
- const message = typeof rawEvent.message === "string" ? rawEvent.message : "An unexpected error occurred during streaming.";
2440
- state$1.messageCompleted = true;
2441
- return [buildErrorEvent(message)];
2260
+ const applyOpenAICompatibleContextCache = (payload) => {
2261
+ const messageIndexes = selectContextCacheMessageIndexes(payload.messages);
2262
+ for (const messageIndex of messageIndexes) applyContextCacheControl(payload.messages[messageIndex]);
2442
2263
  };
2443
- const handleFunctionCallArgumentsValidationError = (error, state$1, events$1 = []) => {
2444
- const reason = error.message;
2445
- closeAllOpenBlocks(state$1, events$1);
2446
- state$1.messageCompleted = true;
2447
- events$1.push(buildErrorEvent(reason));
2448
- return events$1;
2264
+ const selectContextCacheMessageIndexes = (messages) => {
2265
+ const cacheableIndexes = messages.flatMap((message, index) => isContextCacheMarkerEligible(message) ? [index] : []);
2266
+ const systemIndexes = cacheableIndexes.filter((index) => messages[index]?.role === "system").slice(0, 2);
2267
+ const finalIndexes = cacheableIndexes.filter((index) => messages[index]?.role !== "system").slice(-2);
2268
+ return uniqueIndexes$1([...systemIndexes, ...finalIndexes]).sort((a, b) => a - b);
2449
2269
  };
2450
- const messageStart = (state$1, response) => {
2451
- state$1.messageStartSent = true;
2452
- const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
2453
- const inputTokens = (response.usage?.input_tokens ?? 0) - (inputCachedTokens ?? 0);
2454
- return [{
2455
- type: "message_start",
2456
- message: {
2457
- id: response.id,
2458
- type: "message",
2459
- role: "assistant",
2460
- content: [],
2461
- model: response.model,
2462
- stop_reason: null,
2463
- stop_sequence: null,
2464
- usage: {
2465
- input_tokens: inputTokens,
2466
- output_tokens: 0,
2467
- cache_read_input_tokens: inputCachedTokens ?? 0
2270
+ const uniqueIndexes$1 = (indexes) => [...new Set(indexes)].slice(0, OPENAI_COMPATIBLE_CONTEXT_CACHE_MARKER_LIMIT);
2271
+ const isContextCacheMarkerEligible = (message) => {
2272
+ if (!OPENAI_COMPATIBLE_CONTEXT_CACHE_ROLES.has(message.role)) return false;
2273
+ if (typeof message.content === "string") return message.content.length > 0;
2274
+ return Array.isArray(message.content) && message.content.length > 0;
2275
+ };
2276
+ const applyContextCacheControl = (message) => {
2277
+ if (!message) return;
2278
+ if (typeof message.content === "string") {
2279
+ message.content = [{
2280
+ type: "text",
2281
+ text: message.content,
2282
+ cache_control: { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL }
2283
+ }];
2284
+ return;
2285
+ }
2286
+ if (!Array.isArray(message.content)) return;
2287
+ const lastPart = message.content.at(-1);
2288
+ if (!lastPart) return;
2289
+ setContextCacheControl(lastPart);
2290
+ };
2291
+ const setContextCacheControl = (part) => {
2292
+ part.cache_control = { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL };
2293
+ };
2294
+ const streamProviderMessages = ({ c, payload, provider, providerConfig, upstreamResponse }) => {
2295
+ logger$4.debug("provider.messages.streaming");
2296
+ const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
2297
+ return streamSSE(c, async (stream) => {
2298
+ let usage = {};
2299
+ for await (const chunk of events(upstreamResponse)) {
2300
+ logger$4.debug("provider.messages.raw_stream_event:", chunk.data);
2301
+ const eventName = chunk.event;
2302
+ if (eventName === "ping") {
2303
+ await stream.writeSSE({
2304
+ event: "ping",
2305
+ data: "{\"type\":\"ping\"}"
2306
+ });
2307
+ continue;
2308
+ }
2309
+ let data = chunk.data;
2310
+ if (!data) continue;
2311
+ if (chunk.data === "[DONE]") break;
2312
+ const parsed = parseProviderStreamEvent(data, providerConfig);
2313
+ if (parsed) {
2314
+ usage = mergeAnthropicUsage(usage, parsed.usage);
2315
+ data = parsed.data;
2468
2316
  }
2317
+ await stream.writeSSE({
2318
+ event: eventName,
2319
+ data
2320
+ });
2469
2321
  }
2470
- }];
2322
+ recordUsage(usage);
2323
+ });
2471
2324
  };
2472
- const openTextBlockIfNeeded = (state$1, params) => {
2473
- const { outputIndex, contentIndex, events: events$1 } = params;
2474
- const key = getBlockKey(outputIndex, contentIndex);
2475
- let blockIndex = state$1.blockIndexByKey.get(key);
2476
- if (blockIndex === void 0) {
2477
- blockIndex = state$1.nextContentBlockIndex;
2478
- state$1.nextContentBlockIndex += 1;
2479
- state$1.blockIndexByKey.set(key, blockIndex);
2480
- }
2481
- if (!state$1.openBlocks.has(blockIndex)) {
2482
- closeOpenBlocks(state$1, events$1);
2483
- events$1.push({
2484
- type: "content_block_start",
2485
- index: blockIndex,
2486
- content_block: {
2487
- type: "text",
2488
- text: ""
2325
+ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
2326
+ logger$4.debug("provider.messages.openai_compatible.streaming");
2327
+ const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
2328
+ return streamSSE(c, async (stream) => {
2329
+ let usage = {};
2330
+ const streamState = {
2331
+ messageStartSent: false,
2332
+ contentBlockIndex: 0,
2333
+ contentBlockOpen: false,
2334
+ toolCalls: {},
2335
+ thinkingBlockOpen: false
2336
+ };
2337
+ for await (const chunk of events(upstreamResponse)) {
2338
+ logger$4.debug("provider.messages.openai_compatible.raw_stream_event:", chunk.data);
2339
+ if (chunk.event === "ping") {
2340
+ await stream.writeSSE({
2341
+ event: "ping",
2342
+ data: "{\"type\":\"ping\"}"
2343
+ });
2344
+ continue;
2345
+ }
2346
+ if (!chunk.data || chunk.data === "[DONE]") {
2347
+ if (chunk.data === "[DONE]") break;
2348
+ continue;
2349
+ }
2350
+ const parsed = parseOpenAICompatibleStreamChunk(chunk.data);
2351
+ if (!parsed) continue;
2352
+ if (parsed.usage) usage = normalizeOpenAIUsage(parsed.usage);
2353
+ const events$1 = translateChunkToAnthropicEvents(parsed, streamState);
2354
+ for (const event of events$1) {
2355
+ const eventData = JSON.stringify(event);
2356
+ debugLazy(logger$4, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
2357
+ await stream.writeSSE({
2358
+ event: event.type,
2359
+ data: eventData
2360
+ });
2489
2361
  }
2362
+ }
2363
+ for (const event of flushPendingAnthropicStreamEvents(streamState)) {
2364
+ const eventData = JSON.stringify(event);
2365
+ debugLazy(logger$4, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
2366
+ await stream.writeSSE({
2367
+ event: event.type,
2368
+ data: eventData
2369
+ });
2370
+ }
2371
+ recordUsage(usage);
2372
+ });
2373
+ };
2374
+ const parseOpenAICompatibleStreamChunk = (data) => {
2375
+ try {
2376
+ return JSON.parse(data);
2377
+ } catch (error) {
2378
+ logger$4.error("provider.messages.openai_compatible.parse_chunk_error", {
2379
+ data,
2380
+ error
2490
2381
  });
2491
- state$1.openBlocks.add(blockIndex);
2382
+ return null;
2492
2383
  }
2493
- return blockIndex;
2494
2384
  };
2495
- const openThinkingBlockIfNeeded = (state$1, outputIndex, events$1) => {
2496
- const key = getBlockKey(outputIndex, 0);
2497
- let blockIndex = state$1.blockIndexByKey.get(key);
2498
- if (blockIndex === void 0) {
2499
- blockIndex = state$1.nextContentBlockIndex;
2500
- state$1.nextContentBlockIndex += 1;
2501
- state$1.blockIndexByKey.set(key, blockIndex);
2502
- }
2503
- if (!state$1.openBlocks.has(blockIndex)) {
2504
- closeOpenBlocks(state$1, events$1);
2505
- events$1.push({
2506
- type: "content_block_start",
2507
- index: blockIndex,
2508
- content_block: {
2509
- type: "thinking",
2510
- thinking: ""
2511
- }
2385
+ const parseProviderStreamEvent = (data, providerConfig) => {
2386
+ try {
2387
+ const parsed = JSON.parse(data);
2388
+ if (parsed.type === "message_start") {
2389
+ adjustInputTokens(providerConfig, parsed.message.usage);
2390
+ return {
2391
+ data: JSON.stringify(parsed),
2392
+ model: parsed.message.model,
2393
+ usage: normalizeAnthropicUsage(parsed.message.usage)
2394
+ };
2395
+ }
2396
+ if (parsed.type === "message_delta") {
2397
+ adjustInputTokens(providerConfig, parsed.usage);
2398
+ return {
2399
+ data: JSON.stringify(parsed),
2400
+ usage: normalizeAnthropicUsage(parsed.usage)
2401
+ };
2402
+ }
2403
+ return {
2404
+ data: JSON.stringify(parsed),
2405
+ usage: {}
2406
+ };
2407
+ } catch (error) {
2408
+ logger$4.error("provider.messages.streaming.adjust_tokens_error", {
2409
+ error,
2410
+ originalData: data
2512
2411
  });
2513
- state$1.openBlocks.add(blockIndex);
2412
+ return null;
2514
2413
  }
2515
- return blockIndex;
2516
- };
2517
- const closeBlockIfOpen = (state$1, blockIndex, events$1) => {
2518
- if (!state$1.openBlocks.has(blockIndex)) return;
2519
- events$1.push({
2520
- type: "content_block_stop",
2521
- index: blockIndex
2522
- });
2523
- state$1.openBlocks.delete(blockIndex);
2524
- state$1.blockHasDelta.delete(blockIndex);
2525
2414
  };
2526
- const closeOpenBlocks = (state$1, events$1) => {
2527
- for (const blockIndex of state$1.openBlocks) closeBlockIfOpen(state$1, blockIndex, events$1);
2415
+ const respondProviderMessagesJson = (c, options) => {
2416
+ const { body, payload, provider, providerConfig } = options;
2417
+ const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
2418
+ adjustInputTokens(providerConfig, body.usage);
2419
+ recordUsage(normalizeAnthropicUsage(body.usage));
2420
+ debugJson(logger$4, "provider.messages.no_stream result:", body);
2421
+ return c.json(body);
2528
2422
  };
2529
- const closeAllOpenBlocks = (state$1, events$1) => {
2530
- closeOpenBlocks(state$1, events$1);
2531
- state$1.functionCallStateByOutputIndex.clear();
2423
+ const respondOpenAICompatibleProviderMessagesJson = (c, options) => {
2424
+ const { body, payload, provider } = options;
2425
+ createProviderMessagesUsageRecorder(payload, provider)(normalizeOpenAIUsage(body.usage));
2426
+ const anthropicResponse = translateToAnthropic(body);
2427
+ debugJson(logger$4, "provider.messages.openai_compatible.no_stream result:", anthropicResponse);
2428
+ return c.json(anthropicResponse);
2532
2429
  };
2533
- const buildErrorEvent = (message) => ({
2534
- type: "error",
2535
- error: {
2536
- type: "api_error",
2537
- message
2538
- }
2430
+ const createProviderMessagesUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
2431
+ endpoint: "provider_messages",
2432
+ model: payload.model,
2433
+ providerName: provider,
2434
+ sessionId: parseUserIdMetadata(payload.metadata?.user_id).sessionId
2539
2435
  });
2540
- const getBlockKey = (outputIndex, contentIndex) => `${outputIndex}:${contentIndex}`;
2541
- const openFunctionCallBlock = (state$1, params) => {
2542
- const { outputIndex, toolCallId, name, events: events$1 } = params;
2543
- let functionCallState = state$1.functionCallStateByOutputIndex.get(outputIndex);
2544
- if (!functionCallState) {
2545
- const blockIndex$1 = state$1.nextContentBlockIndex;
2546
- state$1.nextContentBlockIndex += 1;
2547
- const resolvedToolCallId = toolCallId ?? `tool_call_${blockIndex$1}`;
2548
- functionCallState = {
2549
- blockIndex: blockIndex$1,
2550
- toolCallId: resolvedToolCallId,
2551
- name: name ?? "function",
2552
- consecutiveWhitespaceCount: 0
2553
- };
2554
- state$1.functionCallStateByOutputIndex.set(outputIndex, functionCallState);
2555
- }
2556
- const { blockIndex } = functionCallState;
2557
- if (!state$1.openBlocks.has(blockIndex)) {
2558
- closeOpenBlocks(state$1, events$1);
2559
- events$1.push({
2560
- type: "content_block_start",
2561
- index: blockIndex,
2562
- content_block: {
2563
- type: "tool_use",
2564
- id: functionCallState.toolCallId,
2565
- name: functionCallState.name,
2566
- input: {}
2567
- }
2568
- });
2569
- state$1.openBlocks.add(blockIndex);
2570
- }
2571
- return blockIndex;
2436
+ const adjustInputTokens = (providerConfig, usage) => {
2437
+ if (!providerConfig.adjustInputTokens || !usage) return;
2438
+ usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
2439
+ debugJson(logger$4, "provider.messages.adjusted_usage:", usage);
2572
2440
  };
2573
- const extractFunctionCallDetails = (rawEvent) => {
2574
- const item = rawEvent.item;
2575
- if (item.type !== "function_call") return;
2576
- const outputIndex = rawEvent.output_index;
2577
- const toolCallId = item.call_id;
2578
- const name = item.name;
2579
- const initialArguments = item.arguments;
2580
- return {
2581
- outputIndex,
2582
- toolCallId,
2583
- name,
2584
- initialArguments
2441
+
2442
+ //#endregion
2443
+ //#region src/services/copilot/create-responses.ts
2444
+ const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId, compactType }) => {
2445
+ if (!state.copilotToken) throw new Error("Copilot token not found");
2446
+ const headers = {
2447
+ ...copilotHeaders(state, requestId, vision),
2448
+ "x-initiator": initiator
2585
2449
  };
2450
+ prepareInteractionHeaders(sessionId, Boolean(subagentMarker), headers);
2451
+ prepareForCompact(headers, compactType);
2452
+ payload.service_tier = void 0;
2453
+ consola.log(`<-- model: ${payload.model}`);
2454
+ const response = await fetch(`${copilotBaseUrl(state)}/responses`, {
2455
+ method: "POST",
2456
+ headers,
2457
+ body: JSON.stringify(payload)
2458
+ });
2459
+ logCopilotRateLimits(response.headers);
2460
+ if (!response.ok) {
2461
+ consola.error("Failed to create responses", response);
2462
+ throw new HTTPError("Failed to create responses", response);
2463
+ }
2464
+ if (payload.stream) return events(response);
2465
+ return await response.json();
2586
2466
  };
2587
2467
 
2588
2468
  //#endregion
2589
- //#region src/routes/responses/utils.ts
2590
- const getResponsesRequestOptions = (payload) => {
2591
- const vision = hasVisionInput(payload);
2592
- const initiator = hasAgentInitiator(payload) ? "agent" : "user";
2469
+ //#region src/routes/messages/responses-translation.ts
2470
+ const MESSAGE_TYPE = "message";
2471
+ const COMPACTION_SIGNATURE_PREFIX = "cm1#";
2472
+ const COMPACTION_SIGNATURE_SEPARATOR = "@";
2473
+ const THINKING_TEXT = "Thinking...";
2474
+ const translateAnthropicMessagesToResponsesPayload = (payload) => {
2475
+ const input = [];
2476
+ const applyPhase = shouldApplyPhase(payload.model);
2477
+ for (const message of payload.messages) input.push(...translateMessage(message, payload.model, applyPhase));
2478
+ const translatedTools = convertAnthropicTools(payload.tools);
2479
+ const toolChoice = convertAnthropicToolChoice(payload.tool_choice);
2480
+ const { sessionId: promptCacheKey } = parseUserIdMetadata(payload.metadata?.user_id);
2593
2481
  return {
2594
- vision,
2595
- initiator
2482
+ model: payload.model,
2483
+ input,
2484
+ instructions: translateSystemPrompt(payload.system, payload.model),
2485
+ temperature: 1,
2486
+ top_p: payload.top_p ?? null,
2487
+ max_output_tokens: Math.max(payload.max_tokens, 12800),
2488
+ tools: translatedTools,
2489
+ tool_choice: toolChoice,
2490
+ metadata: payload.metadata ? { ...payload.metadata } : null,
2491
+ prompt_cache_key: promptCacheKey,
2492
+ stream: payload.stream ?? null,
2493
+ store: false,
2494
+ parallel_tool_calls: true,
2495
+ reasoning: {
2496
+ effort: getReasoningEffortForModel(payload.model),
2497
+ summary: "detailed"
2498
+ },
2499
+ include: ["reasoning.encrypted_content"]
2596
2500
  };
2597
2501
  };
2598
- const hasAgentInitiator = (payload) => {
2599
- const lastItem = getPayloadItems(payload).at(-1);
2600
- if (!lastItem) return false;
2601
- if (!("role" in lastItem) || !lastItem.role) return true;
2602
- return (typeof lastItem.role === "string" ? lastItem.role.toLowerCase() : "") === "assistant";
2603
- };
2604
- const hasVisionInput = (payload) => {
2605
- return getPayloadItems(payload).some((item) => containsVisionContent(item));
2606
- };
2607
- const resolveResponsesCompactThreshold = (maxPromptTokens) => {
2608
- if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
2609
- return 5e4;
2610
- };
2611
- const createCompactionContextManagement = (compactThreshold) => [{
2612
- type: "compaction",
2613
- compact_threshold: compactThreshold
2614
- }];
2615
- const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
2616
- if (payload.context_management !== void 0) return;
2617
- if (!isResponsesApiContextManagementModel(payload.model)) return;
2618
- payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
2619
- };
2620
- const compactInputByLatestCompaction = (payload) => {
2621
- if (!Array.isArray(payload.input) || payload.input.length === 0) return;
2622
- const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
2623
- if (latestCompactionMessageIndex === void 0) return;
2624
- payload.input = payload.input.slice(latestCompactionMessageIndex);
2502
+ const encodeCompactionCarrierSignature = (compaction) => {
2503
+ return `${COMPACTION_SIGNATURE_PREFIX}${compaction.encrypted_content}${COMPACTION_SIGNATURE_SEPARATOR}${compaction.id}`;
2625
2504
  };
2626
- const getLatestCompactionMessageIndex = (input) => {
2627
- for (let index = input.length - 1; index >= 0; index -= 1) if (isCompactionInputItem(input[index])) return index;
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
+ }
2628
2518
  };
2629
- const isCompactionInputItem = (value) => {
2630
- return "type" in value && typeof value.type === "string" && value.type === "compaction";
2519
+ const translateMessage = (message, model, applyPhase) => {
2520
+ if (message.role === "user") return translateUserMessage(message);
2521
+ return translateAssistantMessage(message, model, applyPhase);
2631
2522
  };
2632
- const getPayloadItems = (payload) => {
2633
- const result = [];
2634
- const { input } = payload;
2635
- if (Array.isArray(input)) result.push(...input);
2636
- return result;
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.length > 0) pendingContent.push(...converted);
2536
+ }
2537
+ flushPendingContent(pendingContent, items, { role: "user" });
2538
+ return items;
2637
2539
  };
2638
- const containsVisionContent = (value) => {
2639
- if (!value) return false;
2640
- if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
2641
- if (typeof value !== "object") return false;
2642
- const record = value;
2643
- if ((typeof record.type === "string" ? record.type.toLowerCase() : void 0) === "input_image") return true;
2644
- if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
2645
- return false;
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);
2576
+ }
2577
+ flushPendingContent(pendingContent, items, {
2578
+ role: "assistant",
2579
+ phase: assistantPhase
2580
+ });
2581
+ return items;
2646
2582
  };
2647
-
2648
- //#endregion
2649
- //#region src/services/copilot/create-messages.ts
2650
- const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
2651
- const allowedAnthropicBetas = new Set([
2652
- INTERLEAVED_THINKING_BETA,
2653
- "context-management-2025-06-27",
2654
- "advanced-tool-use-2025-11-20"
2655
- ]);
2656
- const buildAnthropicBetaHeader = (anthropicBetaHeader, thinking, _model) => {
2657
- const isAdaptiveThinking = thinking?.type === "adaptive";
2658
- if (anthropicBetaHeader) {
2659
- const uniqueFilteredBetas = [...anthropicBetaHeader.split(",").map((item) => item.trim()).filter((item) => item.length > 0).filter((item) => allowedAnthropicBetas.has(item))];
2660
- if (uniqueFilteredBetas.length > 0) return uniqueFilteredBetas.join(",");
2661
- return;
2583
+ const translateUserContentBlock = (block) => {
2584
+ switch (block.type) {
2585
+ case "text": return [createTextContent(block.text)];
2586
+ case "image": return [createImageContent(block)];
2587
+ case "document": return [createFileContent(block)];
2588
+ default: return [];
2662
2589
  }
2663
- if (thinking?.budget_tokens && !isAdaptiveThinking) return INTERLEAVED_THINKING_BETA;
2664
2590
  };
2665
- const createMessages = async (payload, anthropicBetaHeader, options) => {
2666
- if (!state.copilotToken) throw new Error("Copilot token not found");
2667
- const enableVision = payload.messages.some((message) => {
2668
- if (!Array.isArray(message.content)) return false;
2669
- return message.content.some((block) => block.type === "image" || block.type === "tool_result" && Array.isArray(block.content) && block.content.some((inner) => inner.type === "image"));
2670
- });
2671
- let isInitiateRequest = false;
2672
- const lastMessage = payload.messages.at(-1);
2673
- if (lastMessage?.role === "user") isInitiateRequest = Array.isArray(lastMessage.content) ? lastMessage.content.some((block) => block.type !== "tool_result") : true;
2674
- const headers = {
2675
- ...copilotHeaders(state, options.requestId, enableVision),
2676
- "x-initiator": isInitiateRequest ? "user" : "agent"
2677
- };
2678
- prepareInteractionHeaders(options.sessionId, Boolean(options.subagentMarker), headers);
2679
- prepareForCompact(headers, options.compactType);
2680
- const { safetyIdentifier, sessionId } = parseUserIdMetadata(payload.metadata?.user_id);
2681
- if (safetyIdentifier && sessionId) prepareMessageProxyHeaders(headers);
2682
- const anthropicBeta = buildAnthropicBetaHeader(anthropicBetaHeader, payload.thinking, payload.model);
2683
- if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
2684
- consola.log(`<-- model: ${payload.model}`);
2685
- const response = await fetch(`${copilotBaseUrl(state)}/v1/messages`, {
2686
- method: "POST",
2687
- headers,
2688
- body: JSON.stringify(payload)
2689
- });
2690
- logCopilotRateLimits(response.headers);
2691
- if (!response.ok) {
2692
- consola.error("Failed to create messages", response);
2693
- throw new HTTPError("Failed to create messages", response);
2591
+ const translateAssistantContentBlock = (block) => {
2592
+ switch (block.type) {
2593
+ case "text": return createOutPutTextContent(block.text);
2594
+ default: return;
2694
2595
  }
2695
- if (payload.stream) return events(response);
2696
- return await response.json();
2697
2596
  };
2698
-
2699
- //#endregion
2700
- //#region src/routes/messages/preprocess.ts
2701
- const TOOL_REFERENCE_TURN_BOUNDARY = "Tool loaded.";
2702
- const IDE_EXECUTE_CODE_TOOL = "mcp__ide__executeCode";
2703
- const IDE_GET_DIAGNOSTICS_TOOL = "mcp__ide__getDiagnostics";
2704
- const IDE_GET_DIAGNOSTICS_DESCRIPTION = "Get language diagnostics from VS Code. Returns errors, warnings, information, and hints for files in the workspace.";
2705
- const PDF_FILE_READ_PREFIX = "PDF file read:";
2706
- const getCompactCandidateText = (message) => {
2707
- if (message.role !== "user") return "";
2708
- if (typeof message.content === "string") return message.content;
2709
- return message.content.filter((block) => block.type === "text").map((block) => block.text.startsWith("<system-reminder>") ? "" : block.text).filter((text) => text.length > 0).join("\n\n");
2597
+ const flushPendingContent = (pendingContent, target, message) => {
2598
+ if (pendingContent.length === 0) return;
2599
+ const messageContent = [...pendingContent];
2600
+ target.push(createMessage(message.role, messageContent, message.phase));
2601
+ pendingContent.length = 0;
2710
2602
  };
2711
- const isCompactMessage = (lastMessage) => {
2712
- const text = getCompactCandidateText(lastMessage);
2713
- if (!text) return false;
2714
- return text.includes(compactTextOnlyGuard) && text.includes(compactSummaryPromptStart) && compactMessageSections.some((section) => text.includes(section));
2603
+ const createMessage = (role, content, phase) => ({
2604
+ type: MESSAGE_TYPE,
2605
+ role,
2606
+ content,
2607
+ ...role === "assistant" && phase ? { phase } : {}
2608
+ });
2609
+ const resolveAssistantPhase = (_model, content, applyPhase) => {
2610
+ if (!applyPhase) return;
2611
+ if (typeof content === "string") return "final_answer";
2612
+ if (!Array.isArray(content)) return;
2613
+ if (!content.some((block) => block.type === "text")) return;
2614
+ return content.some((block) => block.type === "tool_use") ? "commentary" : "final_answer";
2715
2615
  };
2716
- const isCompactAutoContinueMessage = (lastMessage) => {
2717
- const text = getCompactCandidateText(lastMessage);
2718
- return Boolean(text) && compactAutoContinuePromptStarts.some((promptStart) => text.startsWith(promptStart));
2616
+ const shouldApplyPhase = (model) => {
2617
+ return getExtraPromptForModel(model).includes("## Intermediary updates");
2719
2618
  };
2720
- const getCompactType = (anthropicPayload) => {
2721
- const lastMessage = anthropicPayload.messages.at(-1);
2722
- if (lastMessage && isCompactMessage(lastMessage)) return COMPACT_REQUEST;
2723
- if (lastMessage && isCompactAutoContinueMessage(lastMessage)) return COMPACT_AUTO_CONTINUE;
2724
- const system = anthropicPayload.system;
2725
- if (typeof system === "string") return compactSystemPromptStarts.some((promptStart) => system.startsWith(promptStart)) ? COMPACT_REQUEST : 0;
2726
- if (!Array.isArray(system)) return 0;
2727
- if (system.some((msg) => typeof msg.text === "string" && compactSystemPromptStarts.some((promptStart) => msg.text.startsWith(promptStart)))) return COMPACT_REQUEST;
2728
- return 0;
2619
+ const createTextContent = (text) => ({
2620
+ type: "input_text",
2621
+ text
2622
+ });
2623
+ const createOutPutTextContent = (text) => ({
2624
+ type: "output_text",
2625
+ text
2626
+ });
2627
+ const createImageContent = (block) => ({
2628
+ type: "input_image",
2629
+ image_url: `data:${block.source.media_type};base64,${block.source.data}`,
2630
+ detail: "auto"
2631
+ });
2632
+ const createFileContent = (block) => ({
2633
+ type: "input_file",
2634
+ file_data: `data:${block.source.media_type};base64,${block.source.data}`,
2635
+ filename: block.title ?? "document.pdf"
2636
+ });
2637
+ const createReasoningContent = (block) => {
2638
+ const { encryptedContent, id } = parseReasoningSignature(block.signature);
2639
+ const thinking = block.thinking === THINKING_TEXT ? "" : block.thinking;
2640
+ return {
2641
+ id,
2642
+ type: "reasoning",
2643
+ summary: thinking ? [{
2644
+ type: "summary_text",
2645
+ text: thinking
2646
+ }] : [],
2647
+ encrypted_content: encryptedContent
2648
+ };
2729
2649
  };
2730
- const mergeContentWithText = (tr, textBlock) => {
2731
- if (typeof tr.content === "string") return {
2732
- ...tr,
2733
- content: `${tr.content}\n\n${textBlock.text}`
2650
+ const createCompactionContent = (block) => {
2651
+ const compaction = decodeCompactionCarrierSignature(block.signature);
2652
+ if (!compaction) return;
2653
+ return {
2654
+ id: compaction.id,
2655
+ type: "compaction",
2656
+ encrypted_content: compaction.encrypted_content
2657
+ };
2658
+ };
2659
+ const parseReasoningSignature = (signature) => {
2660
+ const splitIndex = signature.lastIndexOf("@");
2661
+ if (splitIndex <= 0 || splitIndex === signature.length - 1) return {
2662
+ encryptedContent: signature,
2663
+ id: ""
2734
2664
  };
2735
- if (hasToolRef(tr)) return tr;
2736
2665
  return {
2737
- ...tr,
2738
- content: [...tr.content, textBlock]
2666
+ encryptedContent: signature.slice(0, splitIndex),
2667
+ id: signature.slice(splitIndex + 1)
2739
2668
  };
2740
2669
  };
2741
- const mergeContentWithTexts = (tr, textBlocks) => {
2742
- if (typeof tr.content === "string") {
2743
- const appendedTexts = textBlocks.map((tb) => tb.text).join("\n\n");
2744
- return {
2745
- ...tr,
2746
- content: `${tr.content}\n\n${appendedTexts}`
2747
- };
2670
+ const createFunctionToolCall = (block) => ({
2671
+ type: "function_call",
2672
+ call_id: block.id,
2673
+ name: block.name,
2674
+ arguments: JSON.stringify(block.input),
2675
+ status: "completed"
2676
+ });
2677
+ const createFunctionCallOutput = (block) => ({
2678
+ type: "function_call_output",
2679
+ call_id: block.tool_use_id,
2680
+ output: convertToolResultContent(block.content),
2681
+ status: block.is_error ? "incomplete" : "completed"
2682
+ });
2683
+ const translateSystemPrompt = (system, model) => {
2684
+ if (!system) return null;
2685
+ const extraPrompt = getExtraPromptForModel(model);
2686
+ if (typeof system === "string") return system + extraPrompt;
2687
+ const text = system.map((block, index) => {
2688
+ if (index === 0) return block.text + "\n\n" + extraPrompt + "\n\n";
2689
+ return block.text;
2690
+ }).join(" ");
2691
+ return text.length > 0 ? text : null;
2692
+ };
2693
+ const convertAnthropicTools = (tools) => {
2694
+ if (!tools || tools.length === 0) return null;
2695
+ return tools.map((tool) => ({
2696
+ type: "function",
2697
+ name: tool.name,
2698
+ parameters: normalizeToolSchema(tool.input_schema),
2699
+ strict: false,
2700
+ ...tool.description ? { description: tool.description } : {}
2701
+ }));
2702
+ };
2703
+ const convertAnthropicToolChoice = (choice) => {
2704
+ if (!choice) return "auto";
2705
+ switch (choice.type) {
2706
+ case "auto": return "auto";
2707
+ case "any": return "required";
2708
+ case "tool": return choice.name ? {
2709
+ type: "function",
2710
+ name: choice.name
2711
+ } : "auto";
2712
+ case "none": return "none";
2713
+ default: return "auto";
2748
2714
  }
2749
- if (hasToolRef(tr)) return tr;
2750
- return {
2751
- ...tr,
2752
- content: [...tr.content, ...textBlocks]
2753
- };
2754
2715
  };
2755
- const mergeContentWithAttachments = (tr, attachments) => {
2756
- if (typeof tr.content === "string") return {
2757
- ...tr,
2758
- content: [{
2759
- type: "text",
2760
- text: tr.content
2761
- }, ...attachments]
2762
- };
2716
+ const translateResponsesResultToAnthropic = (response) => {
2717
+ const contentBlocks = mapOutputToAnthropicContent(response.output);
2718
+ const usage = mapResponsesUsage(response);
2719
+ let anthropicContent = fallbackContentBlocks(response.output_text);
2720
+ if (contentBlocks.length > 0) anthropicContent = contentBlocks;
2721
+ const stopReason = mapResponsesStopReason(response);
2763
2722
  return {
2764
- ...tr,
2765
- content: [...tr.content, ...attachments]
2723
+ id: response.id,
2724
+ type: "message",
2725
+ role: "assistant",
2726
+ content: anthropicContent,
2727
+ model: response.model,
2728
+ stop_reason: stopReason,
2729
+ stop_sequence: null,
2730
+ usage
2766
2731
  };
2767
2732
  };
2768
- const isAttachmentBlock = (block) => {
2769
- return block.type === "image" || block.type === "document";
2770
- };
2771
- const getMergeableToolResultIndices = (toolResults) => {
2772
- return toolResults.flatMap((block, index) => block.is_error || hasToolRef(block) ? [] : [index]);
2773
- };
2774
- const mergeAttachmentsIntoToolResults = (toolResults, attachmentsByToolResultIndex) => {
2775
- if (attachmentsByToolResultIndex.size === 0) return toolResults;
2776
- return toolResults.map((block, index) => {
2777
- const matchedAttachments = attachmentsByToolResultIndex.get(index);
2778
- if (!matchedAttachments) return block;
2779
- const orderedAttachments = [...matchedAttachments].sort((left, right) => left.order - right.order).map(({ attachment }) => attachment);
2780
- return mergeContentWithAttachments(block, orderedAttachments);
2781
- });
2782
- };
2783
- const assignAttachmentsToToolResults = (target, attachments, options) => {
2784
- const { toolResultIndices } = options;
2785
- const fallbackToolResultIndices = options.fallbackToolResultIndices ?? toolResultIndices;
2786
- if (attachments.length === 0) return;
2787
- if (toolResultIndices.length > 0 && toolResultIndices.length === attachments.length) {
2788
- for (const [index, toolResultIndex] of toolResultIndices.entries()) {
2789
- const currentAttachments$1 = target.get(toolResultIndex);
2790
- if (currentAttachments$1) {
2791
- currentAttachments$1.push(attachments[index]);
2792
- continue;
2793
- }
2794
- target.set(toolResultIndex, [attachments[index]]);
2733
+ const mapOutputToAnthropicContent = (output) => {
2734
+ const contentBlocks = [];
2735
+ for (const item of output) switch (item.type) {
2736
+ case "reasoning": {
2737
+ const thinkingText = extractReasoningText(item);
2738
+ if (thinkingText.length > 0) contentBlocks.push({
2739
+ type: "thinking",
2740
+ thinking: thinkingText,
2741
+ signature: (item.encrypted_content ?? "") + "@" + item.id
2742
+ });
2743
+ break;
2744
+ }
2745
+ case "function_call": {
2746
+ const toolUseBlock = createToolUseContentBlock(item);
2747
+ if (toolUseBlock) contentBlocks.push(toolUseBlock);
2748
+ break;
2749
+ }
2750
+ case "message": {
2751
+ const combinedText = combineMessageTextContent(item.content);
2752
+ if (combinedText.length > 0) contentBlocks.push({
2753
+ type: "text",
2754
+ text: combinedText
2755
+ });
2756
+ break;
2757
+ }
2758
+ case "compaction": {
2759
+ const compactionBlock = createCompactionThinkingBlock(item);
2760
+ if (compactionBlock) contentBlocks.push(compactionBlock);
2761
+ break;
2762
+ }
2763
+ default: {
2764
+ const combinedText = combineMessageTextContent(item.content);
2765
+ if (combinedText.length > 0) contentBlocks.push({
2766
+ type: "text",
2767
+ text: combinedText
2768
+ });
2795
2769
  }
2796
- return;
2797
- }
2798
- const lastToolResultIndex = fallbackToolResultIndices.at(-1);
2799
- if (lastToolResultIndex === void 0) return;
2800
- const currentAttachments = target.get(lastToolResultIndex);
2801
- if (currentAttachments) {
2802
- currentAttachments.push(...attachments);
2803
- return;
2804
2770
  }
2805
- target.set(lastToolResultIndex, [...attachments]);
2806
- };
2807
- const startsWithPdfFileRead = (toolResult) => {
2808
- if (typeof toolResult.content === "string") return toolResult.content.startsWith(PDF_FILE_READ_PREFIX);
2809
- if (toolResult.content.some((block) => block.type === "document")) return false;
2810
- if (toolResult.content.length === 0) return false;
2811
- const firstBlock = toolResult.content[0];
2812
- if (firstBlock.type !== "text") return false;
2813
- return firstBlock.text.startsWith(PDF_FILE_READ_PREFIX);
2771
+ return contentBlocks;
2814
2772
  };
2815
- const collectMergeableUserContent = (content) => {
2816
- const toolResults = [];
2817
- const textBlocks = [];
2818
- const attachments = [];
2819
- for (const [order, block] of content.entries()) {
2820
- if (block.type === "tool_result") {
2821
- toolResults.push(block);
2773
+ const combineMessageTextContent = (content) => {
2774
+ if (!Array.isArray(content)) return "";
2775
+ let aggregated = "";
2776
+ for (const block of content) {
2777
+ if (isResponseOutputText(block)) {
2778
+ aggregated += block.text;
2822
2779
  continue;
2823
2780
  }
2824
- if (block.type === "text") {
2825
- textBlocks.push(block);
2781
+ if (isResponseOutputRefusal(block)) {
2782
+ aggregated += block.refusal;
2826
2783
  continue;
2827
2784
  }
2828
- if (isAttachmentBlock(block)) {
2829
- attachments.push({
2830
- attachment: block,
2831
- order
2832
- });
2785
+ if (typeof block.text === "string") {
2786
+ aggregated += block.text;
2787
+ continue;
2788
+ }
2789
+ if (typeof block.reasoning === "string") {
2790
+ aggregated += block.reasoning;
2833
2791
  continue;
2834
2792
  }
2835
- return null;
2836
- }
2837
- return {
2838
- toolResults,
2839
- textBlocks,
2840
- attachments
2841
- };
2842
- };
2843
- const mergeAttachmentsForToolResults = (toolResults, attachments) => {
2844
- if (attachments.length === 0) return toolResults;
2845
- const documentBlocks = attachments.filter(({ attachment }) => attachment.type === "document");
2846
- const mergeableToolResultIndices = getMergeableToolResultIndices(toolResults);
2847
- const pdfReadToolResultIndices = mergeableToolResultIndices.filter((index) => startsWithPdfFileRead(toolResults[index]));
2848
- const attachmentsByToolResultIndex = /* @__PURE__ */ new Map();
2849
- let remainingAttachments = attachments;
2850
- let countMatchToolResultIndices = mergeableToolResultIndices;
2851
- if (documentBlocks.length > 0 && pdfReadToolResultIndices.length > 0) {
2852
- const matchedDocumentCount = Math.min(pdfReadToolResultIndices.length, documentBlocks.length);
2853
- const matchedDocuments = documentBlocks.slice(0, matchedDocumentCount);
2854
- const matchedDocumentOrders = new Set(matchedDocuments.map(({ order }) => order));
2855
- const matchedPdfToolResultIndices = pdfReadToolResultIndices.slice(0, matchedDocumentCount);
2856
- const matchedPdfToolResultIndexSet = new Set(matchedPdfToolResultIndices);
2857
- assignAttachmentsToToolResults(attachmentsByToolResultIndex, matchedDocuments, { toolResultIndices: matchedPdfToolResultIndices });
2858
- countMatchToolResultIndices = mergeableToolResultIndices.filter((index) => !matchedPdfToolResultIndexSet.has(index));
2859
- remainingAttachments = attachments.filter(({ attachment, order }) => attachment.type !== "document" || !matchedDocumentOrders.has(order));
2860
2793
  }
2861
- assignAttachmentsToToolResults(attachmentsByToolResultIndex, remainingAttachments, {
2862
- toolResultIndices: countMatchToolResultIndices,
2863
- fallbackToolResultIndices: mergeableToolResultIndices
2864
- });
2865
- return mergeAttachmentsIntoToolResults(toolResults, attachmentsByToolResultIndex);
2794
+ return aggregated;
2866
2795
  };
2867
- const mergeUserMessageContent = (content) => {
2868
- const mergeableContent = collectMergeableUserContent(content);
2869
- if (!mergeableContent) return null;
2870
- const { toolResults, textBlocks, attachments } = mergeableContent;
2871
- if (toolResults.length === 0 || textBlocks.length === 0 && attachments.length === 0) return null;
2872
- const mergedToolResults = textBlocks.length === 0 ? toolResults : mergeToolResult(toolResults, textBlocks);
2873
- return mergeAttachmentsForToolResults(mergedToolResults, attachments);
2796
+ const extractReasoningText = (item) => {
2797
+ const segments = [];
2798
+ const collectFromBlocks = (blocks) => {
2799
+ if (!Array.isArray(blocks)) return;
2800
+ for (const block of blocks) if (typeof block.text === "string") {
2801
+ segments.push(block.text);
2802
+ continue;
2803
+ }
2804
+ };
2805
+ if (!item.summary || item.summary.length === 0) return THINKING_TEXT;
2806
+ collectFromBlocks(item.summary);
2807
+ return segments.join("").trim();
2874
2808
  };
2875
- const mergeToolResult = (toolResults, textBlocks) => {
2876
- if (toolResults.length === textBlocks.length) return toolResults.map((tr, i) => mergeContentWithText(tr, textBlocks[i]));
2877
- const lastIndex = toolResults.length - 1;
2878
- return toolResults.map((tr, i) => i === lastIndex ? mergeContentWithTexts(tr, textBlocks) : tr);
2809
+ const createToolUseContentBlock = (call) => {
2810
+ const toolId = call.call_id;
2811
+ if (!call.name || !toolId) return null;
2812
+ const input = parseFunctionCallArguments(call.arguments);
2813
+ return {
2814
+ type: "tool_use",
2815
+ id: toolId,
2816
+ name: call.name,
2817
+ input
2818
+ };
2879
2819
  };
2880
- const stripToolReferenceTurnBoundary = (anthropicPayload) => {
2881
- for (const msg of anthropicPayload.messages) {
2882
- if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
2883
- if (!msg.content.some((block) => block.type === "tool_result" && hasToolRef(block))) continue;
2884
- msg.content = msg.content.filter((block) => block.type !== "text" || block.text.trim() !== TOOL_REFERENCE_TURN_BOUNDARY);
2885
- }
2820
+ const createCompactionThinkingBlock = (item) => {
2821
+ if (!item.id || !item.encrypted_content) return null;
2822
+ return {
2823
+ type: "thinking",
2824
+ thinking: THINKING_TEXT,
2825
+ signature: encodeCompactionCarrierSignature({
2826
+ id: item.id,
2827
+ encrypted_content: item.encrypted_content
2828
+ })
2829
+ };
2886
2830
  };
2887
- const mergeToolResultForClaude = (anthropicPayload, options) => {
2888
- const lastMessageIndex = anthropicPayload.messages.length - 1;
2889
- for (const [index, msg] of anthropicPayload.messages.entries()) {
2890
- if (options?.skipLastMessage && index === lastMessageIndex) continue;
2891
- if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
2892
- const mergedContent = mergeUserMessageContent(msg.content);
2893
- if (mergedContent) msg.content = mergedContent;
2831
+ const parseFunctionCallArguments = (rawArguments) => {
2832
+ if (typeof rawArguments !== "string" || rawArguments.trim().length === 0) return {};
2833
+ try {
2834
+ const parsed = JSON.parse(rawArguments);
2835
+ if (Array.isArray(parsed)) return { arguments: parsed };
2836
+ if (parsed && typeof parsed === "object") return parsed;
2837
+ } catch (error) {
2838
+ consola.warn("Failed to parse function call arguments", {
2839
+ error,
2840
+ rawArguments
2841
+ });
2894
2842
  }
2843
+ return { raw_arguments: rawArguments };
2895
2844
  };
2896
- const sanitizeIdeTools = (payload) => {
2897
- if (!payload.tools || payload.tools.length === 0) return;
2898
- payload.tools = payload.tools.flatMap((tool) => {
2899
- if (tool.name === IDE_EXECUTE_CODE_TOOL && !tool.defer_loading) return [];
2900
- if (tool.name === IDE_GET_DIAGNOSTICS_TOOL) return [{
2901
- ...tool,
2902
- description: IDE_GET_DIAGNOSTICS_DESCRIPTION
2903
- }];
2904
- return [tool];
2905
- });
2906
- };
2907
- const hasToolRef = (block) => {
2908
- return Array.isArray(block.content) && block.content.some((c) => c.type === "tool_reference");
2845
+ const fallbackContentBlocks = (outputText) => {
2846
+ if (!outputText) return [];
2847
+ return [{
2848
+ type: "text",
2849
+ text: outputText
2850
+ }];
2909
2851
  };
2910
- const stripCacheControl = (payload) => {
2911
- if (Array.isArray(payload.system)) for (const block of payload.system) {
2912
- const systemBlock = block;
2913
- const cacheControl = systemBlock.cache_control;
2914
- if (cacheControl && typeof cacheControl === "object") {
2915
- const { scope,...rest } = cacheControl;
2916
- systemBlock.cache_control = rest;
2917
- }
2852
+ const mapResponsesStopReason = (response) => {
2853
+ const { status, incomplete_details: incompleteDetails } = response;
2854
+ if (status === "completed") {
2855
+ if (response.output.some((item) => item.type === "function_call")) return "tool_use";
2856
+ return "end_turn";
2918
2857
  }
2858
+ if (status === "incomplete") {
2859
+ if (incompleteDetails?.reason === "max_output_tokens") return "max_tokens";
2860
+ if (incompleteDetails?.reason === "content_filter") return "end_turn";
2861
+ }
2862
+ return null;
2919
2863
  };
2920
- const filterAssistantThinkingBlocks = (payload) => {
2921
- for (const msg of payload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
2922
- if (block.type !== "thinking") return true;
2923
- return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
2924
- });
2864
+ const mapResponsesUsage = (response) => {
2865
+ const inputTokens = response.usage?.input_tokens ?? 0;
2866
+ const outputTokens = response.usage?.output_tokens ?? 0;
2867
+ const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
2868
+ return {
2869
+ input_tokens: inputTokens - (inputCachedTokens ?? 0),
2870
+ output_tokens: outputTokens,
2871
+ ...response.usage?.input_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: response.usage.input_tokens_details.cached_tokens }
2872
+ };
2925
2873
  };
2926
- const prepareMessagesApiPayload = (payload, selectedModel) => {
2927
- stripCacheControl(payload);
2928
- filterAssistantThinkingBlocks(payload);
2929
- const hasThinking = Boolean(payload.thinking);
2930
- const toolChoice = payload.tool_choice;
2931
- const disableThink = toolChoice?.type === "any" || toolChoice?.type === "tool";
2932
- if (selectedModel?.capabilities.supports.adaptive_thinking && !disableThink) {
2933
- payload.thinking = { type: "adaptive" };
2934
- if (!hasThinking) payload.thinking.display = "summarized";
2935
- if (payload.model === "claude-opus-4.7") payload.thinking.display = "summarized";
2936
- let effort = getReasoningEffortForModel(payload.model);
2937
- if (effort === "none" || effort === "minimal") effort = "low";
2938
- const reasoningEffort = selectedModel.capabilities.supports.reasoning_effort;
2939
- if (reasoningEffort && !reasoningEffort.includes(effort)) effort = reasoningEffort.at(-1);
2940
- payload.output_config = { effort };
2874
+ const isRecord = (value) => typeof value === "object" && value !== null;
2875
+ const isResponseOutputText = (block) => isRecord(block) && "type" in block && block.type === "output_text";
2876
+ const isResponseOutputRefusal = (block) => isRecord(block) && "type" in block && block.type === "refusal";
2877
+ const convertToolResultContent = (content) => {
2878
+ if (typeof content === "string") return content;
2879
+ if (Array.isArray(content)) {
2880
+ const result = [];
2881
+ for (const block of content) switch (block.type) {
2882
+ case "text":
2883
+ result.push(createTextContent(block.text));
2884
+ break;
2885
+ case "image":
2886
+ result.push(createImageContent(block));
2887
+ break;
2888
+ case "document":
2889
+ result.push(createFileContent(block));
2890
+ break;
2891
+ case "tool_reference":
2892
+ result.push(createTextContent(`Tool ${block.tool_name} loaded`));
2893
+ break;
2894
+ default: break;
2895
+ }
2896
+ return result;
2941
2897
  }
2898
+ return "";
2942
2899
  };
2943
2900
 
2944
2901
  //#endregion
2945
- //#region src/routes/messages/stream-translation.ts
2946
- function isToolBlockOpen(state$1) {
2947
- if (!state$1.contentBlockOpen) return false;
2948
- return Object.values(state$1.toolCalls).some((tc) => tc.anthropicBlockIndex === state$1.contentBlockIndex);
2949
- }
2950
- function translateChunkToAnthropicEvents(chunk, state$1) {
2951
- const events$1 = [];
2952
- if (chunk.choices.length === 0) {
2953
- completePendingMessage(state$1, events$1, chunk);
2954
- return events$1;
2902
+ //#region src/routes/messages/responses-stream-translation.ts
2903
+ const MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE = 20;
2904
+ var FunctionCallArgumentsValidationError = class extends Error {
2905
+ constructor(message) {
2906
+ super(message);
2907
+ this.name = "FunctionCallArgumentsValidationError";
2955
2908
  }
2956
- const choice = chunk.choices[0];
2957
- const { delta } = choice;
2958
- handleMessageStart(state$1, events$1, chunk);
2959
- handleThinkingText(delta, state$1, events$1);
2960
- handleContent(delta, state$1, events$1);
2961
- handleToolCalls(delta, state$1, events$1);
2962
- handleFinish(choice, state$1, {
2963
- events: events$1,
2964
- chunk
2965
- });
2966
- return events$1;
2967
- }
2968
- function flushPendingAnthropicStreamEvents(state$1) {
2969
- const events$1 = [];
2970
- completePendingMessage(state$1, events$1);
2971
- return events$1;
2972
- }
2973
- function completePendingMessage(state$1, events$1, chunk) {
2974
- if (!state$1.pendingMessageDelta) return;
2975
- if (chunk?.usage) state$1.pendingMessageDelta.usage = getAnthropicUsageFromOpenAIChunk(chunk);
2976
- events$1.push(state$1.pendingMessageDelta, { type: "message_stop" });
2977
- state$1.pendingMessageDelta = void 0;
2978
- }
2979
- function handleFinish(choice, state$1, context) {
2980
- const { events: events$1, chunk } = context;
2981
- if (choice.finish_reason && choice.finish_reason.length > 0) {
2982
- if (state$1.contentBlockOpen) {
2983
- const toolBlockOpen = isToolBlockOpen(state$1);
2984
- context.events.push({
2985
- type: "content_block_stop",
2986
- index: state$1.contentBlockIndex
2987
- });
2988
- state$1.contentBlockOpen = false;
2989
- state$1.contentBlockIndex++;
2990
- if (!toolBlockOpen) handleReasoningOpaque(choice.delta, events$1, state$1);
2909
+ };
2910
+ const updateWhitespaceRunState = (previousCount, chunk) => {
2911
+ let count = previousCount;
2912
+ for (const char of chunk) {
2913
+ if (char === "\r" || char === "\n" || char === " ") {
2914
+ count += 1;
2915
+ if (count > MAX_CONSECUTIVE_FUNCTION_CALL_WHITESPACE) return {
2916
+ nextCount: count,
2917
+ exceeded: true
2918
+ };
2919
+ continue;
2991
2920
  }
2992
- state$1.pendingMessageDelta = {
2993
- type: "message_delta",
2994
- delta: {
2995
- stop_reason: mapOpenAIStopReasonToAnthropic(choice.finish_reason),
2996
- stop_sequence: null
2997
- },
2998
- usage: getAnthropicUsageFromOpenAIChunk(chunk)
2999
- };
3000
- if (chunk.usage) completePendingMessage(state$1, events$1, chunk);
2921
+ if (char !== " ") count = 0;
3001
2922
  }
3002
- }
3003
- function getAnthropicUsageFromOpenAIChunk(chunk) {
3004
- const { cachedTokens, cacheCreationTokens, inputTokens } = getOpenAIChunkUsageTokens(chunk);
3005
- return {
3006
- input_tokens: inputTokens,
3007
- output_tokens: chunk.usage?.completion_tokens ?? 0,
3008
- ...chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens !== void 0 && { cache_creation_input_tokens: cacheCreationTokens },
3009
- ...chunk.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: cachedTokens }
3010
- };
3011
- }
3012
- function getOpenAIChunkUsageTokens(chunk) {
3013
- const promptTokens = chunk.usage?.prompt_tokens ?? 0;
3014
- const cachedTokens = chunk.usage?.prompt_tokens_details?.cached_tokens ?? 0;
3015
- const cacheCreationTokens = chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens ?? 0;
3016
2923
  return {
3017
- cacheCreationTokens,
3018
- cachedTokens,
3019
- inputTokens: Math.max(0, promptTokens - cachedTokens - cacheCreationTokens)
2924
+ nextCount: count,
2925
+ exceeded: false
3020
2926
  };
3021
- }
3022
- function handleToolCalls(delta, state$1, events$1) {
3023
- if (delta.tool_calls && delta.tool_calls.length > 0) {
3024
- closeThinkingBlockIfOpen(state$1, events$1);
3025
- handleReasoningOpaqueInToolCalls(state$1, events$1, delta);
3026
- for (const toolCall of delta.tool_calls) {
3027
- if (toolCall.id && toolCall.function?.name) {
3028
- if (state$1.contentBlockOpen) {
3029
- events$1.push({
3030
- type: "content_block_stop",
3031
- index: state$1.contentBlockIndex
3032
- });
3033
- state$1.contentBlockIndex++;
3034
- state$1.contentBlockOpen = false;
3035
- }
3036
- const anthropicBlockIndex = state$1.contentBlockIndex;
3037
- state$1.toolCalls[toolCall.index] = {
3038
- id: toolCall.id,
3039
- name: toolCall.function.name,
3040
- anthropicBlockIndex
3041
- };
3042
- events$1.push({
3043
- type: "content_block_start",
3044
- index: anthropicBlockIndex,
3045
- content_block: {
3046
- type: "tool_use",
3047
- id: toolCall.id,
3048
- name: toolCall.function.name,
3049
- input: {}
3050
- }
3051
- });
3052
- state$1.contentBlockOpen = true;
2927
+ };
2928
+ const createResponsesStreamState = () => ({
2929
+ messageStartSent: false,
2930
+ messageCompleted: false,
2931
+ nextContentBlockIndex: 0,
2932
+ blockIndexByKey: /* @__PURE__ */ new Map(),
2933
+ openBlocks: /* @__PURE__ */ new Set(),
2934
+ blockHasDelta: /* @__PURE__ */ new Set(),
2935
+ functionCallStateByOutputIndex: /* @__PURE__ */ new Map()
2936
+ });
2937
+ const translateResponsesStreamEvent = (rawEvent, state$1) => {
2938
+ switch (rawEvent.type) {
2939
+ case "response.created": return handleResponseCreated(rawEvent, state$1);
2940
+ case "response.output_item.added": return handleOutputItemAdded$1(rawEvent, state$1);
2941
+ case "response.reasoning_summary_text.delta": return handleReasoningSummaryTextDelta(rawEvent, state$1);
2942
+ case "response.output_text.delta": return handleOutputTextDelta(rawEvent, state$1);
2943
+ case "response.reasoning_summary_text.done": return handleReasoningSummaryTextDone(rawEvent, state$1);
2944
+ case "response.output_text.done": return handleOutputTextDone(rawEvent, state$1);
2945
+ case "response.output_item.done": return handleOutputItemDone$1(rawEvent, state$1);
2946
+ case "response.function_call_arguments.delta": return handleFunctionCallArgumentsDelta(rawEvent, state$1);
2947
+ case "response.function_call_arguments.done": return handleFunctionCallArgumentsDone(rawEvent, state$1);
2948
+ case "response.completed":
2949
+ case "response.incomplete": return handleResponseCompleted(rawEvent, state$1);
2950
+ case "response.failed": return handleResponseFailed(rawEvent, state$1);
2951
+ case "error": return handleErrorEvent(rawEvent, state$1);
2952
+ default: return [];
2953
+ }
2954
+ };
2955
+ const handleResponseCreated = (rawEvent, state$1) => {
2956
+ return messageStart(state$1, rawEvent.response);
2957
+ };
2958
+ const handleOutputItemAdded$1 = (rawEvent, state$1) => {
2959
+ const events$1 = new Array();
2960
+ const functionCallDetails = extractFunctionCallDetails(rawEvent);
2961
+ if (!functionCallDetails) return events$1;
2962
+ const { outputIndex, toolCallId, name, initialArguments } = functionCallDetails;
2963
+ const blockIndex = openFunctionCallBlock(state$1, {
2964
+ outputIndex,
2965
+ toolCallId,
2966
+ name,
2967
+ events: events$1
2968
+ });
2969
+ if (initialArguments !== void 0 && initialArguments.length > 0) {
2970
+ events$1.push({
2971
+ type: "content_block_delta",
2972
+ index: blockIndex,
2973
+ delta: {
2974
+ type: "input_json_delta",
2975
+ partial_json: initialArguments
2976
+ }
2977
+ });
2978
+ state$1.blockHasDelta.add(blockIndex);
2979
+ }
2980
+ return events$1;
2981
+ };
2982
+ const handleOutputItemDone$1 = (rawEvent, state$1) => {
2983
+ const events$1 = new Array();
2984
+ const item = rawEvent.item;
2985
+ const itemType = item.type;
2986
+ const outputIndex = rawEvent.output_index;
2987
+ if (itemType === "compaction") {
2988
+ if (!item.id || !item.encrypted_content) return events$1;
2989
+ const blockIndex$1 = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
2990
+ if (!state$1.blockHasDelta.has(blockIndex$1)) events$1.push({
2991
+ type: "content_block_delta",
2992
+ index: blockIndex$1,
2993
+ delta: {
2994
+ type: "thinking_delta",
2995
+ thinking: THINKING_TEXT
3053
2996
  }
3054
- if (toolCall.function?.arguments) {
3055
- const toolCallInfo = state$1.toolCalls[toolCall.index];
3056
- if (toolCallInfo) events$1.push({
3057
- type: "content_block_delta",
3058
- index: toolCallInfo.anthropicBlockIndex,
3059
- delta: {
3060
- type: "input_json_delta",
3061
- partial_json: toolCall.function.arguments
3062
- }
3063
- });
2997
+ });
2998
+ events$1.push({
2999
+ type: "content_block_delta",
3000
+ index: blockIndex$1,
3001
+ delta: {
3002
+ type: "signature_delta",
3003
+ signature: encodeCompactionCarrierSignature({
3004
+ id: item.id,
3005
+ encrypted_content: item.encrypted_content
3006
+ })
3064
3007
  }
3065
- }
3008
+ });
3009
+ state$1.blockHasDelta.add(blockIndex$1);
3010
+ return events$1;
3066
3011
  }
3067
- }
3068
- function handleReasoningOpaqueInToolCalls(state$1, events$1, delta) {
3069
- if (state$1.contentBlockOpen && !isToolBlockOpen(state$1)) {
3012
+ if (itemType !== "reasoning") return events$1;
3013
+ const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
3014
+ const signature = (item.encrypted_content ?? "") + "@" + item.id;
3015
+ if (signature) {
3016
+ if (!item.summary || item.summary.length === 0) events$1.push({
3017
+ type: "content_block_delta",
3018
+ index: blockIndex,
3019
+ delta: {
3020
+ type: "thinking_delta",
3021
+ thinking: THINKING_TEXT
3022
+ }
3023
+ });
3070
3024
  events$1.push({
3071
- type: "content_block_stop",
3072
- index: state$1.contentBlockIndex
3025
+ type: "content_block_delta",
3026
+ index: blockIndex,
3027
+ delta: {
3028
+ type: "signature_delta",
3029
+ signature
3030
+ }
3073
3031
  });
3074
- state$1.contentBlockIndex++;
3075
- state$1.contentBlockOpen = false;
3032
+ state$1.blockHasDelta.add(blockIndex);
3076
3033
  }
3077
- handleReasoningOpaque(delta, events$1, state$1);
3078
- }
3079
- function handleContent(delta, state$1, events$1) {
3080
- if (delta.content && delta.content.length > 0) {
3081
- closeThinkingBlockIfOpen(state$1, events$1);
3082
- if (isToolBlockOpen(state$1)) {
3083
- events$1.push({
3084
- type: "content_block_stop",
3085
- index: state$1.contentBlockIndex
3086
- });
3087
- state$1.contentBlockIndex++;
3088
- state$1.contentBlockOpen = false;
3089
- }
3090
- if (!state$1.contentBlockOpen) {
3091
- events$1.push({
3092
- type: "content_block_start",
3093
- index: state$1.contentBlockIndex,
3094
- content_block: {
3095
- type: "text",
3096
- text: ""
3097
- }
3098
- });
3099
- state$1.contentBlockOpen = true;
3034
+ return events$1;
3035
+ };
3036
+ const handleFunctionCallArgumentsDelta = (rawEvent, state$1) => {
3037
+ const events$1 = new Array();
3038
+ const outputIndex = rawEvent.output_index;
3039
+ const deltaText = rawEvent.delta;
3040
+ if (!deltaText) return events$1;
3041
+ const blockIndex = openFunctionCallBlock(state$1, {
3042
+ outputIndex,
3043
+ events: events$1
3044
+ });
3045
+ const functionCallState = state$1.functionCallStateByOutputIndex.get(outputIndex);
3046
+ if (!functionCallState) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta without an open tool call block."), state$1, events$1);
3047
+ const { nextCount, exceeded } = updateWhitespaceRunState(functionCallState.consecutiveWhitespaceCount, deltaText);
3048
+ if (exceeded) return handleFunctionCallArgumentsValidationError(new FunctionCallArgumentsValidationError("Received function call arguments delta containing more than 20 consecutive whitespace characters."), state$1, events$1);
3049
+ functionCallState.consecutiveWhitespaceCount = nextCount;
3050
+ events$1.push({
3051
+ type: "content_block_delta",
3052
+ index: blockIndex,
3053
+ delta: {
3054
+ type: "input_json_delta",
3055
+ partial_json: deltaText
3100
3056
  }
3057
+ });
3058
+ state$1.blockHasDelta.add(blockIndex);
3059
+ return events$1;
3060
+ };
3061
+ const handleFunctionCallArgumentsDone = (rawEvent, state$1) => {
3062
+ const events$1 = new Array();
3063
+ const outputIndex = rawEvent.output_index;
3064
+ const blockIndex = openFunctionCallBlock(state$1, {
3065
+ outputIndex,
3066
+ events: events$1
3067
+ });
3068
+ const finalArguments = typeof rawEvent.arguments === "string" ? rawEvent.arguments : void 0;
3069
+ if (!state$1.blockHasDelta.has(blockIndex) && finalArguments) {
3101
3070
  events$1.push({
3102
3071
  type: "content_block_delta",
3103
- index: state$1.contentBlockIndex,
3072
+ index: blockIndex,
3104
3073
  delta: {
3105
- type: "text_delta",
3106
- text: delta.content
3074
+ type: "input_json_delta",
3075
+ partial_json: finalArguments
3076
+ }
3077
+ });
3078
+ state$1.blockHasDelta.add(blockIndex);
3079
+ }
3080
+ state$1.functionCallStateByOutputIndex.delete(outputIndex);
3081
+ return events$1;
3082
+ };
3083
+ const handleOutputTextDelta = (rawEvent, state$1) => {
3084
+ const events$1 = new Array();
3085
+ const outputIndex = rawEvent.output_index;
3086
+ const contentIndex = rawEvent.content_index;
3087
+ const deltaText = rawEvent.delta;
3088
+ if (!deltaText) return events$1;
3089
+ const blockIndex = openTextBlockIfNeeded(state$1, {
3090
+ outputIndex,
3091
+ contentIndex,
3092
+ events: events$1
3093
+ });
3094
+ events$1.push({
3095
+ type: "content_block_delta",
3096
+ index: blockIndex,
3097
+ delta: {
3098
+ type: "text_delta",
3099
+ text: deltaText
3100
+ }
3101
+ });
3102
+ state$1.blockHasDelta.add(blockIndex);
3103
+ return events$1;
3104
+ };
3105
+ const handleReasoningSummaryTextDelta = (rawEvent, state$1) => {
3106
+ const outputIndex = rawEvent.output_index;
3107
+ const deltaText = rawEvent.delta;
3108
+ const events$1 = new Array();
3109
+ const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
3110
+ events$1.push({
3111
+ type: "content_block_delta",
3112
+ index: blockIndex,
3113
+ delta: {
3114
+ type: "thinking_delta",
3115
+ thinking: deltaText
3116
+ }
3117
+ });
3118
+ state$1.blockHasDelta.add(blockIndex);
3119
+ return events$1;
3120
+ };
3121
+ const handleReasoningSummaryTextDone = (rawEvent, state$1) => {
3122
+ const outputIndex = rawEvent.output_index;
3123
+ const text = rawEvent.text;
3124
+ const events$1 = new Array();
3125
+ const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
3126
+ if (text && !state$1.blockHasDelta.has(blockIndex)) events$1.push({
3127
+ type: "content_block_delta",
3128
+ index: blockIndex,
3129
+ delta: {
3130
+ type: "thinking_delta",
3131
+ thinking: text
3132
+ }
3133
+ });
3134
+ return events$1;
3135
+ };
3136
+ const handleOutputTextDone = (rawEvent, state$1) => {
3137
+ const events$1 = new Array();
3138
+ const outputIndex = rawEvent.output_index;
3139
+ const contentIndex = rawEvent.content_index;
3140
+ const text = rawEvent.text;
3141
+ const blockIndex = openTextBlockIfNeeded(state$1, {
3142
+ outputIndex,
3143
+ contentIndex,
3144
+ events: events$1
3145
+ });
3146
+ if (text && !state$1.blockHasDelta.has(blockIndex)) events$1.push({
3147
+ type: "content_block_delta",
3148
+ index: blockIndex,
3149
+ delta: {
3150
+ type: "text_delta",
3151
+ text
3152
+ }
3153
+ });
3154
+ return events$1;
3155
+ };
3156
+ const handleResponseCompleted = (rawEvent, state$1) => {
3157
+ const response = rawEvent.response;
3158
+ const events$1 = new Array();
3159
+ closeAllOpenBlocks(state$1, events$1);
3160
+ const anthropic = translateResponsesResultToAnthropic(response);
3161
+ events$1.push({
3162
+ type: "message_delta",
3163
+ delta: {
3164
+ stop_reason: anthropic.stop_reason,
3165
+ stop_sequence: anthropic.stop_sequence
3166
+ },
3167
+ usage: anthropic.usage
3168
+ }, { type: "message_stop" });
3169
+ state$1.messageCompleted = true;
3170
+ return events$1;
3171
+ };
3172
+ const handleResponseFailed = (rawEvent, state$1) => {
3173
+ const response = rawEvent.response;
3174
+ const events$1 = new Array();
3175
+ closeAllOpenBlocks(state$1, events$1);
3176
+ const message = response.error?.message ?? "The response failed due to an unknown error.";
3177
+ events$1.push(buildErrorEvent(message));
3178
+ state$1.messageCompleted = true;
3179
+ return events$1;
3180
+ };
3181
+ const handleErrorEvent = (rawEvent, state$1) => {
3182
+ const message = typeof rawEvent.message === "string" ? rawEvent.message : "An unexpected error occurred during streaming.";
3183
+ state$1.messageCompleted = true;
3184
+ return [buildErrorEvent(message)];
3185
+ };
3186
+ const handleFunctionCallArgumentsValidationError = (error, state$1, events$1 = []) => {
3187
+ const reason = error.message;
3188
+ closeAllOpenBlocks(state$1, events$1);
3189
+ state$1.messageCompleted = true;
3190
+ events$1.push(buildErrorEvent(reason));
3191
+ return events$1;
3192
+ };
3193
+ const messageStart = (state$1, response) => {
3194
+ state$1.messageStartSent = true;
3195
+ const inputCachedTokens = response.usage?.input_tokens_details?.cached_tokens;
3196
+ const inputTokens = (response.usage?.input_tokens ?? 0) - (inputCachedTokens ?? 0);
3197
+ return [{
3198
+ type: "message_start",
3199
+ message: {
3200
+ id: response.id,
3201
+ type: "message",
3202
+ role: "assistant",
3203
+ content: [],
3204
+ model: response.model,
3205
+ stop_reason: null,
3206
+ stop_sequence: null,
3207
+ usage: {
3208
+ input_tokens: inputTokens,
3209
+ output_tokens: 0,
3210
+ cache_read_input_tokens: inputCachedTokens ?? 0
3107
3211
  }
3108
- });
3212
+ }
3213
+ }];
3214
+ };
3215
+ const openTextBlockIfNeeded = (state$1, params) => {
3216
+ const { outputIndex, contentIndex, events: events$1 } = params;
3217
+ const key = getBlockKey(outputIndex, contentIndex);
3218
+ let blockIndex = state$1.blockIndexByKey.get(key);
3219
+ if (blockIndex === void 0) {
3220
+ blockIndex = state$1.nextContentBlockIndex;
3221
+ state$1.nextContentBlockIndex += 1;
3222
+ state$1.blockIndexByKey.set(key, blockIndex);
3109
3223
  }
3110
- if (delta.content === "" && delta.reasoning_opaque && delta.reasoning_opaque.length > 0 && state$1.thinkingBlockOpen) {
3224
+ if (!state$1.openBlocks.has(blockIndex)) {
3225
+ closeOpenBlocks(state$1, events$1);
3111
3226
  events$1.push({
3112
- type: "content_block_delta",
3113
- index: state$1.contentBlockIndex,
3114
- delta: {
3115
- type: "signature_delta",
3116
- signature: delta.reasoning_opaque
3227
+ type: "content_block_start",
3228
+ index: blockIndex,
3229
+ content_block: {
3230
+ type: "text",
3231
+ text: ""
3117
3232
  }
3118
- }, {
3119
- type: "content_block_stop",
3120
- index: state$1.contentBlockIndex
3121
3233
  });
3122
- state$1.contentBlockIndex++;
3123
- state$1.thinkingBlockOpen = false;
3234
+ state$1.openBlocks.add(blockIndex);
3124
3235
  }
3125
- }
3126
- function handleMessageStart(state$1, events$1, chunk) {
3127
- if (!state$1.messageStartSent) {
3128
- const { cachedTokens, cacheCreationTokens, inputTokens } = getOpenAIChunkUsageTokens(chunk);
3129
- events$1.push({
3130
- type: "message_start",
3131
- message: {
3132
- id: chunk.id,
3133
- type: "message",
3134
- role: "assistant",
3135
- content: [],
3136
- model: chunk.model,
3137
- stop_reason: null,
3138
- stop_sequence: null,
3139
- usage: {
3140
- input_tokens: inputTokens,
3141
- output_tokens: 0,
3142
- ...chunk.usage?.prompt_tokens_details?.cache_creation_input_tokens !== void 0 && { cache_creation_input_tokens: cacheCreationTokens },
3143
- ...chunk.usage?.prompt_tokens_details?.cached_tokens !== void 0 && { cache_read_input_tokens: cachedTokens }
3144
- }
3145
- }
3146
- });
3147
- state$1.messageStartSent = true;
3236
+ return blockIndex;
3237
+ };
3238
+ const openThinkingBlockIfNeeded = (state$1, outputIndex, events$1) => {
3239
+ const key = getBlockKey(outputIndex, 0);
3240
+ let blockIndex = state$1.blockIndexByKey.get(key);
3241
+ if (blockIndex === void 0) {
3242
+ blockIndex = state$1.nextContentBlockIndex;
3243
+ state$1.nextContentBlockIndex += 1;
3244
+ state$1.blockIndexByKey.set(key, blockIndex);
3148
3245
  }
3149
- }
3150
- function handleReasoningOpaque(delta, events$1, state$1) {
3151
- if (delta.reasoning_opaque && delta.reasoning_opaque.length > 0) {
3246
+ if (!state$1.openBlocks.has(blockIndex)) {
3247
+ closeOpenBlocks(state$1, events$1);
3152
3248
  events$1.push({
3153
3249
  type: "content_block_start",
3154
- index: state$1.contentBlockIndex,
3250
+ index: blockIndex,
3155
3251
  content_block: {
3156
3252
  type: "thinking",
3157
3253
  thinking: ""
3158
3254
  }
3159
- }, {
3160
- type: "content_block_delta",
3161
- index: state$1.contentBlockIndex,
3162
- delta: {
3163
- type: "thinking_delta",
3164
- thinking: THINKING_TEXT
3165
- }
3166
- }, {
3167
- type: "content_block_delta",
3168
- index: state$1.contentBlockIndex,
3169
- delta: {
3170
- type: "signature_delta",
3171
- signature: delta.reasoning_opaque
3172
- }
3173
- }, {
3174
- type: "content_block_stop",
3175
- index: state$1.contentBlockIndex
3176
3255
  });
3177
- state$1.contentBlockIndex++;
3256
+ state$1.openBlocks.add(blockIndex);
3178
3257
  }
3179
- }
3180
- function handleThinkingText(delta, state$1, events$1) {
3181
- const reasoningText = delta.reasoning_text ?? delta.reasoning_content;
3182
- if (reasoningText && reasoningText.length > 0) {
3183
- if (state$1.contentBlockOpen) {
3184
- delta.content = reasoningText;
3185
- delta.reasoning_text = void 0;
3186
- delta.reasoning_content = void 0;
3187
- return;
3188
- }
3189
- if (!state$1.thinkingBlockOpen) {
3190
- events$1.push({
3191
- type: "content_block_start",
3192
- index: state$1.contentBlockIndex,
3193
- content_block: {
3194
- type: "thinking",
3195
- thinking: ""
3196
- }
3197
- });
3198
- state$1.thinkingBlockOpen = true;
3199
- }
3200
- events$1.push({
3201
- type: "content_block_delta",
3202
- index: state$1.contentBlockIndex,
3203
- delta: {
3204
- type: "thinking_delta",
3205
- thinking: reasoningText
3206
- }
3207
- });
3258
+ return blockIndex;
3259
+ };
3260
+ const closeBlockIfOpen = (state$1, blockIndex, events$1) => {
3261
+ if (!state$1.openBlocks.has(blockIndex)) return;
3262
+ events$1.push({
3263
+ type: "content_block_stop",
3264
+ index: blockIndex
3265
+ });
3266
+ state$1.openBlocks.delete(blockIndex);
3267
+ state$1.blockHasDelta.delete(blockIndex);
3268
+ };
3269
+ const closeOpenBlocks = (state$1, events$1) => {
3270
+ for (const blockIndex of state$1.openBlocks) closeBlockIfOpen(state$1, blockIndex, events$1);
3271
+ };
3272
+ const closeAllOpenBlocks = (state$1, events$1) => {
3273
+ closeOpenBlocks(state$1, events$1);
3274
+ state$1.functionCallStateByOutputIndex.clear();
3275
+ };
3276
+ const buildErrorEvent = (message) => ({
3277
+ type: "error",
3278
+ error: {
3279
+ type: "api_error",
3280
+ message
3208
3281
  }
3209
- }
3210
- function closeThinkingBlockIfOpen(state$1, events$1) {
3211
- if (state$1.thinkingBlockOpen) {
3282
+ });
3283
+ const getBlockKey = (outputIndex, contentIndex) => `${outputIndex}:${contentIndex}`;
3284
+ const openFunctionCallBlock = (state$1, params) => {
3285
+ const { outputIndex, toolCallId, name, events: events$1 } = params;
3286
+ let functionCallState = state$1.functionCallStateByOutputIndex.get(outputIndex);
3287
+ if (!functionCallState) {
3288
+ const blockIndex$1 = state$1.nextContentBlockIndex;
3289
+ state$1.nextContentBlockIndex += 1;
3290
+ const resolvedToolCallId = toolCallId ?? `tool_call_${blockIndex$1}`;
3291
+ functionCallState = {
3292
+ blockIndex: blockIndex$1,
3293
+ toolCallId: resolvedToolCallId,
3294
+ name: name ?? "function",
3295
+ consecutiveWhitespaceCount: 0
3296
+ };
3297
+ state$1.functionCallStateByOutputIndex.set(outputIndex, functionCallState);
3298
+ }
3299
+ const { blockIndex } = functionCallState;
3300
+ if (!state$1.openBlocks.has(blockIndex)) {
3301
+ closeOpenBlocks(state$1, events$1);
3212
3302
  events$1.push({
3213
- type: "content_block_delta",
3214
- index: state$1.contentBlockIndex,
3215
- delta: {
3216
- type: "signature_delta",
3217
- signature: ""
3303
+ type: "content_block_start",
3304
+ index: blockIndex,
3305
+ content_block: {
3306
+ type: "tool_use",
3307
+ id: functionCallState.toolCallId,
3308
+ name: functionCallState.name,
3309
+ input: {}
3218
3310
  }
3219
- }, {
3220
- type: "content_block_stop",
3221
- index: state$1.contentBlockIndex
3222
3311
  });
3223
- state$1.contentBlockIndex++;
3224
- state$1.thinkingBlockOpen = false;
3312
+ state$1.openBlocks.add(blockIndex);
3225
3313
  }
3226
- }
3314
+ return blockIndex;
3315
+ };
3316
+ const extractFunctionCallDetails = (rawEvent) => {
3317
+ const item = rawEvent.item;
3318
+ if (item.type !== "function_call") return;
3319
+ const outputIndex = rawEvent.output_index;
3320
+ const toolCallId = item.call_id;
3321
+ const name = item.name;
3322
+ const initialArguments = item.arguments;
3323
+ return {
3324
+ outputIndex,
3325
+ toolCallId,
3326
+ name,
3327
+ initialArguments
3328
+ };
3329
+ };
3330
+
3331
+ //#endregion
3332
+ //#region src/routes/responses/utils.ts
3333
+ const getResponsesRequestOptions = (payload) => {
3334
+ const vision = hasVisionInput(payload);
3335
+ const initiator = hasAgentInitiator(payload) ? "agent" : "user";
3336
+ return {
3337
+ vision,
3338
+ initiator
3339
+ };
3340
+ };
3341
+ const hasAgentInitiator = (payload) => {
3342
+ const lastItem = getPayloadItems(payload).at(-1);
3343
+ if (!lastItem) return false;
3344
+ if (!("role" in lastItem) || !lastItem.role) return true;
3345
+ return (typeof lastItem.role === "string" ? lastItem.role.toLowerCase() : "") === "assistant";
3346
+ };
3347
+ const hasVisionInput = (payload) => {
3348
+ return getPayloadItems(payload).some((item) => containsVisionContent(item));
3349
+ };
3350
+ const resolveResponsesCompactThreshold = (maxPromptTokens) => {
3351
+ if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
3352
+ return 5e4;
3353
+ };
3354
+ const createCompactionContextManagement = (compactThreshold) => [{
3355
+ type: "compaction",
3356
+ compact_threshold: compactThreshold
3357
+ }];
3358
+ const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
3359
+ if (payload.context_management !== void 0) return;
3360
+ if (!isResponsesApiContextManagementModel(payload.model)) return;
3361
+ payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
3362
+ };
3363
+ const compactInputByLatestCompaction = (payload) => {
3364
+ if (!Array.isArray(payload.input) || payload.input.length === 0) return;
3365
+ const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
3366
+ if (latestCompactionMessageIndex === void 0) return;
3367
+ payload.input = payload.input.slice(latestCompactionMessageIndex);
3368
+ };
3369
+ const getLatestCompactionMessageIndex = (input) => {
3370
+ for (let index = input.length - 1; index >= 0; index -= 1) if (isCompactionInputItem(input[index])) return index;
3371
+ };
3372
+ const isCompactionInputItem = (value) => {
3373
+ return "type" in value && typeof value.type === "string" && value.type === "compaction";
3374
+ };
3375
+ const getPayloadItems = (payload) => {
3376
+ const result = [];
3377
+ const { input } = payload;
3378
+ if (Array.isArray(input)) result.push(...input);
3379
+ return result;
3380
+ };
3381
+ const containsVisionContent = (value) => {
3382
+ if (!value) return false;
3383
+ if (Array.isArray(value)) return value.some((entry) => containsVisionContent(entry));
3384
+ if (typeof value !== "object") return false;
3385
+ const record = value;
3386
+ if ((typeof record.type === "string" ? record.type.toLowerCase() : void 0) === "input_image") return true;
3387
+ if (Array.isArray(record.content)) return record.content.some((entry) => containsVisionContent(entry));
3388
+ return false;
3389
+ };
3227
3390
 
3228
3391
  //#endregion
3229
- //#region src/routes/messages/api-flows.ts
3230
- const COPILOT_CONTEXT_CACHE_SYSTEM_MARKER_LIMIT = 2;
3231
- const COPILOT_CONTEXT_CACHE_NON_SYSTEM_MARKER_LIMIT = 2;
3232
- const COPILOT_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
3233
- const handleWithChatCompletions = async (c, anthropicPayload, options) => {
3234
- const { logger: logger$7, subagentMarker, requestId, sessionId, compactType } = options;
3235
- const openAIPayload = translateToOpenAI(anthropicPayload);
3236
- prepareCopilotChatCompletionsPayload(openAIPayload);
3237
- const recordUsage = createCopilotUsageRecorder({
3238
- endpoint: "chat_completions",
3239
- fallbackSessionId: sessionId,
3240
- model: openAIPayload.model,
3241
- payload: anthropicPayload
3242
- });
3243
- debugJson(logger$7, "Translated OpenAI request payload:", openAIPayload);
3244
- const response = await createChatCompletions(openAIPayload, {
3245
- subagentMarker,
3246
- requestId,
3247
- sessionId,
3248
- compactType
3249
- });
3250
- if (isNonStreaming(response)) {
3251
- debugJson(logger$7, "Non-streaming response from Copilot:", response);
3252
- recordUsage(normalizeOpenAIUsage(response.usage));
3253
- const anthropicResponse = translateToAnthropic(response);
3254
- debugJson(logger$7, "Translated Anthropic response:", anthropicResponse);
3255
- return c.json(anthropicResponse);
3392
+ //#region src/services/copilot/create-messages.ts
3393
+ const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
3394
+ const allowedAnthropicBetas = new Set([
3395
+ INTERLEAVED_THINKING_BETA,
3396
+ "context-management-2025-06-27",
3397
+ "advanced-tool-use-2025-11-20"
3398
+ ]);
3399
+ const buildAnthropicBetaHeader = (anthropicBetaHeader, thinking, _model) => {
3400
+ const isAdaptiveThinking = thinking?.type === "adaptive";
3401
+ if (anthropicBetaHeader) {
3402
+ const uniqueFilteredBetas = [...anthropicBetaHeader.split(",").map((item) => item.trim()).filter((item) => item.length > 0).filter((item) => allowedAnthropicBetas.has(item))];
3403
+ if (uniqueFilteredBetas.length > 0) return uniqueFilteredBetas.join(",");
3404
+ return;
3256
3405
  }
3257
- logger$7.debug("Streaming response from Copilot");
3258
- return streamSSE(c, async (stream) => {
3259
- let usage = {};
3260
- const streamState = {
3261
- messageStartSent: false,
3262
- contentBlockIndex: 0,
3263
- contentBlockOpen: false,
3264
- toolCalls: {},
3265
- thinkingBlockOpen: false
3266
- };
3267
- for await (const rawEvent of response) {
3268
- debugJson(logger$7, "Copilot raw stream event:", rawEvent);
3269
- if (rawEvent.data === "[DONE]") break;
3270
- if (!rawEvent.data) continue;
3271
- const chunk = JSON.parse(rawEvent.data);
3272
- if (chunk.usage) usage = normalizeOpenAIUsage(chunk.usage);
3273
- const events$1 = translateChunkToAnthropicEvents(chunk, streamState);
3274
- for (const event of events$1) {
3275
- const eventData = JSON.stringify(event);
3276
- debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
3277
- await stream.writeSSE({
3278
- event: event.type,
3279
- data: eventData
3280
- });
3281
- }
3282
- }
3283
- for (const event of flushPendingAnthropicStreamEvents(streamState)) {
3284
- const eventData = JSON.stringify(event);
3285
- debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
3286
- await stream.writeSSE({
3287
- event: event.type,
3288
- data: eventData
3289
- });
3290
- }
3291
- recordUsage(usage);
3292
- });
3406
+ if (thinking?.budget_tokens && !isAdaptiveThinking) return INTERLEAVED_THINKING_BETA;
3293
3407
  };
3294
- const handleWithResponsesApi = async (c, anthropicPayload, options) => {
3295
- const { logger: logger$7, selectedModel,...requestOptions } = options;
3296
- const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload);
3297
- const recordUsage = createCopilotUsageRecorder({
3298
- endpoint: "responses",
3299
- fallbackSessionId: requestOptions.sessionId,
3300
- model: responsesPayload.model,
3301
- payload: anthropicPayload
3408
+ const createMessages = async (payload, anthropicBetaHeader, options) => {
3409
+ if (!state.copilotToken) throw new Error("Copilot token not found");
3410
+ const enableVision = payload.messages.some((message) => {
3411
+ if (!Array.isArray(message.content)) return false;
3412
+ return message.content.some((block) => block.type === "image" || block.type === "tool_result" && Array.isArray(block.content) && block.content.some((inner) => inner.type === "image"));
3302
3413
  });
3303
- applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
3304
- compactInputByLatestCompaction(responsesPayload);
3305
- debugJson(logger$7, "Translated Responses payload:", responsesPayload);
3306
- const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
3307
- const response = await createResponses(responsesPayload, {
3308
- vision,
3309
- initiator,
3310
- ...requestOptions
3414
+ let isInitiateRequest = false;
3415
+ const lastMessage = payload.messages.at(-1);
3416
+ if (lastMessage?.role === "user") isInitiateRequest = Array.isArray(lastMessage.content) ? lastMessage.content.some((block) => block.type !== "tool_result") : true;
3417
+ const headers = {
3418
+ ...copilotHeaders(state, options.requestId, enableVision),
3419
+ "x-initiator": isInitiateRequest ? "user" : "agent"
3420
+ };
3421
+ prepareInteractionHeaders(options.sessionId, Boolean(options.subagentMarker), headers);
3422
+ prepareForCompact(headers, options.compactType);
3423
+ const { safetyIdentifier, sessionId } = parseUserIdMetadata(payload.metadata?.user_id);
3424
+ if (safetyIdentifier && sessionId) prepareMessageProxyHeaders(headers);
3425
+ const anthropicBeta = buildAnthropicBetaHeader(anthropicBetaHeader, payload.thinking, payload.model);
3426
+ if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
3427
+ consola.log(`<-- model: ${payload.model}`);
3428
+ const response = await fetch(`${copilotBaseUrl(state)}/v1/messages`, {
3429
+ method: "POST",
3430
+ headers,
3431
+ body: JSON.stringify(payload)
3311
3432
  });
3312
- if (responsesPayload.stream && isAsyncIterable$1(response)) {
3313
- logger$7.debug("Streaming response from Copilot (Responses API)");
3314
- return streamSSE(c, async (stream) => {
3315
- const streamState = createResponsesStreamState();
3316
- let usage = {};
3317
- for await (const chunk of response) {
3318
- if (chunk.event === "ping") {
3319
- await stream.writeSSE({
3320
- event: "ping",
3321
- data: "{\"type\":\"ping\"}"
3322
- });
3323
- continue;
3324
- }
3325
- const data = chunk.data;
3326
- if (!data) continue;
3327
- debugLazy(logger$7, () => ["Responses raw stream event:", data]);
3328
- const responseEvent = JSON.parse(data);
3329
- if (responseEvent.type === "response.completed" || responseEvent.type === "response.failed" || responseEvent.type === "response.incomplete") usage = normalizeResponsesUsage(responseEvent.response.usage);
3330
- const events$1 = translateResponsesStreamEvent(responseEvent, streamState);
3331
- for (const event of events$1) {
3332
- const eventData = JSON.stringify(event);
3333
- debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
3334
- await stream.writeSSE({
3335
- event: event.type,
3336
- data: eventData
3337
- });
3338
- }
3339
- if (streamState.messageCompleted) {
3340
- logger$7.debug("Message completed, ending stream");
3341
- break;
3342
- }
3343
- }
3344
- if (!streamState.messageCompleted) {
3345
- logger$7.warn("Responses stream ended without completion; sending error event");
3346
- const errorEvent = buildErrorEvent("Responses stream ended without completion");
3347
- await stream.writeSSE({
3348
- event: errorEvent.type,
3349
- data: JSON.stringify(errorEvent)
3350
- });
3351
- }
3352
- recordUsage(usage);
3353
- });
3433
+ logCopilotRateLimits(response.headers);
3434
+ if (!response.ok) {
3435
+ consola.error("Failed to create messages", response);
3436
+ throw new HTTPError("Failed to create messages", response);
3354
3437
  }
3355
- debugJsonTail(logger$7, "Non-streaming Responses result:", {
3356
- value: response,
3357
- tailLength: 400
3358
- });
3359
- const anthropicResponse = translateResponsesResultToAnthropic(response);
3360
- recordUsage(normalizeResponsesUsage(response.usage));
3361
- debugJson(logger$7, "Translated Anthropic response:", anthropicResponse);
3362
- return c.json(anthropicResponse);
3438
+ if (payload.stream) return events(response);
3439
+ return await response.json();
3363
3440
  };
3364
- const handleWithMessagesApi = async (c, anthropicPayload, options) => {
3365
- const { logger: logger$7, anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId, compactType } = options;
3366
- prepareMessagesApiPayload(anthropicPayload, selectedModel);
3367
- const recordUsage = createCopilotUsageRecorder({
3368
- endpoint: "messages",
3369
- fallbackSessionId: sessionId,
3370
- model: anthropicPayload.model,
3371
- payload: anthropicPayload
3372
- });
3373
- debugJson(logger$7, "Translated Messages payload:", anthropicPayload);
3374
- const response = await createMessages(anthropicPayload, anthropicBetaHeader, {
3375
- subagentMarker,
3376
- requestId,
3377
- sessionId,
3378
- compactType
3379
- });
3380
- if (isAsyncIterable$1(response)) {
3381
- logger$7.debug("Streaming response from Copilot (Messages API)");
3382
- return streamSSE(c, async (stream) => {
3383
- let usage = {};
3384
- for await (const event of response) {
3385
- const eventName = event.event;
3386
- const data = event.data ?? "";
3387
- if (data === "[DONE]") break;
3388
- if (!data) continue;
3389
- debugLazy(logger$7, () => ["Messages raw stream event:", data]);
3390
- const parsedEvent = parseAnthropicStreamEvent(data);
3391
- if (parsedEvent?.type === "message_start") usage = mergeAnthropicUsage(usage, normalizeAnthropicUsage(parsedEvent.message.usage));
3392
- else if (parsedEvent?.type === "message_delta") usage = mergeAnthropicUsage(usage, normalizeAnthropicUsage(parsedEvent.usage));
3393
- await stream.writeSSE({
3394
- event: eventName,
3395
- data
3396
- });
3397
- }
3398
- recordUsage(usage);
3399
- });
3400
- }
3401
- debugJsonTail(logger$7, "Non-streaming Messages result:", {
3402
- value: response,
3403
- tailLength: 400
3404
- });
3405
- recordUsage(normalizeAnthropicUsage(response.usage));
3406
- return c.json(response);
3441
+
3442
+ //#endregion
3443
+ //#region src/routes/messages/preprocess.ts
3444
+ const TOOL_REFERENCE_TURN_BOUNDARY = "Tool loaded.";
3445
+ const IDE_EXECUTE_CODE_TOOL = "mcp__ide__executeCode";
3446
+ const IDE_GET_DIAGNOSTICS_TOOL = "mcp__ide__getDiagnostics";
3447
+ const IDE_GET_DIAGNOSTICS_DESCRIPTION = "Get language diagnostics from VS Code. Returns errors, warnings, information, and hints for files in the workspace.";
3448
+ const PDF_FILE_READ_PREFIX = "PDF file read:";
3449
+ const getCompactCandidateText = (message) => {
3450
+ if (message.role !== "user") return "";
3451
+ if (typeof message.content === "string") return message.content;
3452
+ return message.content.filter((block) => block.type === "text").map((block) => block.text.startsWith("<system-reminder>") ? "" : block.text).filter((text) => text.length > 0).join("\n\n");
3407
3453
  };
3408
- const prepareCopilotChatCompletionsPayload = (payload) => {
3409
- applyCopilotContextCache(payload);
3454
+ const isCompactMessage = (lastMessage) => {
3455
+ const text = getCompactCandidateText(lastMessage);
3456
+ if (!text) return false;
3457
+ return text.includes(compactTextOnlyGuard) && text.includes(compactSummaryPromptStart) && compactMessageSections.some((section) => text.includes(section));
3458
+ };
3459
+ const isCompactAutoContinueMessage = (lastMessage) => {
3460
+ const text = getCompactCandidateText(lastMessage);
3461
+ return Boolean(text) && compactAutoContinuePromptStarts.some((promptStart) => text.startsWith(promptStart));
3462
+ };
3463
+ const getCompactType = (anthropicPayload) => {
3464
+ const lastMessage = anthropicPayload.messages.at(-1);
3465
+ if (lastMessage && isCompactMessage(lastMessage)) return COMPACT_REQUEST;
3466
+ if (lastMessage && isCompactAutoContinueMessage(lastMessage)) return COMPACT_AUTO_CONTINUE;
3467
+ const system = anthropicPayload.system;
3468
+ if (typeof system === "string") return compactSystemPromptStarts.some((promptStart) => system.startsWith(promptStart)) ? COMPACT_REQUEST : 0;
3469
+ if (!Array.isArray(system)) return 0;
3470
+ if (system.some((msg) => typeof msg.text === "string" && compactSystemPromptStarts.some((promptStart) => msg.text.startsWith(promptStart)))) return COMPACT_REQUEST;
3471
+ return 0;
3472
+ };
3473
+ const mergeContentWithText = (tr, textBlock) => {
3474
+ if (typeof tr.content === "string") return {
3475
+ ...tr,
3476
+ content: `${tr.content}\n\n${textBlock.text}`
3477
+ };
3478
+ if (hasToolRef(tr)) return tr;
3479
+ return {
3480
+ ...tr,
3481
+ content: [...tr.content, textBlock]
3482
+ };
3410
3483
  };
3411
- const applyCopilotContextCache = (payload) => {
3412
- const messageIndexes = selectCopilotContextCacheMessageIndexes(payload.messages);
3413
- for (const messageIndex of messageIndexes) {
3414
- const message = payload.messages[messageIndex];
3415
- message.copilot_cache_control = { ...COPILOT_CONTEXT_CACHE_CONTROL };
3484
+ const mergeContentWithTexts = (tr, textBlocks) => {
3485
+ if (typeof tr.content === "string") {
3486
+ const appendedTexts = textBlocks.map((tb) => tb.text).join("\n\n");
3487
+ return {
3488
+ ...tr,
3489
+ content: `${tr.content}\n\n${appendedTexts}`
3490
+ };
3416
3491
  }
3492
+ if (hasToolRef(tr)) return tr;
3493
+ return {
3494
+ ...tr,
3495
+ content: [...tr.content, ...textBlocks]
3496
+ };
3417
3497
  };
3418
- const selectCopilotContextCacheMessageIndexes = (messages) => {
3419
- const systemIndexes = messages.flatMap((message, index) => message.role === "system" && isCopilotContextCacheEligible(message) ? [index] : []).slice(0, COPILOT_CONTEXT_CACHE_SYSTEM_MARKER_LIMIT);
3420
- const reverseNonSystemIndexes = messages.flatMap((message, index) => message.role !== "system" && isCopilotContextCacheEligible(message) ? [index] : []).reverse().slice(0, COPILOT_CONTEXT_CACHE_NON_SYSTEM_MARKER_LIMIT);
3421
- return uniqueIndexes$1([...systemIndexes, ...reverseNonSystemIndexes]).sort((a, b) => a - b);
3498
+ const mergeContentWithAttachments = (tr, attachments) => {
3499
+ if (typeof tr.content === "string") return {
3500
+ ...tr,
3501
+ content: [{
3502
+ type: "text",
3503
+ text: tr.content
3504
+ }, ...attachments]
3505
+ };
3506
+ return {
3507
+ ...tr,
3508
+ content: [...tr.content, ...attachments]
3509
+ };
3422
3510
  };
3423
- const isCopilotContextCacheEligible = (message) => {
3424
- if (typeof message.content === "string") return message.content.length > 0;
3425
- return Array.isArray(message.content) && message.content.length > 0;
3511
+ const isAttachmentBlock = (block) => {
3512
+ return block.type === "image" || block.type === "document";
3426
3513
  };
3427
- const uniqueIndexes$1 = (indexes) => [...new Set(indexes)];
3428
- const isNonStreaming = (response) => Object.hasOwn(response, "choices");
3429
- const isAsyncIterable$1 = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
3430
- const createCopilotUsageRecorder = (options) => createCopilotTokenUsageRecorder({
3431
- endpoint: options.endpoint,
3432
- fallbackSessionId: options.fallbackSessionId,
3433
- model: options.model,
3434
- sessionId: getMetadataSessionId(options.payload)
3435
- });
3436
- const getMetadataSessionId = (payload) => parseUserIdMetadata(payload.metadata?.user_id).sessionId;
3437
- const parseAnthropicStreamEvent = (data) => {
3438
- try {
3439
- return JSON.parse(data);
3440
- } catch {
3441
- return null;
3442
- }
3514
+ const getMergeableToolResultIndices = (toolResults) => {
3515
+ return toolResults.flatMap((block, index) => block.is_error || hasToolRef(block) ? [] : [index]);
3443
3516
  };
3444
-
3445
- //#endregion
3446
- //#region src/lib/subagent.ts
3447
- const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
3448
-
3449
- //#endregion
3450
- //#region src/routes/messages/subagent-marker.ts
3451
- const parseSubagentMarkerFromFirstUser = (payload) => {
3452
- const firstUserMessage = payload.messages.find((msg) => msg.role === "user" && Array.isArray(msg.content));
3453
- if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
3454
- for (const block of firstUserMessage.content) {
3455
- if (block.type !== "text") continue;
3456
- const marker = parseSubagentMarkerFromSystemReminder(block.text);
3457
- if (marker) return marker;
3458
- }
3459
- return null;
3517
+ const mergeAttachmentsIntoToolResults = (toolResults, attachmentsByToolResultIndex) => {
3518
+ if (attachmentsByToolResultIndex.size === 0) return toolResults;
3519
+ return toolResults.map((block, index) => {
3520
+ const matchedAttachments = attachmentsByToolResultIndex.get(index);
3521
+ if (!matchedAttachments) return block;
3522
+ const orderedAttachments = [...matchedAttachments].sort((left, right) => left.order - right.order).map(({ attachment }) => attachment);
3523
+ return mergeContentWithAttachments(block, orderedAttachments);
3524
+ });
3460
3525
  };
3461
- const parseSubagentMarkerFromSystemReminder = (text) => {
3462
- const startTag = "<system-reminder>";
3463
- const endTag = "</system-reminder>";
3464
- let searchFrom = 0;
3465
- while (true) {
3466
- const reminderStart = text.indexOf(startTag, searchFrom);
3467
- if (reminderStart === -1) break;
3468
- const contentStart = reminderStart + 17;
3469
- const reminderEnd = text.indexOf(endTag, contentStart);
3470
- if (reminderEnd === -1) break;
3471
- const reminderContent = text.slice(contentStart, reminderEnd);
3472
- const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
3473
- if (markerIndex === -1) {
3474
- searchFrom = reminderEnd + 18;
3475
- continue;
3476
- }
3477
- const markerJson = reminderContent.slice(markerIndex + subagentMarkerPrefix.length).trim();
3478
- try {
3479
- const parsed = JSON.parse(markerJson);
3480
- if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
3481
- searchFrom = reminderEnd + 18;
3526
+ const assignAttachmentsToToolResults = (target, attachments, options) => {
3527
+ const { toolResultIndices } = options;
3528
+ const fallbackToolResultIndices = options.fallbackToolResultIndices ?? toolResultIndices;
3529
+ if (attachments.length === 0) return;
3530
+ if (toolResultIndices.length > 0 && toolResultIndices.length === attachments.length) {
3531
+ for (const [index, toolResultIndex] of toolResultIndices.entries()) {
3532
+ const currentAttachments$1 = target.get(toolResultIndex);
3533
+ if (currentAttachments$1) {
3534
+ currentAttachments$1.push(attachments[index]);
3482
3535
  continue;
3483
3536
  }
3484
- return parsed;
3485
- } catch {
3486
- searchFrom = reminderEnd + 18;
3487
- continue;
3537
+ target.set(toolResultIndex, [attachments[index]]);
3488
3538
  }
3539
+ return;
3489
3540
  }
3490
- return null;
3491
- };
3492
-
3493
- //#endregion
3494
- //#region src/routes/messages/handler.ts
3495
- const logger$5 = createHandlerLogger("messages-handler");
3496
- const messagesFlowHandlers = {
3497
- handleWithChatCompletions,
3498
- handleWithMessagesApi,
3499
- handleWithResponsesApi
3500
- };
3501
- async function handleCompletion(c) {
3502
- await checkRateLimit(state);
3503
- const anthropicPayload = await c.req.json();
3504
- debugJson(logger$5, "Anthropic request payload:", anthropicPayload);
3505
- sanitizeIdeTools(anthropicPayload);
3506
- const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
3507
- if (subagentMarker) debugJson(logger$5, "Detected Subagent marker:", subagentMarker);
3508
- const sessionId = getRootSessionId(anthropicPayload, c);
3509
- logger$5.debug("Extracted session ID:", sessionId);
3510
- const compactType = getCompactType(anthropicPayload);
3511
- const anthropicBeta = c.req.header("anthropic-beta");
3512
- logger$5.debug("Anthropic Beta header:", anthropicBeta);
3513
- const noTools = !anthropicPayload.tools || anthropicPayload.tools.length === 0;
3514
- if (anthropicBeta && noTools && compactType === 0) anthropicPayload.model = getSmallModel();
3515
- if (compactType) logger$5.debug("Compact request type:", compactType);
3516
- stripToolReferenceTurnBoundary(anthropicPayload);
3517
- mergeToolResultForClaude(anthropicPayload, { skipLastMessage: compactType === COMPACT_REQUEST });
3518
- const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
3519
- logger$5.debug("Generated request ID:", requestId);
3520
- if (state.manualApprove) await awaitApproval();
3521
- const selectedModel = findEndpointModel(anthropicPayload.model);
3522
- anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
3523
- if (shouldUseMessagesApi(selectedModel)) return await messagesFlowHandlers.handleWithMessagesApi(c, anthropicPayload, {
3524
- anthropicBetaHeader: anthropicBeta,
3525
- subagentMarker,
3526
- selectedModel,
3527
- requestId,
3528
- sessionId,
3529
- compactType,
3530
- logger: logger$5
3531
- });
3532
- if (shouldUseResponsesApi(selectedModel)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
3533
- subagentMarker,
3534
- selectedModel,
3535
- requestId,
3536
- sessionId,
3537
- compactType,
3538
- logger: logger$5
3539
- });
3540
- return await messagesFlowHandlers.handleWithChatCompletions(c, anthropicPayload, {
3541
- subagentMarker,
3542
- requestId,
3543
- sessionId,
3544
- compactType,
3545
- logger: logger$5
3546
- });
3547
- }
3548
- const RESPONSES_ENDPOINT$1 = "/responses";
3549
- const MESSAGES_ENDPOINT = "/v1/messages";
3550
- const shouldUseResponsesApi = (selectedModel) => {
3551
- return selectedModel?.supported_endpoints?.includes(RESPONSES_ENDPOINT$1) ?? false;
3552
- };
3553
- const shouldUseMessagesApi = (selectedModel) => {
3554
- if (!isMessagesApiEnabled()) return false;
3555
- return selectedModel?.supported_endpoints?.includes(MESSAGES_ENDPOINT) ?? false;
3556
- };
3557
-
3558
- //#endregion
3559
- //#region src/routes/messages/route.ts
3560
- const messageRoutes = new Hono();
3561
- messageRoutes.post("/", async (c) => {
3562
- try {
3563
- return await handleCompletion(c);
3564
- } catch (error) {
3565
- return await forwardError(c, error);
3566
- }
3567
- });
3568
- messageRoutes.post("/count_tokens", async (c) => {
3569
- try {
3570
- return await handleCountTokens(c);
3571
- } catch (error) {
3572
- return await forwardError(c, error);
3573
- }
3574
- });
3575
-
3576
- //#endregion
3577
- //#region src/routes/models/route.ts
3578
- const modelRoutes = new Hono();
3579
- modelRoutes.get("/", async (c) => {
3580
- try {
3581
- if (!state.models) await cacheModels();
3582
- const models = state.models?.data.map((model) => {
3583
- const is1m = model.capabilities.limits?.max_context_window_tokens === 1e6;
3584
- return {
3585
- ...model,
3586
- id: is1m ? `${model.id}[1m]` : model.id,
3587
- object: "model",
3588
- type: "model",
3589
- created: 0,
3590
- created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
3591
- owned_by: model.vendor,
3592
- display_name: model.name
3593
- };
3594
- });
3595
- return c.json({
3596
- object: "list",
3597
- data: models,
3598
- has_more: false
3599
- });
3600
- } catch (error) {
3601
- return await forwardError(c, error);
3541
+ const lastToolResultIndex = fallbackToolResultIndices.at(-1);
3542
+ if (lastToolResultIndex === void 0) return;
3543
+ const currentAttachments = target.get(lastToolResultIndex);
3544
+ if (currentAttachments) {
3545
+ currentAttachments.push(...attachments);
3546
+ return;
3602
3547
  }
3603
- });
3604
-
3605
- //#endregion
3606
- //#region src/routes/provider/messages/count-tokens-handler.ts
3607
- const logger$4 = createHandlerLogger("provider-count-tokens-handler");
3608
- const createFallbackModel = (modelId) => ({
3609
- capabilities: {
3610
- family: "provider",
3611
- limits: {},
3612
- object: "model_capabilities",
3613
- supports: {},
3614
- tokenizer: "o200k_base",
3615
- type: "chat"
3616
- },
3617
- id: modelId,
3618
- model_picker_enabled: false,
3619
- name: modelId,
3620
- object: "model",
3621
- preview: false,
3622
- vendor: "provider",
3623
- version: "unknown"
3624
- });
3625
- async function handleProviderCountTokens(c) {
3626
- const provider = c.req.param("provider");
3627
- try {
3628
- const anthropicPayload = await c.req.json();
3629
- const modelId = anthropicPayload.model.trim();
3630
- const providerConfig = getProviderConfig(provider);
3631
- const modelConfig = providerConfig?.models?.[modelId];
3632
- const translationOptions = providerConfig?.type === "openai-compatible" ? {
3633
- supportPdf: modelConfig?.supportPdf,
3634
- toolContentSupportType: modelConfig?.toolContentSupportType ?? []
3635
- } : void 0;
3636
- const openAIPayload = translateToOpenAI(anthropicPayload, translationOptions);
3637
- let selectedModel = state.models?.data.find((model) => model.id === modelId);
3638
- if (!selectedModel && modelId) selectedModel = createFallbackModel(modelId);
3639
- if (!selectedModel) {
3640
- logger$4.warn("provider.count_tokens.model_not_found", {
3641
- provider,
3642
- model: anthropicPayload.model
3548
+ target.set(lastToolResultIndex, [...attachments]);
3549
+ };
3550
+ const startsWithPdfFileRead = (toolResult) => {
3551
+ if (typeof toolResult.content === "string") return toolResult.content.startsWith(PDF_FILE_READ_PREFIX);
3552
+ if (toolResult.content.some((block) => block.type === "document")) return false;
3553
+ if (toolResult.content.length === 0) return false;
3554
+ const firstBlock = toolResult.content[0];
3555
+ if (firstBlock.type !== "text") return false;
3556
+ return firstBlock.text.startsWith(PDF_FILE_READ_PREFIX);
3557
+ };
3558
+ const collectMergeableUserContent = (content) => {
3559
+ const toolResults = [];
3560
+ const textBlocks = [];
3561
+ const attachments = [];
3562
+ for (const [order, block] of content.entries()) {
3563
+ if (block.type === "tool_result") {
3564
+ toolResults.push(block);
3565
+ continue;
3566
+ }
3567
+ if (block.type === "text") {
3568
+ textBlocks.push(block);
3569
+ continue;
3570
+ }
3571
+ if (isAttachmentBlock(block)) {
3572
+ attachments.push({
3573
+ attachment: block,
3574
+ order
3643
3575
  });
3644
- return c.json({ input_tokens: 1 });
3576
+ continue;
3645
3577
  }
3646
- const tokenCount = await getTokenCount(openAIPayload, selectedModel);
3647
- const finalTokenCount = tokenCount.input + tokenCount.output;
3648
- logger$4.debug("provider.count_tokens.success", {
3649
- provider,
3650
- model: anthropicPayload.model,
3651
- input_tokens: finalTokenCount
3652
- });
3653
- return c.json({ input_tokens: finalTokenCount });
3654
- } catch (error) {
3655
- logger$4.error("provider.count_tokens.error", {
3656
- provider,
3657
- error
3658
- });
3659
- return c.json({ input_tokens: 1 });
3578
+ return null;
3660
3579
  }
3661
- }
3662
-
3663
- //#endregion
3664
- //#region src/services/providers/anthropic-proxy.ts
3665
- const SHARED_FORWARDABLE_HEADERS = ["accept", "user-agent"];
3666
- const ANTHROPIC_FORWARDABLE_HEADERS = ["anthropic-version", "anthropic-beta"];
3667
- const STRIPPED_RESPONSE_HEADERS = [
3668
- "connection",
3669
- "content-encoding",
3670
- "content-length",
3671
- "keep-alive",
3672
- "proxy-authenticate",
3673
- "proxy-authorization",
3674
- "te",
3675
- "trailer",
3676
- "transfer-encoding",
3677
- "upgrade"
3678
- ];
3679
- function buildProviderUpstreamHeaders(providerConfig, requestHeaders) {
3680
- const authHeaders = {};
3681
- if (providerConfig.authType === "authorization") authHeaders.authorization = `Bearer ${providerConfig.apiKey}`;
3682
- else authHeaders["x-api-key"] = providerConfig.apiKey;
3683
- const headers = {
3684
- "content-type": "application/json",
3685
- accept: "application/json",
3686
- ...authHeaders
3580
+ return {
3581
+ toolResults,
3582
+ textBlocks,
3583
+ attachments
3687
3584
  };
3688
- for (const headerName of SHARED_FORWARDABLE_HEADERS) {
3689
- const headerValue = requestHeaders.get(headerName);
3690
- if (headerValue) headers[headerName] = headerValue;
3691
- }
3692
- if (providerConfig.type !== "anthropic") return headers;
3693
- for (const headerName of ANTHROPIC_FORWARDABLE_HEADERS) {
3694
- const headerValue = requestHeaders.get(headerName);
3695
- if (headerValue) headers[headerName] = headerValue;
3585
+ };
3586
+ const mergeAttachmentsForToolResults = (toolResults, attachments) => {
3587
+ if (attachments.length === 0) return toolResults;
3588
+ const documentBlocks = attachments.filter(({ attachment }) => attachment.type === "document");
3589
+ const mergeableToolResultIndices = getMergeableToolResultIndices(toolResults);
3590
+ const pdfReadToolResultIndices = mergeableToolResultIndices.filter((index) => startsWithPdfFileRead(toolResults[index]));
3591
+ const attachmentsByToolResultIndex = /* @__PURE__ */ new Map();
3592
+ let remainingAttachments = attachments;
3593
+ let countMatchToolResultIndices = mergeableToolResultIndices;
3594
+ if (documentBlocks.length > 0 && pdfReadToolResultIndices.length > 0) {
3595
+ const matchedDocumentCount = Math.min(pdfReadToolResultIndices.length, documentBlocks.length);
3596
+ const matchedDocuments = documentBlocks.slice(0, matchedDocumentCount);
3597
+ const matchedDocumentOrders = new Set(matchedDocuments.map(({ order }) => order));
3598
+ const matchedPdfToolResultIndices = pdfReadToolResultIndices.slice(0, matchedDocumentCount);
3599
+ const matchedPdfToolResultIndexSet = new Set(matchedPdfToolResultIndices);
3600
+ assignAttachmentsToToolResults(attachmentsByToolResultIndex, matchedDocuments, { toolResultIndices: matchedPdfToolResultIndices });
3601
+ countMatchToolResultIndices = mergeableToolResultIndices.filter((index) => !matchedPdfToolResultIndexSet.has(index));
3602
+ remainingAttachments = attachments.filter(({ attachment, order }) => attachment.type !== "document" || !matchedDocumentOrders.has(order));
3696
3603
  }
3697
- return headers;
3698
- }
3699
- function createProviderProxyResponse(upstreamResponse) {
3700
- const headers = new Headers(upstreamResponse.headers);
3701
- for (const headerName of STRIPPED_RESPONSE_HEADERS) headers.delete(headerName);
3702
- return new Response(upstreamResponse.body, {
3703
- headers,
3704
- status: upstreamResponse.status,
3705
- statusText: upstreamResponse.statusText
3706
- });
3707
- }
3708
- async function forwardProviderMessages(providerConfig, payload, requestHeaders) {
3709
- return await fetch(`${providerConfig.baseUrl}/v1/messages`, {
3710
- method: "POST",
3711
- headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
3712
- body: JSON.stringify(payload)
3713
- });
3714
- }
3715
- async function forwardProviderChatCompletions(providerConfig, payload, requestHeaders) {
3716
- return await fetch(`${providerConfig.baseUrl}/v1/chat/completions`, {
3717
- method: "POST",
3718
- headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders),
3719
- body: JSON.stringify(payload)
3720
- });
3721
- }
3722
- async function forwardProviderModels(providerConfig, requestHeaders) {
3723
- return await fetch(`${providerConfig.baseUrl}/v1/models`, {
3724
- method: "GET",
3725
- headers: buildProviderUpstreamHeaders(providerConfig, requestHeaders)
3604
+ assignAttachmentsToToolResults(attachmentsByToolResultIndex, remainingAttachments, {
3605
+ toolResultIndices: countMatchToolResultIndices,
3606
+ fallbackToolResultIndices: mergeableToolResultIndices
3726
3607
  });
3727
- }
3728
-
3729
- //#endregion
3730
- //#region src/routes/provider/messages/handler.ts
3731
- const logger$3 = createHandlerLogger("provider-messages-handler");
3732
- const OPENAI_COMPATIBLE_CONTEXT_CACHE_MARKER_LIMIT = 4;
3733
- const OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
3734
- const OPENAI_COMPATIBLE_CONTEXT_CACHE_ROLES = new Set([
3735
- "system",
3736
- "user",
3737
- "assistant",
3738
- "tool"
3739
- ]);
3740
- async function handleProviderMessages(c) {
3741
- const provider = c.req.param("provider");
3742
- const providerConfig = getProviderConfig(provider);
3743
- if (!providerConfig) return c.json({ error: {
3744
- message: `Provider '${provider}' not found or disabled`,
3745
- type: "invalid_request_error"
3746
- } }, 404);
3747
- try {
3748
- const payload = await c.req.json();
3749
- const modelConfig = providerConfig.models?.[payload.model];
3750
- applyModelDefaults(payload, modelConfig);
3751
- debugJson(logger$3, "provider.messages.request", {
3752
- payload,
3753
- provider
3754
- });
3755
- if (providerConfig.type === "openai-compatible") return await handleOpenAICompatibleProviderMessages(c, {
3756
- modelConfig,
3757
- payload,
3758
- provider,
3759
- providerConfig
3760
- });
3761
- applyMissingExtraBody(payload, { extraBody: modelConfig?.extraBody });
3762
- const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
3763
- if (!upstreamResponse.ok) {
3764
- logger$3.error("Failed to create responses", upstreamResponse);
3765
- throw new HTTPError("Failed to create responses", upstreamResponse);
3766
- }
3767
- const contentType = upstreamResponse.headers.get("content-type") ?? "";
3768
- if (Boolean(payload.stream) && contentType.includes("text/event-stream")) return streamProviderMessages({
3769
- c,
3770
- payload,
3771
- provider,
3772
- providerConfig,
3773
- upstreamResponse
3774
- });
3775
- const jsonBody = await upstreamResponse.json();
3776
- return respondProviderMessagesJson(c, {
3777
- body: jsonBody,
3778
- payload,
3779
- provider,
3780
- providerConfig
3781
- });
3782
- } catch (error) {
3783
- logger$3.error("provider.messages.error", {
3784
- provider,
3785
- error
3786
- });
3787
- throw error;
3788
- }
3789
- }
3790
- const applyModelDefaults = (payload, modelConfig) => {
3791
- payload.temperature ??= modelConfig?.temperature;
3792
- payload.top_p ??= modelConfig?.topP;
3793
- payload.top_k ??= modelConfig?.topK;
3608
+ return mergeAttachmentsIntoToolResults(toolResults, attachmentsByToolResultIndex);
3794
3609
  };
3795
- const applyMissingExtraBody = (payload, options) => {
3796
- for (const [key, value] of Object.entries(options.extraBody ?? {})) if (!Object.hasOwn(payload, key)) payload[key] = value;
3610
+ const mergeUserMessageContent = (content) => {
3611
+ const mergeableContent = collectMergeableUserContent(content);
3612
+ if (!mergeableContent) return null;
3613
+ const { toolResults, textBlocks, attachments } = mergeableContent;
3614
+ if (toolResults.length === 0 || textBlocks.length === 0 && attachments.length === 0) return null;
3615
+ const mergedToolResults = textBlocks.length === 0 ? toolResults : mergeToolResult(toolResults, textBlocks);
3616
+ return mergeAttachmentsForToolResults(mergedToolResults, attachments);
3797
3617
  };
3798
- const handleOpenAICompatibleProviderMessages = async (c, options) => {
3799
- const { modelConfig, payload, provider, providerConfig } = options;
3800
- const openAIPayload = createOpenAICompatiblePayload(payload, modelConfig);
3801
- debugJson(logger$3, "provider.messages.openai_compatible.request", {
3802
- payload: openAIPayload,
3803
- provider
3804
- });
3805
- const upstreamResponse = await forwardProviderChatCompletions(providerConfig, openAIPayload, c.req.raw.headers);
3806
- if (!upstreamResponse.ok) {
3807
- logger$3.error("Failed to create openai-compatible responses", upstreamResponse);
3808
- throw new HTTPError("Failed to create openai-compatible responses", upstreamResponse);
3809
- }
3810
- const contentType = upstreamResponse.headers.get("content-type") ?? "";
3811
- if (Boolean(openAIPayload.stream) && contentType.includes("text/event-stream")) return streamOpenAICompatibleProviderMessages({
3812
- c,
3813
- payload,
3814
- provider,
3815
- upstreamResponse
3816
- });
3817
- const jsonBody = await upstreamResponse.json();
3818
- return respondOpenAICompatibleProviderMessagesJson(c, {
3819
- body: jsonBody,
3820
- payload,
3821
- provider
3822
- });
3618
+ const mergeToolResult = (toolResults, textBlocks) => {
3619
+ if (toolResults.length === textBlocks.length) return toolResults.map((tr, i) => mergeContentWithText(tr, textBlocks[i]));
3620
+ const lastIndex = toolResults.length - 1;
3621
+ return toolResults.map((tr, i) => i === lastIndex ? mergeContentWithTexts(tr, textBlocks) : tr);
3823
3622
  };
3824
- const createOpenAICompatiblePayload = (payload, modelConfig) => {
3825
- const openAIPayload = translateToOpenAI(payload, {
3826
- supportPdf: modelConfig?.supportPdf,
3827
- toolContentSupportType: modelConfig?.toolContentSupportType ?? []
3828
- });
3829
- if (payload.top_k !== void 0) openAIPayload.top_k = payload.top_k;
3830
- if (openAIPayload.stream) openAIPayload.stream_options = { include_usage: true };
3831
- normalizeOpenAICompatibleReasoningContent(openAIPayload);
3832
- applyOpenAICompatibleRequestOverrides(openAIPayload, {
3833
- extraBody: modelConfig?.extraBody,
3834
- source: payload
3835
- });
3836
- applyMissingExtraBody(openAIPayload, { extraBody: modelConfig?.extraBody });
3837
- if (!Object.hasOwn(openAIPayload, "parallel_tool_calls")) openAIPayload.parallel_tool_calls = true;
3838
- if (modelConfig?.contextCache !== false) applyOpenAICompatibleContextCache(openAIPayload);
3839
- return openAIPayload;
3623
+ const stripToolReferenceTurnBoundary = (anthropicPayload) => {
3624
+ for (const msg of anthropicPayload.messages) {
3625
+ if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
3626
+ if (!msg.content.some((block) => block.type === "tool_result" && hasToolRef(block))) continue;
3627
+ msg.content = msg.content.filter((block) => block.type !== "text" || block.text.trim() !== TOOL_REFERENCE_TURN_BOUNDARY);
3628
+ }
3840
3629
  };
3841
- const normalizeOpenAICompatibleReasoningContent = (payload) => {
3842
- for (const message of payload.messages) {
3843
- if (message.role !== "assistant") continue;
3844
- if (message.reasoning_content === void 0 && message.reasoning_text !== void 0) message.reasoning_content = message.reasoning_text;
3845
- delete message.reasoning_text;
3846
- delete message.reasoning_opaque;
3630
+ const mergeToolResultForClaude = (anthropicPayload, options) => {
3631
+ const lastMessageIndex = anthropicPayload.messages.length - 1;
3632
+ for (const [index, msg] of anthropicPayload.messages.entries()) {
3633
+ if (options?.skipLastMessage && index === lastMessageIndex) continue;
3634
+ if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
3635
+ const mergedContent = mergeUserMessageContent(msg.content);
3636
+ if (mergedContent) msg.content = mergedContent;
3847
3637
  }
3848
3638
  };
3849
- const applyOpenAICompatibleRequestOverrides = (payload, options) => {
3850
- const allowedKeys = new Set(Object.keys(options.extraBody ?? {}));
3851
- for (const key of allowedKeys) if (Object.hasOwn(options.source, key)) payload[key] = options.source[key];
3639
+ const sanitizeIdeTools = (payload) => {
3640
+ if (!payload.tools || payload.tools.length === 0) return;
3641
+ payload.tools = payload.tools.flatMap((tool) => {
3642
+ if (tool.name === IDE_EXECUTE_CODE_TOOL && !tool.defer_loading) return [];
3643
+ if (tool.name === IDE_GET_DIAGNOSTICS_TOOL) return [{
3644
+ ...tool,
3645
+ description: IDE_GET_DIAGNOSTICS_DESCRIPTION
3646
+ }];
3647
+ return [tool];
3648
+ });
3852
3649
  };
3853
- const applyOpenAICompatibleContextCache = (payload) => {
3854
- const messageIndexes = selectContextCacheMessageIndexes(payload.messages);
3855
- for (const messageIndex of messageIndexes) applyContextCacheControl(payload.messages[messageIndex]);
3650
+ const hasToolRef = (block) => {
3651
+ return Array.isArray(block.content) && block.content.some((c) => c.type === "tool_reference");
3856
3652
  };
3857
- const selectContextCacheMessageIndexes = (messages) => {
3858
- const cacheableIndexes = messages.flatMap((message, index) => isContextCacheMarkerEligible(message) ? [index] : []);
3859
- const systemIndexes = cacheableIndexes.filter((index) => messages[index]?.role === "system").slice(0, 2);
3860
- const finalIndexes = cacheableIndexes.filter((index) => messages[index]?.role !== "system").slice(-2);
3861
- return uniqueIndexes([...systemIndexes, ...finalIndexes]).sort((a, b) => a - b);
3653
+ const stripCacheControl = (payload) => {
3654
+ if (Array.isArray(payload.system)) for (const block of payload.system) {
3655
+ const systemBlock = block;
3656
+ const cacheControl = systemBlock.cache_control;
3657
+ if (cacheControl && typeof cacheControl === "object") {
3658
+ const { scope,...rest } = cacheControl;
3659
+ systemBlock.cache_control = rest;
3660
+ }
3661
+ }
3862
3662
  };
3863
- const uniqueIndexes = (indexes) => [...new Set(indexes)].slice(0, OPENAI_COMPATIBLE_CONTEXT_CACHE_MARKER_LIMIT);
3864
- const isContextCacheMarkerEligible = (message) => {
3865
- if (!OPENAI_COMPATIBLE_CONTEXT_CACHE_ROLES.has(message.role)) return false;
3866
- if (typeof message.content === "string") return message.content.length > 0;
3867
- return Array.isArray(message.content) && message.content.length > 0;
3663
+ const filterAssistantThinkingBlocks = (payload) => {
3664
+ for (const msg of payload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
3665
+ if (block.type !== "thinking") return true;
3666
+ return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
3667
+ });
3868
3668
  };
3869
- const applyContextCacheControl = (message) => {
3870
- if (!message) return;
3871
- if (typeof message.content === "string") {
3872
- message.content = [{
3873
- type: "text",
3874
- text: message.content,
3875
- cache_control: { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL }
3876
- }];
3877
- return;
3669
+ const prepareMessagesApiPayload = (payload, selectedModel) => {
3670
+ stripCacheControl(payload);
3671
+ filterAssistantThinkingBlocks(payload);
3672
+ const hasThinking = Boolean(payload.thinking);
3673
+ const toolChoice = payload.tool_choice;
3674
+ const disableThink = toolChoice?.type === "any" || toolChoice?.type === "tool";
3675
+ if (selectedModel?.capabilities.supports.adaptive_thinking && !disableThink) {
3676
+ payload.thinking = { type: "adaptive" };
3677
+ if (!hasThinking) payload.thinking.display = "summarized";
3678
+ if (payload.model === "claude-opus-4.7") payload.thinking.display = "summarized";
3679
+ let effort = getReasoningEffortForModel(payload.model);
3680
+ if (effort === "none" || effort === "minimal") effort = "low";
3681
+ const reasoningEffort = selectedModel.capabilities.supports.reasoning_effort;
3682
+ if (reasoningEffort && !reasoningEffort.includes(effort)) effort = reasoningEffort.at(-1);
3683
+ payload.output_config = { effort };
3878
3684
  }
3879
- if (!Array.isArray(message.content)) return;
3880
- const lastPart = message.content.at(-1);
3881
- if (!lastPart) return;
3882
- setContextCacheControl(lastPart);
3883
3685
  };
3884
- const setContextCacheControl = (part) => {
3885
- part.cache_control = { ...OPENAI_COMPATIBLE_CONTEXT_CACHE_CONTROL };
3886
- };
3887
- const streamProviderMessages = ({ c, payload, provider, providerConfig, upstreamResponse }) => {
3888
- logger$3.debug("provider.messages.streaming");
3889
- const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
3890
- return streamSSE(c, async (stream) => {
3891
- let usage = {};
3892
- for await (const chunk of events(upstreamResponse)) {
3893
- logger$3.debug("provider.messages.raw_stream_event:", chunk.data);
3894
- const eventName = chunk.event;
3895
- if (eventName === "ping") {
3896
- await stream.writeSSE({
3897
- event: "ping",
3898
- data: "{\"type\":\"ping\"}"
3899
- });
3900
- continue;
3901
- }
3902
- let data = chunk.data;
3903
- if (!data) continue;
3904
- if (chunk.data === "[DONE]") break;
3905
- const parsed = parseProviderStreamEvent(data, providerConfig);
3906
- if (parsed) {
3907
- usage = mergeAnthropicUsage(usage, parsed.usage);
3908
- data = parsed.data;
3909
- }
3910
- await stream.writeSSE({
3911
- event: eventName,
3912
- data
3913
- });
3914
- }
3915
- recordUsage(usage);
3686
+
3687
+ //#endregion
3688
+ //#region src/routes/messages/api-flows.ts
3689
+ const COPILOT_CONTEXT_CACHE_SYSTEM_MARKER_LIMIT = 2;
3690
+ const COPILOT_CONTEXT_CACHE_NON_SYSTEM_MARKER_LIMIT = 2;
3691
+ const COPILOT_CONTEXT_CACHE_CONTROL = { type: "ephemeral" };
3692
+ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
3693
+ const { logger: logger$7, subagentMarker, requestId, sessionId, compactType } = options;
3694
+ const openAIPayload = translateToOpenAI(anthropicPayload);
3695
+ prepareCopilotChatCompletionsPayload(openAIPayload);
3696
+ const recordUsage = createCopilotUsageRecorder({
3697
+ endpoint: "chat_completions",
3698
+ fallbackSessionId: sessionId,
3699
+ model: openAIPayload.model,
3700
+ payload: anthropicPayload
3916
3701
  });
3917
- };
3918
- const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstreamResponse }) => {
3919
- logger$3.debug("provider.messages.openai_compatible.streaming");
3920
- const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
3702
+ debugJson(logger$7, "Translated OpenAI request payload:", openAIPayload);
3703
+ const response = await createChatCompletions(openAIPayload, {
3704
+ subagentMarker,
3705
+ requestId,
3706
+ sessionId,
3707
+ compactType
3708
+ });
3709
+ if (isNonStreaming(response)) {
3710
+ debugJson(logger$7, "Non-streaming response from Copilot:", response);
3711
+ recordUsage(normalizeOpenAIUsage(response.usage));
3712
+ const anthropicResponse = translateToAnthropic(response);
3713
+ debugJson(logger$7, "Translated Anthropic response:", anthropicResponse);
3714
+ return c.json(anthropicResponse);
3715
+ }
3716
+ logger$7.debug("Streaming response from Copilot");
3921
3717
  return streamSSE(c, async (stream) => {
3922
3718
  let usage = {};
3923
3719
  const streamState = {
@@ -3927,111 +3723,352 @@ const streamOpenAICompatibleProviderMessages = ({ c, payload, provider, upstream
3927
3723
  toolCalls: {},
3928
3724
  thinkingBlockOpen: false
3929
3725
  };
3930
- for await (const chunk of events(upstreamResponse)) {
3931
- logger$3.debug("provider.messages.openai_compatible.raw_stream_event:", chunk.data);
3932
- if (chunk.event === "ping") {
3726
+ for await (const rawEvent of response) {
3727
+ debugJson(logger$7, "Copilot raw stream event:", rawEvent);
3728
+ if (rawEvent.data === "[DONE]") break;
3729
+ if (!rawEvent.data) continue;
3730
+ const chunk = JSON.parse(rawEvent.data);
3731
+ if (chunk.usage) usage = normalizeOpenAIUsage(chunk.usage);
3732
+ const events$1 = translateChunkToAnthropicEvents(chunk, streamState);
3733
+ for (const event of events$1) {
3734
+ const eventData = JSON.stringify(event);
3735
+ debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
3933
3736
  await stream.writeSSE({
3934
- event: "ping",
3935
- data: "{\"type\":\"ping\"}"
3737
+ event: event.type,
3738
+ data: eventData
3936
3739
  });
3937
- continue;
3938
3740
  }
3939
- if (!chunk.data || chunk.data === "[DONE]") {
3940
- if (chunk.data === "[DONE]") break;
3941
- continue;
3741
+ }
3742
+ for (const event of flushPendingAnthropicStreamEvents(streamState)) {
3743
+ const eventData = JSON.stringify(event);
3744
+ debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
3745
+ await stream.writeSSE({
3746
+ event: event.type,
3747
+ data: eventData
3748
+ });
3749
+ }
3750
+ recordUsage(usage);
3751
+ });
3752
+ };
3753
+ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
3754
+ const { logger: logger$7, selectedModel,...requestOptions } = options;
3755
+ const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload);
3756
+ const recordUsage = createCopilotUsageRecorder({
3757
+ endpoint: "responses",
3758
+ fallbackSessionId: requestOptions.sessionId,
3759
+ model: responsesPayload.model,
3760
+ payload: anthropicPayload
3761
+ });
3762
+ applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
3763
+ compactInputByLatestCompaction(responsesPayload);
3764
+ debugJson(logger$7, "Translated Responses payload:", responsesPayload);
3765
+ const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
3766
+ const response = await createResponses(responsesPayload, {
3767
+ vision,
3768
+ initiator,
3769
+ ...requestOptions
3770
+ });
3771
+ if (responsesPayload.stream && isAsyncIterable$1(response)) {
3772
+ logger$7.debug("Streaming response from Copilot (Responses API)");
3773
+ return streamSSE(c, async (stream) => {
3774
+ const streamState = createResponsesStreamState();
3775
+ let usage = {};
3776
+ for await (const chunk of response) {
3777
+ if (chunk.event === "ping") {
3778
+ await stream.writeSSE({
3779
+ event: "ping",
3780
+ data: "{\"type\":\"ping\"}"
3781
+ });
3782
+ continue;
3783
+ }
3784
+ const data = chunk.data;
3785
+ if (!data) continue;
3786
+ debugLazy(logger$7, () => ["Responses raw stream event:", data]);
3787
+ const responseEvent = JSON.parse(data);
3788
+ if (responseEvent.type === "response.completed" || responseEvent.type === "response.failed" || responseEvent.type === "response.incomplete") usage = normalizeResponsesUsage(responseEvent.response.usage);
3789
+ const events$1 = translateResponsesStreamEvent(responseEvent, streamState);
3790
+ for (const event of events$1) {
3791
+ const eventData = JSON.stringify(event);
3792
+ debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
3793
+ await stream.writeSSE({
3794
+ event: event.type,
3795
+ data: eventData
3796
+ });
3797
+ }
3798
+ if (streamState.messageCompleted) {
3799
+ logger$7.debug("Message completed, ending stream");
3800
+ break;
3801
+ }
3942
3802
  }
3943
- const parsed = parseOpenAICompatibleStreamChunk(chunk.data);
3944
- if (!parsed) continue;
3945
- if (parsed.usage) usage = normalizeOpenAIUsage(parsed.usage);
3946
- const events$1 = translateChunkToAnthropicEvents(parsed, streamState);
3947
- for (const event of events$1) {
3948
- const eventData = JSON.stringify(event);
3949
- debugLazy(logger$3, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
3803
+ if (!streamState.messageCompleted) {
3804
+ logger$7.warn("Responses stream ended without completion; sending error event");
3805
+ const errorEvent = buildErrorEvent("Responses stream ended without completion");
3806
+ await stream.writeSSE({
3807
+ event: errorEvent.type,
3808
+ data: JSON.stringify(errorEvent)
3809
+ });
3810
+ }
3811
+ recordUsage(usage);
3812
+ });
3813
+ }
3814
+ debugJsonTail(logger$7, "Non-streaming Responses result:", {
3815
+ value: response,
3816
+ tailLength: 400
3817
+ });
3818
+ const anthropicResponse = translateResponsesResultToAnthropic(response);
3819
+ recordUsage(normalizeResponsesUsage(response.usage));
3820
+ debugJson(logger$7, "Translated Anthropic response:", anthropicResponse);
3821
+ return c.json(anthropicResponse);
3822
+ };
3823
+ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
3824
+ const { logger: logger$7, anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId, compactType } = options;
3825
+ prepareMessagesApiPayload(anthropicPayload, selectedModel);
3826
+ const recordUsage = createCopilotUsageRecorder({
3827
+ endpoint: "messages",
3828
+ fallbackSessionId: sessionId,
3829
+ model: anthropicPayload.model,
3830
+ payload: anthropicPayload
3831
+ });
3832
+ debugJson(logger$7, "Translated Messages payload:", anthropicPayload);
3833
+ const response = await createMessages(anthropicPayload, anthropicBetaHeader, {
3834
+ subagentMarker,
3835
+ requestId,
3836
+ sessionId,
3837
+ compactType
3838
+ });
3839
+ if (isAsyncIterable$1(response)) {
3840
+ logger$7.debug("Streaming response from Copilot (Messages API)");
3841
+ return streamSSE(c, async (stream) => {
3842
+ let usage = {};
3843
+ for await (const event of response) {
3844
+ const eventName = event.event;
3845
+ const data = event.data ?? "";
3846
+ if (data === "[DONE]") break;
3847
+ if (!data) continue;
3848
+ debugLazy(logger$7, () => ["Messages raw stream event:", data]);
3849
+ const parsedEvent = parseAnthropicStreamEvent(data);
3850
+ if (parsedEvent?.type === "message_start") usage = mergeAnthropicUsage(usage, normalizeAnthropicUsage(parsedEvent.message.usage));
3851
+ else if (parsedEvent?.type === "message_delta") usage = mergeAnthropicUsage(usage, normalizeAnthropicUsage(parsedEvent.usage));
3950
3852
  await stream.writeSSE({
3951
- event: event.type,
3952
- data: eventData
3853
+ event: eventName,
3854
+ data
3953
3855
  });
3954
3856
  }
3955
- }
3956
- for (const event of flushPendingAnthropicStreamEvents(streamState)) {
3957
- const eventData = JSON.stringify(event);
3958
- debugLazy(logger$3, () => ["provider.messages.openai_compatible.translated_event:", eventData]);
3959
- await stream.writeSSE({
3960
- event: event.type,
3961
- data: eventData
3962
- });
3963
- }
3964
- recordUsage(usage);
3857
+ recordUsage(usage);
3858
+ });
3859
+ }
3860
+ debugJsonTail(logger$7, "Non-streaming Messages result:", {
3861
+ value: response,
3862
+ tailLength: 400
3965
3863
  });
3864
+ recordUsage(normalizeAnthropicUsage(response.usage));
3865
+ return c.json(response);
3966
3866
  };
3967
- const parseOpenAICompatibleStreamChunk = (data) => {
3867
+ const prepareCopilotChatCompletionsPayload = (payload) => {
3868
+ applyCopilotContextCache(payload);
3869
+ };
3870
+ const applyCopilotContextCache = (payload) => {
3871
+ const messageIndexes = selectCopilotContextCacheMessageIndexes(payload.messages);
3872
+ for (const messageIndex of messageIndexes) {
3873
+ const message = payload.messages[messageIndex];
3874
+ message.copilot_cache_control = { ...COPILOT_CONTEXT_CACHE_CONTROL };
3875
+ }
3876
+ };
3877
+ const selectCopilotContextCacheMessageIndexes = (messages) => {
3878
+ const systemIndexes = messages.flatMap((message, index) => message.role === "system" && isCopilotContextCacheEligible(message) ? [index] : []).slice(0, COPILOT_CONTEXT_CACHE_SYSTEM_MARKER_LIMIT);
3879
+ const reverseNonSystemIndexes = messages.flatMap((message, index) => message.role !== "system" && isCopilotContextCacheEligible(message) ? [index] : []).reverse().slice(0, COPILOT_CONTEXT_CACHE_NON_SYSTEM_MARKER_LIMIT);
3880
+ return uniqueIndexes([...systemIndexes, ...reverseNonSystemIndexes]).sort((a, b) => a - b);
3881
+ };
3882
+ const isCopilotContextCacheEligible = (message) => {
3883
+ if (typeof message.content === "string") return message.content.length > 0;
3884
+ return Array.isArray(message.content) && message.content.length > 0;
3885
+ };
3886
+ const uniqueIndexes = (indexes) => [...new Set(indexes)];
3887
+ const isNonStreaming = (response) => Object.hasOwn(response, "choices");
3888
+ const isAsyncIterable$1 = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
3889
+ const createCopilotUsageRecorder = (options) => createCopilotTokenUsageRecorder({
3890
+ endpoint: options.endpoint,
3891
+ fallbackSessionId: options.fallbackSessionId,
3892
+ model: options.model,
3893
+ sessionId: getMetadataSessionId(options.payload)
3894
+ });
3895
+ const getMetadataSessionId = (payload) => parseUserIdMetadata(payload.metadata?.user_id).sessionId;
3896
+ const parseAnthropicStreamEvent = (data) => {
3968
3897
  try {
3969
3898
  return JSON.parse(data);
3970
- } catch (error) {
3971
- logger$3.error("provider.messages.openai_compatible.parse_chunk_error", {
3972
- data,
3973
- error
3974
- });
3899
+ } catch {
3975
3900
  return null;
3976
3901
  }
3977
3902
  };
3978
- const parseProviderStreamEvent = (data, providerConfig) => {
3979
- try {
3980
- const parsed = JSON.parse(data);
3981
- if (parsed.type === "message_start") {
3982
- adjustInputTokens(providerConfig, parsed.message.usage);
3983
- return {
3984
- data: JSON.stringify(parsed),
3985
- model: parsed.message.model,
3986
- usage: normalizeAnthropicUsage(parsed.message.usage)
3987
- };
3903
+
3904
+ //#endregion
3905
+ //#region src/lib/subagent.ts
3906
+ const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
3907
+
3908
+ //#endregion
3909
+ //#region src/routes/messages/subagent-marker.ts
3910
+ const parseSubagentMarkerFromFirstUser = (payload) => {
3911
+ const firstUserMessage = payload.messages.find((msg) => msg.role === "user" && Array.isArray(msg.content));
3912
+ if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
3913
+ for (const block of firstUserMessage.content) {
3914
+ if (block.type !== "text") continue;
3915
+ const marker = parseSubagentMarkerFromSystemReminder(block.text);
3916
+ if (marker) return marker;
3917
+ }
3918
+ return null;
3919
+ };
3920
+ const parseSubagentMarkerFromSystemReminder = (text) => {
3921
+ const startTag = "<system-reminder>";
3922
+ const endTag = "</system-reminder>";
3923
+ let searchFrom = 0;
3924
+ while (true) {
3925
+ const reminderStart = text.indexOf(startTag, searchFrom);
3926
+ if (reminderStart === -1) break;
3927
+ const contentStart = reminderStart + 17;
3928
+ const reminderEnd = text.indexOf(endTag, contentStart);
3929
+ if (reminderEnd === -1) break;
3930
+ const reminderContent = text.slice(contentStart, reminderEnd);
3931
+ const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
3932
+ if (markerIndex === -1) {
3933
+ searchFrom = reminderEnd + 18;
3934
+ continue;
3988
3935
  }
3989
- if (parsed.type === "message_delta") {
3990
- adjustInputTokens(providerConfig, parsed.usage);
3991
- return {
3992
- data: JSON.stringify(parsed),
3993
- usage: normalizeAnthropicUsage(parsed.usage)
3994
- };
3936
+ const markerJson = reminderContent.slice(markerIndex + subagentMarkerPrefix.length).trim();
3937
+ try {
3938
+ const parsed = JSON.parse(markerJson);
3939
+ if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
3940
+ searchFrom = reminderEnd + 18;
3941
+ continue;
3942
+ }
3943
+ return parsed;
3944
+ } catch {
3945
+ searchFrom = reminderEnd + 18;
3946
+ continue;
3995
3947
  }
3996
- return {
3997
- data: JSON.stringify(parsed),
3998
- usage: {}
3999
- };
4000
- } catch (error) {
4001
- logger$3.error("provider.messages.streaming.adjust_tokens_error", {
4002
- error,
4003
- originalData: data
4004
- });
4005
- return null;
4006
3948
  }
3949
+ return null;
4007
3950
  };
4008
- const respondProviderMessagesJson = (c, options) => {
4009
- const { body, payload, provider, providerConfig } = options;
4010
- const recordUsage = createProviderMessagesUsageRecorder(payload, provider);
4011
- adjustInputTokens(providerConfig, body.usage);
4012
- recordUsage(normalizeAnthropicUsage(body.usage));
4013
- debugJson(logger$3, "provider.messages.no_stream result:", body);
4014
- return c.json(body);
3951
+
3952
+ //#endregion
3953
+ //#region src/routes/messages/handler.ts
3954
+ const logger$3 = createHandlerLogger("messages-handler");
3955
+ const messagesFlowHandlers = {
3956
+ handleWithChatCompletions,
3957
+ handleWithMessagesApi,
3958
+ handleWithResponsesApi
4015
3959
  };
4016
- const respondOpenAICompatibleProviderMessagesJson = (c, options) => {
4017
- const { body, payload, provider } = options;
4018
- createProviderMessagesUsageRecorder(payload, provider)(normalizeOpenAIUsage(body.usage));
4019
- const anthropicResponse = translateToAnthropic(body);
4020
- debugJson(logger$3, "provider.messages.openai_compatible.no_stream result:", anthropicResponse);
4021
- return c.json(anthropicResponse);
3960
+ async function handleCompletion(c) {
3961
+ const anthropicPayload = await c.req.json();
3962
+ const providerModelAlias = parseProviderModelAlias(anthropicPayload.model);
3963
+ if (providerModelAlias) {
3964
+ anthropicPayload.model = providerModelAlias.model;
3965
+ return await handleProviderMessagesForProvider(c, {
3966
+ payload: anthropicPayload,
3967
+ provider: providerModelAlias.provider
3968
+ });
3969
+ }
3970
+ await checkRateLimit(state);
3971
+ debugJson(logger$3, "Anthropic request payload:", anthropicPayload);
3972
+ sanitizeIdeTools(anthropicPayload);
3973
+ const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
3974
+ if (subagentMarker) debugJson(logger$3, "Detected Subagent marker:", subagentMarker);
3975
+ const sessionId = getRootSessionId(anthropicPayload, c);
3976
+ logger$3.debug("Extracted session ID:", sessionId);
3977
+ const compactType = getCompactType(anthropicPayload);
3978
+ const anthropicBeta = c.req.header("anthropic-beta");
3979
+ logger$3.debug("Anthropic Beta header:", anthropicBeta);
3980
+ const noTools = !anthropicPayload.tools || anthropicPayload.tools.length === 0;
3981
+ if (anthropicBeta && noTools && compactType === 0) anthropicPayload.model = getSmallModel();
3982
+ if (compactType) logger$3.debug("Compact request type:", compactType);
3983
+ stripToolReferenceTurnBoundary(anthropicPayload);
3984
+ mergeToolResultForClaude(anthropicPayload, { skipLastMessage: compactType === COMPACT_REQUEST });
3985
+ const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
3986
+ logger$3.debug("Generated request ID:", requestId);
3987
+ if (state.manualApprove) await awaitApproval();
3988
+ const selectedModel = findEndpointModel(anthropicPayload.model);
3989
+ anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
3990
+ if (shouldUseMessagesApi(selectedModel)) return await messagesFlowHandlers.handleWithMessagesApi(c, anthropicPayload, {
3991
+ anthropicBetaHeader: anthropicBeta,
3992
+ subagentMarker,
3993
+ selectedModel,
3994
+ requestId,
3995
+ sessionId,
3996
+ compactType,
3997
+ logger: logger$3
3998
+ });
3999
+ if (shouldUseResponsesApi(selectedModel)) return await messagesFlowHandlers.handleWithResponsesApi(c, anthropicPayload, {
4000
+ subagentMarker,
4001
+ selectedModel,
4002
+ requestId,
4003
+ sessionId,
4004
+ compactType,
4005
+ logger: logger$3
4006
+ });
4007
+ return await messagesFlowHandlers.handleWithChatCompletions(c, anthropicPayload, {
4008
+ subagentMarker,
4009
+ requestId,
4010
+ sessionId,
4011
+ compactType,
4012
+ logger: logger$3
4013
+ });
4014
+ }
4015
+ const RESPONSES_ENDPOINT$1 = "/responses";
4016
+ const MESSAGES_ENDPOINT = "/v1/messages";
4017
+ const shouldUseResponsesApi = (selectedModel) => {
4018
+ return selectedModel?.supported_endpoints?.includes(RESPONSES_ENDPOINT$1) ?? false;
4022
4019
  };
4023
- const createProviderMessagesUsageRecorder = (payload, provider) => createProviderTokenUsageRecorder({
4024
- endpoint: "provider_messages",
4025
- model: payload.model,
4026
- providerName: provider,
4027
- sessionId: parseUserIdMetadata(payload.metadata?.user_id).sessionId
4028
- });
4029
- const adjustInputTokens = (providerConfig, usage) => {
4030
- if (!providerConfig.adjustInputTokens || !usage) return;
4031
- usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
4032
- debugJson(logger$3, "provider.messages.adjusted_usage:", usage);
4020
+ const shouldUseMessagesApi = (selectedModel) => {
4021
+ if (!isMessagesApiEnabled()) return false;
4022
+ return selectedModel?.supported_endpoints?.includes(MESSAGES_ENDPOINT) ?? false;
4033
4023
  };
4034
4024
 
4025
+ //#endregion
4026
+ //#region src/routes/messages/route.ts
4027
+ const messageRoutes = new Hono();
4028
+ messageRoutes.post("/", async (c) => {
4029
+ try {
4030
+ return await handleCompletion(c);
4031
+ } catch (error) {
4032
+ return await forwardError(c, error);
4033
+ }
4034
+ });
4035
+ messageRoutes.post("/count_tokens", async (c) => {
4036
+ try {
4037
+ return await handleCountTokens(c);
4038
+ } catch (error) {
4039
+ return await forwardError(c, error);
4040
+ }
4041
+ });
4042
+
4043
+ //#endregion
4044
+ //#region src/routes/models/route.ts
4045
+ const modelRoutes = new Hono();
4046
+ modelRoutes.get("/", async (c) => {
4047
+ try {
4048
+ if (!state.models) await cacheModels();
4049
+ const models = state.models?.data.map((model) => {
4050
+ const is1m = model.capabilities.limits?.max_context_window_tokens === 1e6;
4051
+ return {
4052
+ ...model,
4053
+ id: is1m ? `${model.id}[1m]` : model.id,
4054
+ object: "model",
4055
+ type: "model",
4056
+ created: 0,
4057
+ created_at: (/* @__PURE__ */ new Date(0)).toISOString(),
4058
+ owned_by: model.vendor,
4059
+ display_name: model.name
4060
+ };
4061
+ });
4062
+ return c.json({
4063
+ object: "list",
4064
+ data: models,
4065
+ has_more: false
4066
+ });
4067
+ } catch (error) {
4068
+ return await forwardError(c, error);
4069
+ }
4070
+ });
4071
+
4035
4072
  //#endregion
4036
4073
  //#region src/routes/provider/messages/route.ts
4037
4074
  const providerMessageRoutes = new Hono();
@@ -4339,4 +4376,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
4339
4376
 
4340
4377
  //#endregion
4341
4378
  export { server };
4342
- //# sourceMappingURL=server-BG69Fgym.js.map
4379
+ //# sourceMappingURL=server-D4pg54e1.js.map