@jeffreycao/copilot-api 1.2.2 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { HTTPError, PATHS, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, getConfig, getCopilotUsage, getExtraPromptForModel, getReasoningEffortForModel, getSmallModel, isNullish, shouldCompactUseSmallModel, sleep, state } from "./config-DYI6xs3W.js";
1
+ import { HTTPError, PATHS, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getConfig, getCopilotUsage, getExtraPromptForModel, getReasoningEffortForModel, getRootSessionId, getSmallModel, getUUID, isNullish, isResponsesApiContextManagementModel, shouldCompactUseSmallModel, sleep, state } from "./config-BD6sOCuT.js";
2
2
  import consola from "consola";
3
3
  import path from "node:path";
4
4
  import fs, { readFileSync } from "node:fs";
@@ -426,9 +426,14 @@ const createChatCompletions = async (payload, options) => {
426
426
  if (lastMessage) isAgentCall = ["assistant", "tool"].includes(lastMessage.role);
427
427
  }
428
428
  const headers = {
429
- ...copilotHeaders(state, enableVision),
430
- "X-Initiator": options?.initiator ?? (isAgentCall ? "agent" : "user")
429
+ ...copilotHeaders(state, options.requestId, enableVision),
430
+ "x-initiator": isAgentCall ? "agent" : "user"
431
431
  };
