@jeffreycao/copilot-api 1.5.2 → 1.5.3-beta.1

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,5 +1,5 @@
1
1
  import { PATHS } from "./paths-Cla6y5eD.js";
2
- import { HTTPError, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getCopilotUsage, getRootSessionId, getUUID, isNullish, parseUserIdMetadata, prepareForCompact, prepareInteractionHeaders, requestContext, resolveTraceId, sleep, state } from "./utils-B_0M2nQy.js";
2
+ import { HTTPError, cacheModels, copilotBaseUrl, copilotHeaders, forwardError, generateRequestIdFromPayload, getCopilotUsage, getRootSessionId, getUUID, isNullish, parseUserIdMetadata, prepareForCompact, prepareInteractionHeaders, prepareMessageProxyHeaders, requestContext, resolveTraceId, sleep, state } from "./utils-DDQKGVRQ.js";
3
3
  import { getAnthropicApiKey, getClaudeTokenMultiplier, getConfig, getExtraPromptForModel, getProviderConfig, getReasoningEffortForModel, getSmallModel, isMessagesApiEnabled, isResponsesApiContextManagementModel, isResponsesApiWebSearchEnabled } from "./config-EvlyFBSs.js";
4
4
  import consola from "consola";
5
5
  import path from "node:path";
@@ -86,6 +86,9 @@ const FLUSH_INTERVAL_MS = 1e3;
86
86
  const MAX_BUFFER_SIZE = 100;
87
87
  const logStreams = /* @__PURE__ */ new Map();
88
88
  const logBuffers = /* @__PURE__ */ new Map();
89
+ let runtimeInitialized = false;
90
+ let flushInterval;
91
+ let cleanupInterval;
89
92
  const ensureLogDirectory = () => {
90
93
  if (!fs.existsSync(LOG_DIR)) fs.mkdirSync(LOG_DIR, { recursive: true });
91
94
  };
@@ -116,17 +119,8 @@ const sanitizeName = (name) => {
116
119
  const normalized = name.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replaceAll(/^-+|-+$/g, "");
117
120
  return normalized === "" ? "handler" : normalized;
118
121
  };