432
+ if (options.subagentMarker) {
433
+ headers["x-initiator"] = "agent";
434
+ headers["x-interaction-type"] = "conversation-subagent";
435
+ }
436
+ if (options.sessionId) headers["x-interaction-id"] = options.sessionId;
432
437
  const response = await fetch(`${copilotBaseUrl(state)}/chat/completions`, {
433
438
  method: "POST",
434
439
  headers,
@@ -466,7 +471,14 @@ async function handleCompletion$1(c) {
466
471
  };
467
472
  logger$3.debug("Set max_tokens to:", JSON.stringify(payload.max_tokens));
468
473
  }
469
- const response = await createChatCompletions(payload);
474
+ const requestId = generateRequestIdFromPayload(payload);
475
+ logger$3.debug("Generated request ID:", requestId);
476
+ const sessionId = getUUID(requestId);
477
+ logger$3.debug("Extracted session ID:", sessionId);
478
+ const response = await createChatCompletions(payload, {
479
+ requestId,
480
+ sessionId
481
+ });
470
482
  if (isNonStreaming$1(response)) {
471
483
  logger$3.debug("Non-streaming response:", JSON.stringify(response));
472
484
  return c.json(response);
@@ -805,12 +817,17 @@ async function handleCountTokens(c) {
805
817
 
806
818
  //#endregion
807
819
  //#region src/services/copilot/create-responses.ts
808
- const createResponses = async (payload, { vision, initiator }) => {
820
+ const createResponses = async (payload, { vision, initiator, subagentMarker, requestId, sessionId }) => {
809
821
  if (!state.copilotToken) throw new Error("Copilot token not found");
810
822
  const headers = {
811
- ...copilotHeaders(state, vision),
812
- "X-Initiator": initiator
823
+ ...copilotHeaders(state, requestId, vision),
824
+ "x-initiator": initiator
813
825
  };
826
+ if (subagentMarker) {
827
+ headers["x-initiator"] = "agent";
828
+ headers["x-interaction-type"] = "conversation-subagent";
829
+ }
830
+ if (sessionId) headers["x-interaction-id"] = sessionId;
814
831
  payload.service_tier = null;
815
832
  const response = await fetch(`${copilotBaseUrl(state)}/responses`, {
816
833
  method: "POST",
@@ -828,6 +845,8 @@ const createResponses = async (payload, { vision, initiator }) => {
828
845
  //#endregion
829
846
  //#region src/routes/messages/responses-translation.ts
830
847
  const MESSAGE_TYPE = "message";
848
+ const COMPACTION_SIGNATURE_PREFIX = "cm1#";
849
+ const COMPACTION_SIGNATURE_SEPARATOR = "@";
831
850
  const THINKING_TEXT$1 = "Thinking...";
832
851
  const translateAnthropicMessagesToResponsesPayload = (payload) => {
833
852
  const input = [];
@@ -858,6 +877,23 @@ const translateAnthropicMessagesToResponsesPayload = (payload) => {
858
877
  include: ["reasoning.encrypted_content"]
859
878
  };
860
879
  };
880
+ const encodeCompactionCarrierSignature = (compaction) => {
881
+ return `${COMPACTION_SIGNATURE_PREFIX}${compaction.encrypted_content}${COMPACTION_SIGNATURE_SEPARATOR}${compaction.id}`;
882
+ };
883
+ const decodeCompactionCarrierSignature = (signature) => {
884
+ if (signature.startsWith(COMPACTION_SIGNATURE_PREFIX)) {
885
+ const raw = signature.slice(4);
886
+ const separatorIndex = raw.indexOf(COMPACTION_SIGNATURE_SEPARATOR);
887
+ if (separatorIndex <= 0 || separatorIndex === raw.length - 1) return;
888
+ const encrypted_content = raw.slice(0, separatorIndex);
889
+ const id = raw.slice(separatorIndex + 1);
890
+ if (!encrypted_content) return;
891
+ return {
892
+ id,
893
+ encrypted_content
894
+ };
895
+ }
896
+ };
861
897
  const translateMessage = (message, model, applyPhase) => {
862
898
  if (message.role === "user") return translateUserMessage(message);
863
899
  return translateAssistantMessage(message, model, applyPhase);
@@ -894,13 +930,24 @@ const translateAssistantMessage = (message, model, applyPhase) => {
894
930
  items.push(createFunctionToolCall(block));
895
931
  continue;
896
932
  }
897
- if (block.type === "thinking" && block.signature && block.signature.includes("@")) {
898
- flushPendingContent(pendingContent, items, {
899
- role: "assistant",
900
- phase: assistantPhase
901
- });
902
- items.push(createReasoningContent(block));
903
- continue;
933
+ if (block.type === "thinking" && block.signature) {
934
+ const compactionContent = createCompactionContent(block);
935
+ if (compactionContent) {
936
+ flushPendingContent(pendingContent, items, {
937
+ role: "assistant",
938
+ phase: assistantPhase
939
+ });
940
+ items.push(compactionContent);
941
+ continue;
942
+ }
943
+ if (block.signature.includes("@")) {
944
+ flushPendingContent(pendingContent, items, {
945
+ role: "assistant",
946
+ phase: assistantPhase
947
+ });
948
+ items.push(createReasoningContent(block));
949
+ continue;
950
+ }
904
951
  }
905
952
  const converted = translateAssistantContentBlock(block);
906
953
  if (converted) pendingContent.push(converted);
@@ -960,9 +1007,7 @@ const createImageContent = (block) => ({
960
1007
  detail: "auto"
961
1008
  });
962
1009
  const createReasoningContent = (block) => {
963
- const array = block.signature.split("@");
964
- const signature = array[0];
965
- const id = array[1];
1010
+ const { encryptedContent, id } = parseReasoningSignature(block.signature);
966
1011
  const thinking = block.thinking === THINKING_TEXT$1 ? "" : block.thinking;
967
1012
  return {
968
1013
  id,
@@ -971,7 +1016,27 @@ const createReasoningContent = (block) => {
971
1016
  type: "summary_text",
972
1017
  text: thinking
973
1018
  }] : [],
974
- encrypted_content: signature
1019
+ encrypted_content: encryptedContent
1020
+ };
1021
+ };
1022
+ const createCompactionContent = (block) => {
1023
+ const compaction = decodeCompactionCarrierSignature(block.signature);
1024
+ if (!compaction) return;
1025
+ return {
1026
+ id: compaction.id,
1027
+ type: "compaction",
1028
+ encrypted_content: compaction.encrypted_content
1029
+ };
1030
+ };
1031
+ const parseReasoningSignature = (signature) => {
1032
+ const splitIndex = signature.lastIndexOf("@");
1033
+ if (splitIndex <= 0 || splitIndex === signature.length - 1) return {
1034
+ encryptedContent: signature,
1035
+ id: ""
1036
+ };
1037
+ return {
1038
+ encryptedContent: signature.slice(0, splitIndex),
1039
+ id: signature.slice(splitIndex + 1)
975
1040
  };
976
1041
  };
977
1042
  const createFunctionToolCall = (block) => ({
@@ -1062,6 +1127,11 @@ const mapOutputToAnthropicContent = (output) => {
1062
1127
  });
1063
1128
  break;
1064
1129
  }
1130
+ case "compaction": {
1131
+ const compactionBlock = createCompactionThinkingBlock(item);
1132
+ if (compactionBlock) contentBlocks.push(compactionBlock);
1133
+ break;
1134
+ }
1065
1135
  default: {
1066
1136
  const combinedText = combineMessageTextContent(item.content);
1067
1137
  if (combinedText.length > 0) contentBlocks.push({
@@ -1119,6 +1189,17 @@ const createToolUseContentBlock = (call) => {
1119
1189
  input
1120
1190
  };
1121
1191
  };
1192
+ const createCompactionThinkingBlock = (item) => {
1193
+ if (!item.id || !item.encrypted_content) return null;
1194
+ return {
1195
+ type: "thinking",
1196
+ thinking: THINKING_TEXT$1,
1197
+ signature: encodeCompactionCarrierSignature({
1198
+ id: item.id,
1199
+ encrypted_content: item.encrypted_content
1200
+ })
1201
+ };
1202
+ };
1122
1203
  const parseFunctionCallArguments = (rawArguments) => {
1123
1204
  if (typeof rawArguments !== "string" || rawArguments.trim().length === 0) return {};
1124
1205
  try {
@@ -1281,8 +1362,34 @@ const handleOutputItemAdded$1 = (rawEvent, state$1) => {
1281
1362
  const handleOutputItemDone$1 = (rawEvent, state$1) => {
1282
1363
  const events$1 = new Array();
1283
1364
  const item = rawEvent.item;
1284
- if (item.type !== "reasoning") return events$1;
1365
+ const itemType = item.type;
1285
1366
  const outputIndex = rawEvent.output_index;
1367
+ if (itemType === "compaction") {
1368
+ if (!item.id || !item.encrypted_content) return events$1;
1369
+ const blockIndex$1 = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
1370
+ if (!state$1.blockHasDelta.has(blockIndex$1)) events$1.push({
1371
+ type: "content_block_delta",
1372
+ index: blockIndex$1,
1373
+ delta: {
1374
+ type: "thinking_delta",
1375
+ thinking: THINKING_TEXT$1
1376
+ }
1377
+ });
1378
+ events$1.push({
1379
+ type: "content_block_delta",
1380
+ index: blockIndex$1,
1381
+ delta: {
1382
+ type: "signature_delta",
1383
+ signature: encodeCompactionCarrierSignature({
1384
+ id: item.id,
1385
+ encrypted_content: item.encrypted_content
1386
+ })
1387
+ }
1388
+ });
1389
+ state$1.blockHasDelta.add(blockIndex$1);
1390
+ return events$1;
1391
+ }
1392
+ if (itemType !== "reasoning") return events$1;
1286
1393
  const blockIndex = openThinkingBlockIfNeeded(state$1, outputIndex, events$1);
1287
1394
  const signature = (item.encrypted_content ?? "") + "@" + item.id;
1288
1395
  if (signature) {
@@ -1620,6 +1727,31 @@ const hasAgentInitiator = (payload) => {
1620
1727
  const hasVisionInput = (payload) => {
1621
1728
  return getPayloadItems(payload).some((item) => containsVisionContent(item));
1622
1729
  };
1730
+ const resolveResponsesCompactThreshold = (maxPromptTokens) => {
1731
+ if (typeof maxPromptTokens === "number" && maxPromptTokens > 0) return Math.floor(maxPromptTokens * .9);
1732
+ return 5e4;
1733
+ };
1734
+ const createCompactionContextManagement = (compactThreshold) => [{
1735
+ type: "compaction",
1736
+ compact_threshold: compactThreshold
1737
+ }];
1738
+ const applyResponsesApiContextManagement = (payload, maxPromptTokens) => {
1739
+ if (payload.context_management !== void 0) return;
1740
+ if (!isResponsesApiContextManagementModel(payload.model)) return;
1741
+ payload.context_management = createCompactionContextManagement(resolveResponsesCompactThreshold(maxPromptTokens));
1742
+ };
1743
+ const compactInputByLatestCompaction = (payload) => {
1744
+ if (!Array.isArray(payload.input) || payload.input.length === 0) return;
1745
+ const latestCompactionMessageIndex = getLatestCompactionMessageIndex(payload.input);
1746
+ if (latestCompactionMessageIndex === void 0) return;
1747
+ payload.input = payload.input.slice(latestCompactionMessageIndex);
1748
+ };
1749
+ const getLatestCompactionMessageIndex = (input) => {
1750
+ for (let index = input.length - 1; index >= 0; index -= 1) if (isCompactionInputItem(input[index])) return index;
1751
+ };
1752
+ const isCompactionInputItem = (value) => {
1753
+ return "type" in value && typeof value.type === "string" && value.type === "compaction";
1754
+ };
1623
1755
  const getPayloadItems = (payload) => {
1624
1756
  const result = [];
1625
1757
  const { input } = payload;
@@ -1661,11 +1793,15 @@ const createMessages = async (payload, anthropicBetaHeader, options) => {
1661
1793
  let isInitiateRequest = false;
1662
1794
  const lastMessage = payload.messages.at(-1);
1663
1795
  if (lastMessage?.role === "user") isInitiateRequest = Array.isArray(lastMessage.content) ? lastMessage.content.some((block) => block.type !== "tool_result") : true;
1664
- const initiator = options?.initiator ?? (isInitiateRequest ? "user" : "agent");
1665
1796
  const headers = {
1666
- ...copilotHeaders(state, enableVision),
1667
- "X-Initiator": initiator
1797
+ ...copilotHeaders(state, options.requestId, enableVision),
1798
+ "x-initiator": isInitiateRequest ? "user" : "agent"
1668
1799
  };
1800
+ if (options.subagentMarker) {
1801
+ headers["x-initiator"] = "agent";
1802
+ headers["x-interaction-type"] = "conversation-subagent";
1803
+ }
1804
+ if (options.sessionId) headers["x-interaction-id"] = options.sessionId;
1669
1805
  const anthropicBeta = buildAnthropicBetaHeader(anthropicBetaHeader, payload.thinking);
1670
1806
  if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
1671
1807
  const response = await fetch(`${copilotBaseUrl(state)}/v1/messages`, {
@@ -1985,8 +2121,9 @@ async function handleCompletion(c) {
1985
2121
  const anthropicPayload = await c.req.json();
1986
2122
  logger$2.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
1987
2123
  const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
1988
- const initiatorOverride = subagentMarker ? "agent" : void 0;
1989
2124
  if (subagentMarker) logger$2.debug("Detected Subagent marker:", JSON.stringify(subagentMarker));
2125
+ const sessionId = getRootSessionId(anthropicPayload, c);
2126
+ logger$2.debug("Extracted session ID:", sessionId);
1990
2127
  const isCompact = isCompactRequest(anthropicPayload);
1991
2128
  const anthropicBeta = c.req.header("anthropic-beta");
1992
2129
  logger$2.debug("Anthropic Beta header:", anthropicBeta);
@@ -1996,22 +2133,40 @@ async function handleCompletion(c) {
1996
2133
  logger$2.debug("Is compact request:", isCompact);
1997
2134
  if (shouldCompactUseSmallModel()) anthropicPayload.model = getSmallModel();
1998
2135
  } else mergeToolResultForClaude(anthropicPayload);
2136
+ const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
2137
+ logger$2.debug("Generated request ID:", requestId);
1999
2138
  if (state.manualApprove) await awaitApproval();
2000
2139
  const selectedModel = state.models?.data.find((m) => m.id === anthropicPayload.model);
2001
2140
  if (shouldUseMessagesApi(selectedModel)) return await handleWithMessagesApi(c, anthropicPayload, {
2002
2141
  anthropicBetaHeader: anthropicBeta,
2003
- initiatorOverride,
2004
- selectedModel
2142
+ subagentMarker,
2143
+ selectedModel,
2144
+ requestId,
2145
+ sessionId
2146
+ });
2147
+ if (shouldUseResponsesApi(selectedModel)) return await handleWithResponsesApi(c, anthropicPayload, {
2148
+ subagentMarker,
2149
+ selectedModel,
2150
+ requestId,
2151
+ sessionId
2152
+ });
2153
+ return await handleWithChatCompletions(c, anthropicPayload, {
2154
+ subagentMarker,
2155
+ requestId,
2156
+ sessionId
2005
2157
  });
2006
- if (shouldUseResponsesApi(selectedModel)) return await handleWithResponsesApi(c, anthropicPayload, initiatorOverride);
2007
- return await handleWithChatCompletions(c, anthropicPayload, initiatorOverride);
2008
2158
  }
2009
2159
  const RESPONSES_ENDPOINT$1 = "/responses";
2010
2160
  const MESSAGES_ENDPOINT = "/v1/messages";
2011
- const handleWithChatCompletions = async (c, anthropicPayload, initiatorOverride) => {
2161
+ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
2162
+ const { subagentMarker, requestId, sessionId } = options;
2012
2163
  const openAIPayload = translateToOpenAI(anthropicPayload);
2013
2164
  logger$2.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
2014
- const response = await createChatCompletions(openAIPayload, { initiator: initiatorOverride });
2165
+ const response = await createChatCompletions(openAIPayload, {
2166
+ subagentMarker,
2167
+ requestId,
2168
+ sessionId
2169
+ });
2015
2170
  if (isNonStreaming(response)) {
2016
2171
  logger$2.debug("Non-streaming response from Copilot:", JSON.stringify(response));
2017
2172
  const anthropicResponse = translateToAnthropic(response);
@@ -2043,13 +2198,19 @@ const handleWithChatCompletions = async (c, anthropicPayload, initiatorOverride)
2043
2198
  }
2044
2199
  });
2045
2200
  };
2046
- const handleWithResponsesApi = async (c, anthropicPayload, initiatorOverride) => {
2201
+ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
2202
+ const { subagentMarker, selectedModel, requestId, sessionId } = options;
2047
2203
  const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload);
2204
+ applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
2205
+ compactInputByLatestCompaction(responsesPayload);
2048
2206
  logger$2.debug("Translated Responses payload:", JSON.stringify(responsesPayload));
2049
2207
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
2050
2208
  const response = await createResponses(responsesPayload, {
2051
2209
  vision,
2052
- initiator: initiatorOverride ?? initiator
2210
+ initiator,
2211
+ subagentMarker,
2212
+ requestId,
2213
+ sessionId
2053
2214
  });
2054
2215
  if (responsesPayload.stream && isAsyncIterable$1(response)) {
2055
2216
  logger$2.debug("Streaming response from Copilot (Responses API)");
@@ -2096,17 +2257,23 @@ const handleWithResponsesApi = async (c, anthropicPayload, initiatorOverride) =>
2096
2257
  return c.json(anthropicResponse);
2097
2258
  };
2098
2259
  const handleWithMessagesApi = async (c, anthropicPayload, options) => {
2099
- const { anthropicBetaHeader, initiatorOverride, selectedModel } = options ?? {};
2260
+ const { anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId } = options;
2100
2261
  for (const msg of anthropicPayload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
2101
2262
  if (block.type !== "thinking") return true;
2102
2263
  return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
2103
2264
  });
2104
- if (selectedModel?.capabilities.supports.adaptive_thinking) {
2265
+ const toolChoice = anthropicPayload.tool_choice;
2266
+ const disableThink = toolChoice?.type === "any" || toolChoice?.type === "tool";
2267
+ if (selectedModel?.capabilities.supports.adaptive_thinking && !disableThink) {
2105
2268
  anthropicPayload.thinking = { type: "adaptive" };
2106
2269
  anthropicPayload.output_config = { effort: getAnthropicEffortForModel(anthropicPayload.model) };
2107
2270
  }
2108
2271
  logger$2.debug("Translated Messages payload:", JSON.stringify(anthropicPayload));
2109
- const response = await createMessages(anthropicPayload, anthropicBetaHeader, { initiator: initiatorOverride });
2272
+ const response = await createMessages(anthropicPayload, anthropicBetaHeader, {
2273
+ subagentMarker,
2274
+ requestId,
2275
+ sessionId
2276
+ });
2110
2277
  if (isAsyncIterable$1(response)) {
2111
2278
  logger$2.debug("Streaming response from Copilot (Messages API)");
2112
2279
  return streamSSE(c, async (stream) => {
@@ -2277,17 +2444,27 @@ const handleResponses = async (c) => {
2277
2444
  await checkRateLimit(state);
2278
2445
  const payload = await c.req.json();
2279
2446
  logger$1.debug("Responses request payload:", JSON.stringify(payload));
2447
+ const requestId = generateRequestIdFromPayload({ messages: payload.input });
2448
+ logger$1.debug("Generated request ID:", requestId);
2449
+ const sessionId = getUUID(requestId);
2450
+ logger$1.debug("Extracted session ID:", sessionId);
2280
2451
  useFunctionApplyPatch(payload);
2281
2452
  removeWebSearchTool(payload);
2282
- if (!((state.models?.data.find((model) => model.id === payload.model))?.supported_endpoints?.includes(RESPONSES_ENDPOINT) ?? false)) return c.json({ error: {
2453
+ compactInputByLatestCompaction(payload);
2454
+ const selectedModel = state.models?.data.find((model) => model.id === payload.model);
2455
+ if (!(selectedModel?.supported_endpoints?.includes(RESPONSES_ENDPOINT) ?? false)) return c.json({ error: {
2283
2456
  message: "This model does not support the responses endpoint. Please choose a different model.",
2284
2457
  type: "invalid_request_error"
2285
2458
  } }, 400);
2459
+ applyResponsesApiContextManagement(payload, selectedModel?.capabilities.limits.max_prompt_tokens);
2460
+ logger$1.debug("Translated Responses payload:", JSON.stringify(payload));
2286
2461
  const { vision, initiator } = getResponsesRequestOptions(payload);
2287
2462
  if (state.manualApprove) await awaitApproval();
2288
2463
  const response = await createResponses(payload, {
2289
2464
  vision,
2290
- initiator
2465
+ initiator,
2466
+ requestId,
2467
+ sessionId
2291
2468
  });
2292
2469
  if (isStreamingRequested(payload) && isAsyncIterable(response)) {
2293
2470
  logger$1.debug("Forwarding native Responses stream");
@@ -2410,4 +2587,4 @@ server.route("/v1/messages", messageRoutes);
2410
2587
 
2411
2588
  //#endregion
2412
2589
  export { server };
2413
- //# sourceMappingURL=server-BHzEoq4-.js.map
2590
+ //# sourceMappingURL=server-BPTBrSfO.js.map