119
- const getLogStream = (filePath) => {
120
- let stream = logStreams.get(filePath);
121
- if (!stream || stream.destroyed) {
122
- stream = fs.createWriteStream(filePath, { flags: "a" });
123
- logStreams.set(filePath, stream);
124
- stream.on("error", (error) => {
125
- console.warn("Log stream error", error);
126
- logStreams.delete(filePath);
127
- });
128
- }
129
- return stream;
122
+ const maybeUnref = (timer) => {
123
+ timer.unref();
130
124
  };
131
125
  const flushBuffer = (filePath) => {
132
126
  const buffer = logBuffers.get(filePath);
@@ -141,6 +135,52 @@ const flushBuffer = (filePath) => {
141
135
  const flushAllBuffers = () => {
142
136
  for (const filePath of logBuffers.keys()) flushBuffer(filePath);
143
137
  };
138
+ const cleanup = () => {
139
+ if (flushInterval) {
140
+ clearInterval(flushInterval);
141
+ flushInterval = void 0;
142
+ }
143
+ if (cleanupInterval) {
144
+ clearInterval(cleanupInterval);
145
+ cleanupInterval = void 0;
146
+ }
147
+ flushAllBuffers();
148
+ for (const stream of logStreams.values()) stream.end();
149
+ logStreams.clear();
150
+ logBuffers.clear();
151
+ };
152
+ const initializeLoggerRuntime = () => {
153
+ if (runtimeInitialized) return;
154
+ runtimeInitialized = true;
155
+ ensureLogDirectory();
156
+ cleanupOldLogs();
157
+ flushInterval = setInterval(flushAllBuffers, FLUSH_INTERVAL_MS);
158
+ maybeUnref(flushInterval);
159
+ cleanupInterval = setInterval(cleanupOldLogs, CLEANUP_INTERVAL_MS);
160
+ maybeUnref(cleanupInterval);
161
+ process.once("exit", cleanup);
162
+ process.once("SIGINT", () => {
163
+ cleanup();
164
+ process.exit(0);
165
+ });
166
+ process.once("SIGTERM", () => {
167
+ cleanup();
168
+ process.exit(0);
169
+ });
170
+ };
171
+ const getLogStream = (filePath) => {
172
+ initializeLoggerRuntime();
173
+ let stream = logStreams.get(filePath);
174
+ if (!stream || stream.destroyed) {
175
+ stream = fs.createWriteStream(filePath, { flags: "a" });
176
+ logStreams.set(filePath, stream);
177
+ stream.on("error", (error) => {
178
+ console.warn("Log stream error", error);
179
+ logStreams.delete(filePath);
180
+ });
181
+ }
182
+ return stream;
183
+ };
144
184
  const appendLine = (filePath, line) => {
145
185
  let buffer = logBuffers.get(filePath);
146
186
  if (!buffer) {
@@ -150,35 +190,23 @@ const appendLine = (filePath, line) => {
150
190
  buffer.push(line);
151
191
  if (buffer.length >= MAX_BUFFER_SIZE) flushBuffer(filePath);
152
192
  };
153
- setInterval(flushAllBuffers, FLUSH_INTERVAL_MS);
154
- const cleanup = () => {
155
- flushAllBuffers();
156
- for (const stream of logStreams.values()) stream.end();
157
- logStreams.clear();
158
- logBuffers.clear();
193
+ const debugLazy = (logger$7, factory) => {
194
+ if (!state.verbose) return;
195
+ logger$7.debug(...factory());
196
+ };
197
+ const debugJson = (logger$7, label, value) => {
198
+ debugLazy(logger$7, () => [label, JSON.stringify(value)]);
199
+ };
200
+ const debugJsonTail = (logger$7, label, { value, tailLength = 400 }) => {
201
+ debugLazy(logger$7, () => [label, JSON.stringify(value).slice(-tailLength)]);
159
202
  };
160
- process.on("exit", cleanup);
161
- process.on("SIGINT", () => {
162
- cleanup();
163
- process.exit(0);
164
- });
165
- process.on("SIGTERM", () => {
166
- cleanup();
167
- process.exit(0);
168
- });
169
- let lastCleanup = 0;
170
203
  const createHandlerLogger = (name) => {
171
- ensureLogDirectory();
172
204
  const sanitizedName = sanitizeName(name);
173
205
  const instance = consola.withTag(name);
174
206
  if (state.verbose) instance.level = 5;
175
207
  instance.setReporters([]);
176
208
  instance.addReporter({ log(logObj) {
177
- ensureLogDirectory();
178
- if (Date.now() - lastCleanup > CLEANUP_INTERVAL_MS) {
179
- cleanupOldLogs();
180
- lastCleanup = Date.now();
181
- }
209
+ initializeLoggerRuntime();
182
210
  const traceId = requestContext.getStore()?.traceId;
183
211
  const date = logObj.date;
184
212
  const dateKey = date.toLocaleDateString("sv-SE");
@@ -469,7 +497,10 @@ const logger$6 = createHandlerLogger("chat-completions-handler");
469
497
  async function handleCompletion$1(c) {
470
498
  await checkRateLimit(state);
471
499
  let payload = await c.req.json();
472
- logger$6.debug("Request payload:", JSON.stringify(payload).slice(-400));
500
+ debugJsonTail(logger$6, "Request payload:", {
501
+ value: payload,
502
+ tailLength: 400
503
+ });
473
504
  const selectedModel = state.models?.data.find((model) => model.id === payload.model);
474
505
  try {
475
506
  if (selectedModel) {
@@ -485,7 +516,7 @@ async function handleCompletion$1(c) {
485
516
  ...payload,
486
517
  max_tokens: selectedModel?.capabilities.limits.max_output_tokens
487
518
  };
488
- logger$6.debug("Set max_tokens to:", JSON.stringify(payload.max_tokens));
519
+ debugJson(logger$6, "Set max_tokens to:", payload.max_tokens);
489
520
  }
490
521
  const requestId = generateRequestIdFromPayload(payload);
491
522
  logger$6.debug("Generated request ID:", requestId);
@@ -496,13 +527,13 @@ async function handleCompletion$1(c) {
496
527
  sessionId
497
528
  });
498
529
  if (isNonStreaming$1(response)) {
499
- logger$6.debug("Non-streaming response:", JSON.stringify(response));
530
+ debugJson(logger$6, "Non-streaming response:", response);
500
531
  return c.json(response);
501
532
  }
502
533
  logger$6.debug("Streaming response");
503
534
  return streamSSE(c, async (stream) => {
504
535
  for await (const chunk of response) {
505
- logger$6.debug("Streaming chunk:", JSON.stringify(chunk));
536
+ debugJson(logger$6, "Streaming chunk:", chunk);
506
537
  await stream.writeSSE(chunk);
507
538
  }
508
539
  });
@@ -1867,6 +1898,8 @@ const createMessages = async (payload, anthropicBetaHeader, options) => {
1867
1898
  };
1868
1899
  prepareInteractionHeaders(options.sessionId, Boolean(options.subagentMarker), headers);
1869
1900
  prepareForCompact(headers, options.isCompact);
1901
+ const { safetyIdentifier, sessionId } = parseUserIdMetadata(payload.metadata?.user_id);
1902
+ if (safetyIdentifier && sessionId) prepareMessageProxyHeaders(headers);
1870
1903
  const anthropicBeta = buildAnthropicBetaHeader(anthropicBetaHeader, payload.thinking);
1871
1904
  if (anthropicBeta) headers["anthropic-beta"] = anthropicBeta;
1872
1905
  const response = await fetch(`${copilotBaseUrl(state)}/v1/messages`, {
@@ -1882,6 +1915,107 @@ const createMessages = async (payload, anthropicBetaHeader, options) => {
1882
1915
  return await response.json();
1883
1916
  };
1884
1917
 
1918
+ //#endregion
1919
+ //#region src/routes/messages/preprocess.ts
1920
+ const compactSystemPromptStart = "You are a helpful AI assistant tasked with summarizing conversations";
1921
+ const compactTextOnlyGuard = "CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.";
1922
+ const compactSummaryPromptStart = "Your task is to create a detailed summary of the conversation so far";
1923
+ const compactMessageSections = ["Pending Tasks:", "Current Work:"];
1924
+ const getAnthropicEffortForModel = (model) => {
1925
+ const reasoningEffort = getReasoningEffortForModel(model);
1926
+ if (reasoningEffort === "xhigh") return "max";
1927
+ if (reasoningEffort === "none" || reasoningEffort === "minimal") return "low";
1928
+ return reasoningEffort;
1929
+ };
1930
+ const getCompactCandidateText = (message) => {
1931
+ if (message.role !== "user") return "";
1932
+ if (typeof message.content === "string") return message.content;
1933
+ 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");
1934
+ };
1935
+ const isCompactMessage = (lastMessage) => {
1936
+ const text = getCompactCandidateText(lastMessage);
1937
+ if (!text) return false;
1938
+ return text.includes(compactTextOnlyGuard) && text.includes(compactSummaryPromptStart) && compactMessageSections.some((section) => text.includes(section));
1939
+ };
1940
+ const isCompactRequest = (anthropicPayload) => {
1941
+ const lastMessage = anthropicPayload.messages.at(-1);
1942
+ if (lastMessage && isCompactMessage(lastMessage)) return true;
1943
+ const system = anthropicPayload.system;
1944
+ if (typeof system === "string") return system.startsWith(compactSystemPromptStart);
1945
+ if (!Array.isArray(system)) return false;
1946
+ return system.some((msg) => typeof msg.text === "string" && msg.text.startsWith(compactSystemPromptStart));
1947
+ };
1948
+ const mergeContentWithText = (tr, textBlock) => {
1949
+ if (typeof tr.content === "string") return {
1950
+ ...tr,
1951
+ content: `${tr.content}\n\n${textBlock.text}`
1952
+ };
1953
+ return {
1954
+ ...tr,
1955
+ content: [...tr.content, textBlock]
1956
+ };
1957
+ };
1958
+ const mergeContentWithTexts = (tr, textBlocks) => {
1959
+ if (typeof tr.content === "string") {
1960
+ const appendedTexts = textBlocks.map((tb) => tb.text).join("\n\n");
1961
+ return {
1962
+ ...tr,
1963
+ content: `${tr.content}\n\n${appendedTexts}`
1964
+ };
1965
+ }
1966
+ return {
1967
+ ...tr,
1968
+ content: [...tr.content, ...textBlocks]
1969
+ };
1970
+ };
1971
+ const mergeToolResult = (toolResults, textBlocks) => {
1972
+ if (toolResults.length === textBlocks.length) return toolResults.map((tr, i) => mergeContentWithText(tr, textBlocks[i]));
1973
+ const lastIndex = toolResults.length - 1;
1974
+ return toolResults.map((tr, i) => i === lastIndex ? mergeContentWithTexts(tr, textBlocks) : tr);
1975
+ };
1976
+ const mergeToolResultForClaude = (anthropicPayload) => {
1977
+ for (const msg of anthropicPayload.messages) {
1978
+ if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
1979
+ const toolResults = [];
1980
+ const textBlocks = [];
1981
+ let valid = true;
1982
+ for (const block of msg.content) if (block.type === "tool_result") toolResults.push(block);
1983
+ else if (block.type === "text") textBlocks.push(block);
1984
+ else {
1985
+ valid = false;
1986
+ break;
1987
+ }
1988
+ if (!valid || toolResults.length === 0 || textBlocks.length === 0) continue;
1989
+ msg.content = mergeToolResult(toolResults, textBlocks);
1990
+ }
1991
+ };
1992
+ const stripCacheControl = (payload) => {
1993
+ if (Array.isArray(payload.system)) for (const block of payload.system) {
1994
+ const systemBlock = block;
1995
+ const cacheControl = systemBlock.cache_control;
1996
+ if (cacheControl && typeof cacheControl === "object") {
1997
+ const { scope,...rest } = cacheControl;
1998
+ systemBlock.cache_control = rest;
1999
+ }
2000
+ }
2001
+ };
2002
+ const filterAssistantThinkingBlocks = (payload) => {
2003
+ for (const msg of payload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
2004
+ if (block.type !== "thinking") return true;
2005
+ return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
2006
+ });
2007
+ };
2008
+ const prepareMessagesApiPayload = (payload, selectedModel) => {
2009
+ stripCacheControl(payload);
2010
+ filterAssistantThinkingBlocks(payload);
2011
+ const toolChoice = payload.tool_choice;
2012
+ const disableThink = toolChoice?.type === "any" || toolChoice?.type === "tool";
2013
+ if (selectedModel?.capabilities.supports.adaptive_thinking && !disableThink) {
2014
+ payload.thinking = { type: "adaptive" };
2015
+ payload.output_config = { effort: getAnthropicEffortForModel(payload.model) };
2016
+ }
2017
+ };
2018
+
1885
2019
  //#endregion
1886
2020
  //#region src/routes/messages/stream-translation.ts
1887
2021
  function isToolBlockOpen(state$1) {
@@ -2133,105 +2267,11 @@ function closeThinkingBlockIfOpen(state$1, events$1) {
2133
2267
  }
2134
2268
 
2135
2269
  //#endregion
2136
- //#region src/routes/messages/subagent-marker.ts
2137
- const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
2138
- const parseSubagentMarkerFromFirstUser = (payload) => {
2139
- const firstUserMessage = payload.messages.find((msg) => msg.role === "user");
2140
- if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
2141
- for (const block of firstUserMessage.content) {
2142
- if (block.type !== "text") continue;
2143
- const marker = parseSubagentMarkerFromSystemReminder(block.text);
2144
- if (marker) return marker;
2145
- }
2146
- return null;
2147
- };
2148
- const parseSubagentMarkerFromSystemReminder = (text) => {
2149
- const startTag = "<system-reminder>";
2150
- const endTag = "</system-reminder>";
2151
- let searchFrom = 0;
2152
- while (true) {
2153
- const reminderStart = text.indexOf(startTag, searchFrom);
2154
- if (reminderStart === -1) break;
2155
- const contentStart = reminderStart + 17;
2156
- const reminderEnd = text.indexOf(endTag, contentStart);
2157
- if (reminderEnd === -1) break;
2158
- const reminderContent = text.slice(contentStart, reminderEnd);
2159
- const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
2160
- if (markerIndex === -1) {
2161
- searchFrom = reminderEnd + 18;
2162
- continue;
2163
- }
2164
- const markerJson = reminderContent.slice(markerIndex + 19).trim();
2165
- try {
2166
- const parsed = JSON.parse(markerJson);
2167
- if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
2168
- searchFrom = reminderEnd + 18;
2169
- continue;
2170
- }
2171
- return parsed;
2172
- } catch {
2173
- searchFrom = reminderEnd + 18;
2174
- continue;
2175
- }
2176
- }
2177
- return null;
2178
- };
2179
-
2180
- //#endregion
2181
- //#region src/routes/messages/handler.ts
2182
- const logger$5 = createHandlerLogger("messages-handler");
2183
- const compactSystemPromptStart = "You are a helpful AI assistant tasked with summarizing conversations";
2184
- const compactTextOnlyGuard = "CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.";
2185
- const compactSummaryPromptStart = "Your task is to create a detailed summary of the conversation so far";
2186
- const compactMessageSections = ["Pending Tasks:", "Current Work:"];
2187
- async function handleCompletion(c) {
2188
- await checkRateLimit(state);
2189
- const anthropicPayload = await c.req.json();
2190
- logger$5.debug("Anthropic request payload:", JSON.stringify(anthropicPayload));
2191
- const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
2192
- if (subagentMarker) logger$5.debug("Detected Subagent marker:", JSON.stringify(subagentMarker));
2193
- const sessionId = getRootSessionId(anthropicPayload, c);
2194
- logger$5.debug("Extracted session ID:", sessionId);
2195
- const isCompact = isCompactRequest(anthropicPayload);
2196
- const anthropicBeta = c.req.header("anthropic-beta");
2197
- logger$5.debug("Anthropic Beta header:", anthropicBeta);
2198
- const noTools = !anthropicPayload.tools || anthropicPayload.tools.length === 0;
2199
- if (anthropicBeta && noTools && !isCompact) anthropicPayload.model = getSmallModel();
2200
- if (isCompact) logger$5.debug("Is compact request:", isCompact);
2201
- else mergeToolResultForClaude(anthropicPayload);
2202
- const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
2203
- logger$5.debug("Generated request ID:", requestId);
2204
- if (state.manualApprove) await awaitApproval();
2205
- const selectedModel = findEndpointModel(anthropicPayload.model);
2206
- anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
2207
- if (shouldUseMessagesApi(selectedModel)) return await handleWithMessagesApi(c, anthropicPayload, {
2208
- anthropicBetaHeader: anthropicBeta,
2209
- subagentMarker,
2210
- selectedModel,
2211
- requestId,
2212
- sessionId,
2213
- isCompact
2214
- });
2215
- if (shouldUseResponsesApi(selectedModel)) return await handleWithResponsesApi(c, anthropicPayload, {
2216
- subagentMarker,
2217
- selectedModel,
2218
- requestId,
2219
- sessionId,
2220
- isCompact
2221
- });
2222
- return await handleWithChatCompletions(c, anthropicPayload, {
2223
- subagentMarker,
2224
- requestId,
2225
- sessionId,
2226
- isCompact
2227
- });
2228
- }
2229
- const RESPONSES_ENDPOINT$1 = "/responses";
2230
- const MESSAGES_ENDPOINT = "/v1/messages";
2270
+ //#region src/routes/messages/api-flows.ts
2231
2271
  const handleWithChatCompletions = async (c, anthropicPayload, options) => {
2232
- const { subagentMarker, requestId, sessionId, isCompact } = options;
2272
+ const { logger: logger$7, subagentMarker, requestId, sessionId, isCompact } = options;
2233
2273
  const openAIPayload = translateToOpenAI(anthropicPayload);
2234
- logger$5.debug("Translated OpenAI request payload:", JSON.stringify(openAIPayload));
2274
+ debugJson(logger$7, "Translated OpenAI request payload:", openAIPayload);
2235
2275
  const response = await createChatCompletions(openAIPayload, {
2236
2276
  subagentMarker,
2237
2277
  requestId,
@@ -2239,12 +2279,12 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
2239
2279
  isCompact
2240
2280
  });
2241
2281
  if (isNonStreaming(response)) {
2242
- logger$5.debug("Non-streaming response from Copilot:", JSON.stringify(response));
2282
+ debugJson(logger$7, "Non-streaming response from Copilot:", response);
2243
2283
  const anthropicResponse = translateToAnthropic(response);
2244
- logger$5.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
2284
+ debugJson(logger$7, "Translated Anthropic response:", anthropicResponse);
2245
2285
  return c.json(anthropicResponse);
2246
2286
  }
2247
- logger$5.debug("Streaming response from Copilot");
2287
+ logger$7.debug("Streaming response from Copilot");
2248
2288
  return streamSSE(c, async (stream) => {
2249
2289
  const streamState = {
2250
2290
  messageStartSent: false,
@@ -2254,27 +2294,28 @@ const handleWithChatCompletions = async (c, anthropicPayload, options) => {
2254
2294
  thinkingBlockOpen: false
2255
2295
  };
2256
2296
  for await (const rawEvent of response) {
2257
- logger$5.debug("Copilot raw stream event:", JSON.stringify(rawEvent));
2297
+ debugJson(logger$7, "Copilot raw stream event:", rawEvent);
2258
2298
  if (rawEvent.data === "[DONE]") break;
2259
2299
  if (!rawEvent.data) continue;
2260
2300
  const chunk = JSON.parse(rawEvent.data);
2261
2301
  const events$1 = translateChunkToAnthropicEvents(chunk, streamState);
2262
2302
  for (const event of events$1) {
2263
- logger$5.debug("Translated Anthropic event:", JSON.stringify(event));
2303
+ const eventData = JSON.stringify(event);
2304
+ debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
2264
2305
  await stream.writeSSE({
2265
2306
  event: event.type,
2266
- data: JSON.stringify(event)
2307
+ data: eventData
2267
2308
  });
2268
2309
  }
2269
2310
  }
2270
2311
  });
2271
2312
  };
2272
2313
  const handleWithResponsesApi = async (c, anthropicPayload, options) => {
2273
- const { subagentMarker, selectedModel, requestId, sessionId, isCompact } = options;
2314
+ const { logger: logger$7, subagentMarker, selectedModel, requestId, sessionId, isCompact } = options;
2274
2315
  const responsesPayload = translateAnthropicMessagesToResponsesPayload(anthropicPayload);
2275
2316
  applyResponsesApiContextManagement(responsesPayload, selectedModel?.capabilities.limits.max_prompt_tokens);
2276
2317
  compactInputByLatestCompaction(responsesPayload);
2277
- logger$5.debug("Translated Responses payload:", JSON.stringify(responsesPayload));
2318
+ debugJson(logger$7, "Translated Responses payload:", responsesPayload);
2278
2319
  const { vision, initiator } = getResponsesRequestOptions(responsesPayload);
2279
2320
  const response = await createResponses(responsesPayload, {
2280
2321
  vision,
@@ -2285,7 +2326,7 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
2285
2326
  isCompact
2286
2327
  });
2287
2328
  if (responsesPayload.stream && isAsyncIterable$1(response)) {
2288
- logger$5.debug("Streaming response from Copilot (Responses API)");
2329
+ logger$7.debug("Streaming response from Copilot (Responses API)");
2289
2330
  return streamSSE(c, async (stream) => {
2290
2331
  const streamState = createResponsesStreamState();
2291
2332
  for await (const chunk of response) {
@@ -2298,23 +2339,23 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
2298
2339
  }
2299
2340
  const data = chunk.data;
2300
2341
  if (!data) continue;
2301
- logger$5.debug("Responses raw stream event:", data);
2342
+ debugLazy(logger$7, () => ["Responses raw stream event:", data]);
2302
2343
  const events$1 = translateResponsesStreamEvent(JSON.parse(data), streamState);
2303
2344
  for (const event of events$1) {
2304
2345
  const eventData = JSON.stringify(event);
2305
- logger$5.debug("Translated Anthropic event:", eventData);
2346
+ debugLazy(logger$7, () => ["Translated Anthropic event:", eventData]);
2306
2347
  await stream.writeSSE({
2307
2348
  event: event.type,
2308
2349
  data: eventData
2309
2350
  });
2310
2351
  }
2311
2352
  if (streamState.messageCompleted) {
2312
- logger$5.debug("Message completed, ending stream");
2353
+ logger$7.debug("Message completed, ending stream");
2313
2354
  break;
2314
2355
  }
2315
2356
  }
2316
2357
  if (!streamState.messageCompleted) {
2317
- logger$5.warn("Responses stream ended without completion; sending error event");
2358
+ logger$7.warn("Responses stream ended without completion; sending error event");
2318
2359
  const errorEvent = buildErrorEvent("Responses stream ended without completion");
2319
2360
  await stream.writeSSE({
2320
2361
  event: errorEvent.type,
@@ -2323,25 +2364,18 @@ const handleWithResponsesApi = async (c, anthropicPayload, options) => {
2323
2364
  }
2324
2365
  });
2325
2366
  }
2326
- logger$5.debug("Non-streaming Responses result:", JSON.stringify(response).slice(-400));
2367
+ debugJsonTail(logger$7, "Non-streaming Responses result:", {
2368
+ value: response,
2369
+ tailLength: 400
2370
+ });
2327
2371
  const anthropicResponse = translateResponsesResultToAnthropic(response);
2328
- logger$5.debug("Translated Anthropic response:", JSON.stringify(anthropicResponse));
2372
+ debugJson(logger$7, "Translated Anthropic response:", anthropicResponse);
2329
2373
  return c.json(anthropicResponse);
2330
2374
  };
2331
2375
  const handleWithMessagesApi = async (c, anthropicPayload, options) => {
2332
- const { anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId, isCompact } = options;
2333
- stripCacheControl(anthropicPayload);
2334
- for (const msg of anthropicPayload.messages) if (msg.role === "assistant" && Array.isArray(msg.content)) msg.content = msg.content.filter((block) => {
2335
- if (block.type !== "thinking") return true;
2336
- return block.thinking && block.thinking !== "Thinking..." && block.signature && !block.signature.includes("@");
2337
- });
2338
- const toolChoice = anthropicPayload.tool_choice;
2339
- const disableThink = toolChoice?.type === "any" || toolChoice?.type === "tool";
2340
- if (selectedModel?.capabilities.supports.adaptive_thinking && !disableThink) {
2341
- anthropicPayload.thinking = { type: "adaptive" };
2342
- anthropicPayload.output_config = { effort: getAnthropicEffortForModel(anthropicPayload.model) };
2343
- }
2344
- logger$5.debug("Translated Messages payload:", JSON.stringify(anthropicPayload));
2376
+ const { logger: logger$7, anthropicBetaHeader, subagentMarker, selectedModel, requestId, sessionId, isCompact } = options;
2377
+ prepareMessagesApiPayload(anthropicPayload, selectedModel);
2378
+ debugJson(logger$7, "Translated Messages payload:", anthropicPayload);
2345
2379
  const response = await createMessages(anthropicPayload, anthropicBetaHeader, {
2346
2380
  subagentMarker,
2347
2381
  requestId,
@@ -2349,12 +2383,12 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
2349
2383
  isCompact
2350
2384
  });
2351
2385
  if (isAsyncIterable$1(response)) {
2352
- logger$5.debug("Streaming response from Copilot (Messages API)");
2386
+ logger$7.debug("Streaming response from Copilot (Messages API)");
2353
2387
  return streamSSE(c, async (stream) => {
2354
2388
  for await (const event of response) {
2355
2389
  const eventName = event.event;
2356
2390
  const data = event.data ?? "";
2357
- logger$5.debug("Messages raw stream event:", data);
2391
+ debugLazy(logger$7, () => ["Messages raw stream event:", data]);
2358
2392
  await stream.writeSSE({
2359
2393
  event: eventName,
2360
2394
  data
@@ -2362,95 +2396,116 @@ const handleWithMessagesApi = async (c, anthropicPayload, options) => {
2362
2396
  }
2363
2397
  });
2364
2398
  }
2365
- logger$5.debug("Non-streaming Messages result:", JSON.stringify(response).slice(-400));
2399
+ debugJsonTail(logger$7, "Non-streaming Messages result:", {
2400
+ value: response,
2401
+ tailLength: 400
2402
+ });
2366
2403
  return c.json(response);
2367
2404
  };
2368
- const shouldUseResponsesApi = (selectedModel) => {
2369
- return selectedModel?.supported_endpoints?.includes(RESPONSES_ENDPOINT$1) ?? false;
2370
- };
2371
- const shouldUseMessagesApi = (selectedModel) => {
2372
- if (!isMessagesApiEnabled()) return false;
2373
- return selectedModel?.supported_endpoints?.includes(MESSAGES_ENDPOINT) ?? false;
2374
- };
2375
2405
  const isNonStreaming = (response) => Object.hasOwn(response, "choices");
2376
2406
  const isAsyncIterable$1 = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
2377
- const getAnthropicEffortForModel = (model) => {
2378
- const reasoningEffort = getReasoningEffortForModel(model);
2379
- if (reasoningEffort === "xhigh") return "max";
2380
- if (reasoningEffort === "none" || reasoningEffort === "minimal") return "low";
2381
- return reasoningEffort;
2382
- };
2383
- const getCompactCandidateText = (message) => {
2384
- if (message.role !== "user") return "";
2385
- if (typeof message.content === "string") return message.content;
2386
- 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");
2387
- };
2388
- const isCompactMessage = (lastMessage) => {
2389
- const text = getCompactCandidateText(lastMessage);
2390
- if (!text) return false;
2391
- return text.includes(compactTextOnlyGuard) && text.includes(compactSummaryPromptStart) && compactMessageSections.some((section) => text.includes(section));
2392
- };
2393
- const isCompactRequest = (anthropicPayload) => {
2394
- const lastMessage = anthropicPayload.messages.at(-1);
2395
- if (lastMessage && isCompactMessage(lastMessage)) return true;
2396
- const system = anthropicPayload.system;
2397
- if (typeof system === "string") return system.startsWith(compactSystemPromptStart);
2398
- if (!Array.isArray(system)) return false;
2399
- return system.some((msg) => typeof msg.text === "string" && msg.text.startsWith(compactSystemPromptStart));
2400
- };
2401
- const mergeContentWithText = (tr, textBlock) => {
2402
- if (typeof tr.content === "string") return {
2403
- ...tr,
2404
- content: `${tr.content}\n\n${textBlock.text}`
2405
- };
2406
- return {
2407
- ...tr,
2408
- content: [...tr.content, textBlock]
2409
- };
2410
- };
2411
- const mergeContentWithTexts = (tr, textBlocks) => {
2412
- if (typeof tr.content === "string") {
2413
- const appendedTexts = textBlocks.map((tb) => tb.text).join("\n\n");
2414
- return {
2415
- ...tr,
2416
- content: `${tr.content}\n\n${appendedTexts}`
2417
- };
2407
+
2408
+ //#endregion
2409
+ //#region src/routes/messages/subagent-marker.ts
2410
+ const subagentMarkerPrefix = "__SUBAGENT_MARKER__";
2411
+ const parseSubagentMarkerFromFirstUser = (payload) => {
2412
+ const firstUserMessage = payload.messages.find((msg) => msg.role === "user");
2413
+ if (!firstUserMessage || !Array.isArray(firstUserMessage.content)) return null;
2414
+ for (const block of firstUserMessage.content) {
2415
+ if (block.type !== "text") continue;
2416
+ const marker = parseSubagentMarkerFromSystemReminder(block.text);
2417
+ if (marker) return marker;
2418
2418
  }
2419
- return {
2420
- ...tr,
2421
- content: [...tr.content, ...textBlocks]
2422
- };
2419
+ return null;
2423
2420
  };
2424
- const mergeToolResultForClaude = (anthropicPayload) => {
2425
- for (const msg of anthropicPayload.messages) {
2426
- if (msg.role !== "user" || !Array.isArray(msg.content)) continue;
2427
- const toolResults = [];
2428
- const textBlocks = [];
2429
- let valid = true;
2430
- for (const block of msg.content) if (block.type === "tool_result") toolResults.push(block);
2431
- else if (block.type === "text") textBlocks.push(block);
2432
- else {
2433
- valid = false;
2434
- break;
2421
+ const parseSubagentMarkerFromSystemReminder = (text) => {
2422
+ const startTag = "<system-reminder>";
2423
+ const endTag = "</system-reminder>";
2424
+ let searchFrom = 0;
2425
+ while (true) {
2426
+ const reminderStart = text.indexOf(startTag, searchFrom);
2427
+ if (reminderStart === -1) break;
2428
+ const contentStart = reminderStart + 17;
2429
+ const reminderEnd = text.indexOf(endTag, contentStart);
2430
+ if (reminderEnd === -1) break;
2431
+ const reminderContent = text.slice(contentStart, reminderEnd);
2432
+ const markerIndex = reminderContent.indexOf(subagentMarkerPrefix);
2433
+ if (markerIndex === -1) {
2434
+ searchFrom = reminderEnd + 18;
2435
+ continue;
2436
+ }
2437
+ const markerJson = reminderContent.slice(markerIndex + 19).trim();
2438
+ try {
2439
+ const parsed = JSON.parse(markerJson);
2440
+ if (!parsed.session_id || !parsed.agent_id || !parsed.agent_type) {
2441
+ searchFrom = reminderEnd + 18;
2442
+ continue;
2443
+ }
2444
+ return parsed;
2445
+ } catch {
2446
+ searchFrom = reminderEnd + 18;
2447
+ continue;
2435
2448
  }
2436
- if (!valid || toolResults.length === 0 || textBlocks.length === 0) continue;
2437
- msg.content = mergeToolResult(toolResults, textBlocks);
2438
2449
  }
2450
+ return null;
2439
2451
  };
2440
- const mergeToolResult = (toolResults, textBlocks) => {
2441
- if (toolResults.length === textBlocks.length) return toolResults.map((tr, i) => mergeContentWithText(tr, textBlocks[i]));
2442
- const lastIndex = toolResults.length - 1;
2443
- return toolResults.map((tr, i) => i === lastIndex ? mergeContentWithTexts(tr, textBlocks) : tr);
2452
+
2453
+ //#endregion
2454
+ //#region src/routes/messages/handler.ts
2455
+ const logger$5 = createHandlerLogger("messages-handler");
2456
+ async function handleCompletion(c) {
2457
+ await checkRateLimit(state);
2458
+ const anthropicPayload = await c.req.json();
2459
+ debugJson(logger$5, "Anthropic request payload:", anthropicPayload);
2460
+ const subagentMarker = parseSubagentMarkerFromFirstUser(anthropicPayload);
2461
+ if (subagentMarker) debugJson(logger$5, "Detected Subagent marker:", subagentMarker);
2462
+ const sessionId = getRootSessionId(anthropicPayload, c);
2463
+ logger$5.debug("Extracted session ID:", sessionId);
2464
+ const isCompact = isCompactRequest(anthropicPayload);
2465
+ const anthropicBeta = c.req.header("anthropic-beta");
2466
+ logger$5.debug("Anthropic Beta header:", anthropicBeta);
2467
+ const noTools = !anthropicPayload.tools || anthropicPayload.tools.length === 0;
2468
+ if (anthropicBeta && noTools && !isCompact) anthropicPayload.model = getSmallModel();
2469
+ if (isCompact) logger$5.debug("Is compact request:", isCompact);
2470
+ else mergeToolResultForClaude(anthropicPayload);
2471
+ const requestId = generateRequestIdFromPayload(anthropicPayload, sessionId);
2472
+ logger$5.debug("Generated request ID:", requestId);
2473
+ if (state.manualApprove) await awaitApproval();
2474
+ const selectedModel = findEndpointModel(anthropicPayload.model);
2475
+ anthropicPayload.model = selectedModel?.id ?? anthropicPayload.model;
2476
+ if (shouldUseMessagesApi(selectedModel)) return await handleWithMessagesApi(c, anthropicPayload, {
2477
+ anthropicBetaHeader: anthropicBeta,
2478
+ subagentMarker,
2479
+ selectedModel,
2480
+ requestId,
2481
+ sessionId,
2482
+ isCompact,
2483
+ logger: logger$5
2484
+ });
2485
+ if (shouldUseResponsesApi(selectedModel)) return await handleWithResponsesApi(c, anthropicPayload, {
2486
+ subagentMarker,
2487
+ selectedModel,
2488
+ requestId,
2489
+ sessionId,
2490
+ isCompact,
2491
+ logger: logger$5
2492
+ });
2493
+ return await handleWithChatCompletions(c, anthropicPayload, {
2494
+ subagentMarker,
2495
+ requestId,
2496
+ sessionId,
2497
+ isCompact,
2498
+ logger: logger$5
2499
+ });
2500
+ }
2501
+ const RESPONSES_ENDPOINT$1 = "/responses";
2502
+ const MESSAGES_ENDPOINT = "/v1/messages";
2503
+ const shouldUseResponsesApi = (selectedModel) => {
2504
+ return selectedModel?.supported_endpoints?.includes(RESPONSES_ENDPOINT$1) ?? false;
2444
2505
  };
2445
- const stripCacheControl = (payload) => {
2446
- if (Array.isArray(payload.system)) for (const block of payload.system) {
2447
- const b = block;
2448
- const cc = b.cache_control;
2449
- if (cc && typeof cc === "object") {
2450
- const { scope,...rest } = cc;
2451
- b.cache_control = rest;
2452
- }
2453
- }
2506
+ const shouldUseMessagesApi = (selectedModel) => {
2507
+ if (!isMessagesApiEnabled()) return false;
2508
+ return selectedModel?.supported_endpoints?.includes(MESSAGES_ENDPOINT) ?? false;
2454
2509
  };
2455
2510
 
2456
2511
  //#endregion
@@ -2620,10 +2675,10 @@ async function handleProviderMessages(c) {
2620
2675
  payload.temperature ??= modelConfig?.temperature;
2621
2676
  payload.top_p ??= modelConfig?.topP;
2622
2677
  payload.top_k ??= modelConfig?.topK;
2623
- logger$3.debug("provider.messages.request", JSON.stringify({
2678
+ debugJson(logger$3, "provider.messages.request", {
2624
2679
  payload,
2625
2680
  provider
2626
- }));
2681
+ });
2627
2682
  const upstreamResponse = await forwardProviderMessages(providerConfig, payload, c.req.raw.headers);
2628
2683
  if (!upstreamResponse.ok) {
2629
2684
  logger$3.error("Failed to create responses", upstreamResponse);
@@ -2666,7 +2721,7 @@ async function handleProviderMessages(c) {
2666
2721
  }
2667
2722
  const jsonBody = await upstreamResponse.json();
2668
2723
  adjustInputTokens(providerConfig, jsonBody.usage);
2669
- logger$3.debug("provider.messages.no_stream result:", JSON.stringify(jsonBody));
2724
+ debugJson(logger$3, "provider.messages.no_stream result:", jsonBody);
2670
2725
  return c.json(jsonBody);
2671
2726
  } catch (error) {
2672
2727
  logger$3.error("provider.messages.error", {
@@ -2679,7 +2734,7 @@ async function handleProviderMessages(c) {
2679
2734
  const adjustInputTokens = (providerConfig, usage) => {
2680
2735
  if (!providerConfig.adjustInputTokens || !usage) return;
2681
2736
  usage.input_tokens = Math.max(0, (usage.input_tokens ?? 0) - (usage.cache_read_input_tokens ?? 0) - (usage.cache_creation_input_tokens ?? 0));
2682
- logger$3.debug("provider.messages.adjusted_usage:", JSON.stringify(usage));
2737
+ debugJson(logger$3, "provider.messages.adjusted_usage:", usage);
2683
2738
  };
2684
2739
 
2685
2740
  //#endregion
@@ -2771,7 +2826,7 @@ const RESPONSES_ENDPOINT = "/responses";
2771
2826
  const handleResponses = async (c) => {
2772
2827
  await checkRateLimit(state);
2773
2828
  const payload = await c.req.json();
2774
- logger$1.debug("Responses request payload:", JSON.stringify(payload));
2829
+ debugJson(logger$1, "Responses request payload:", payload);
2775
2830
  const requestId = generateRequestIdFromPayload({ messages: payload.input });
2776
2831
  logger$1.debug("Generated request ID:", requestId);
2777
2832
  const sessionId = getUUID(requestId);
@@ -2785,7 +2840,7 @@ const handleResponses = async (c) => {
2785
2840
  type: "invalid_request_error"
2786
2841
  } }, 400);
2787
2842
  applyResponsesApiContextManagement(payload, selectedModel?.capabilities.limits.max_prompt_tokens);
2788
- logger$1.debug("Translated Responses payload:", JSON.stringify(payload));
2843
+ debugJson(logger$1, "Translated Responses payload:", payload);
2789
2844
  const { vision, initiator } = getResponsesRequestOptions(payload);
2790
2845
  if (state.manualApprove) await awaitApproval();
2791
2846
  const response = await createResponses(payload, {
@@ -2799,7 +2854,7 @@ const handleResponses = async (c) => {
2799
2854
  return streamSSE(c, async (stream) => {
2800
2855
  const idTracker = createStreamIdTracker();
2801
2856
  for await (const chunk of response) {
2802
- logger$1.debug("Responses stream chunk:", JSON.stringify(chunk));
2857
+ debugJson(logger$1, "Responses stream chunk:", chunk);
2803
2858
  const processedData = fixStreamIds(chunk.data ?? "", chunk.event, idTracker);
2804
2859
  await stream.writeSSE({
2805
2860
  id: chunk.id,
@@ -2809,7 +2864,10 @@ const handleResponses = async (c) => {
2809
2864
  }
2810
2865
  });
2811
2866
  }
2812
- logger$1.debug("Forwarding native Responses result:", JSON.stringify(response).slice(-400));
2867
+ debugJsonTail(logger$1, "Forwarding native Responses result:", {
2868
+ value: response,
2869
+ tailLength: 400
2870
+ });
2813
2871
  return c.json(response);
2814
2872
  };
2815
2873
  const isAsyncIterable = (value) => Boolean(value) && typeof value[Symbol.asyncIterator] === "function";
@@ -2918,4 +2976,4 @@ server.route("/:provider/v1/models", providerModelRoutes);
2918
2976
 
2919
2977
  //#endregion
2920
2978
  export { server };
2921
- //# sourceMappingURL=server-219WLjAn.js.map
2979
+ //# sourceMappingURL=server-DP3qGqqy.js.map