copilot-api-plus 1.1.8 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -1719,9 +1719,14 @@ const createChatCompletions = async (payload) => {
1719
1719
  model: resolvedModel
1720
1720
  } : payload;
1721
1721
  if (resolvedModel !== payload.model) consola.debug(`Model routed: ${payload.model} → ${resolvedModel}`);
1722
+ const supportsReasoning = /^claude-.+-4\.6/.test(resolvedModel);
1723
+ const thinkingPayload = {
1724
+ ...routedPayload,
1725
+ ...!routedPayload.reasoning_effort && supportsReasoning && { reasoning_effort: "high" }
1726
+ };
1722
1727
  const releaseSlot = await modelRouter.acquireSlot(resolvedModel);
1723
1728
  try {
1724
- const result = state.multiAccountEnabled && accountManager.hasAccounts() ? await createWithMultiAccount(routedPayload) : await createWithSingleAccount(routedPayload);
1729
+ const result = state.multiAccountEnabled && accountManager.hasAccounts() ? await createWithMultiAccount(thinkingPayload) : await createWithSingleAccount(thinkingPayload);
1725
1730
  if (Symbol.asyncIterator in result) return wrapGeneratorWithRelease(result, releaseSlot);
1726
1731
  releaseSlot();
1727
1732
  return result;
@@ -1941,8 +1946,9 @@ async function handleCompletion$1(c) {
1941
1946
  if (state.manualApprove) await awaitApproval();
1942
1947
  const response = await createChatCompletions(payload);
1943
1948
  if (isNonStreaming$1(response)) {
1944
- consola.debug("Non-streaming response:", JSON.stringify(response));
1945
- return c.json(response);
1949
+ const mappedResponse = mapReasoningFields(response);
1950
+ consola.debug("Non-streaming response:", JSON.stringify(mappedResponse));
1951
+ return c.json(mappedResponse);
1946
1952
  }
1947
1953
  consola.debug("Streaming response");
1948
1954
  return streamSSE(c, async (stream) => {
@@ -1958,6 +1964,27 @@ async function handleCompletion$1(c) {
1958
1964
  });
1959
1965
  }
1960
1966
  const isNonStreaming$1 = (response) => Object.hasOwn(response, "choices");
1967
+ /**
1968
+ * Map `reasoning_text` (Copilot-specific) to `reasoning_content` (OpenAI-compatible)
1969
+ * so that downstream OpenAI-compatible clients can consume the reasoning output.
1970
+ */
1971
+ function mapReasoningFields(response) {
1972
+ if (!response.choices.some((c) => c.message.reasoning_text)) return response;
1973
+ return {
1974
+ ...response,
1975
+ choices: response.choices.map((choice) => {
1976
+ const msg = choice.message;
1977
+ if (!msg.reasoning_text) return choice;
1978
+ return {
1979
+ ...choice,
1980
+ message: {
1981
+ ...choice.message,
1982
+ reasoning_content: msg.reasoning_text || choice.message.reasoning_content
1983
+ }
1984
+ };
1985
+ })
1986
+ };
1987
+ }
1961
1988
  //#endregion
1962
1989
  //#region src/routes/chat-completions/route.ts
1963
1990
  const completionRoutes = new Hono();
@@ -2217,7 +2244,9 @@ function translateToOpenAI(payload) {
2217
2244
  top_p: payload.top_p,
2218
2245
  user: payload.metadata?.user_id,
2219
2246
  tools: translateAnthropicToolsToOpenAI(payload.tools),
2220
- tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice)
2247
+ tool_choice: translateAnthropicToolChoiceToOpenAI(payload.tool_choice),
2248
+ ...payload.thinking && { thinking: payload.thinking },
2249
+ ...payload.thinking?.type === "enabled" && { reasoning_effort: "high" }
2221
2250
  };
2222
2251
  }
2223
2252
  function translateModelName(model) {
@@ -2354,13 +2383,16 @@ function translateAnthropicToolChoiceToOpenAI(anthropicToolChoice) {
2354
2383
  }
2355
2384
  }
2356
2385
  function translateToAnthropic(response) {
2386
+ const allThinkingBlocks = [];
2357
2387
  const allTextBlocks = [];
2358
2388
  const allToolUseBlocks = [];
2359
2389
  let stopReason = null;
2360
2390
  stopReason = response.choices[0]?.finish_reason ?? stopReason;
2361
2391
  for (const choice of response.choices) {
2392
+ const thinkingBlocks = getAnthropicThinkingBlocks(choice.message.reasoning_content ?? choice.message.reasoning_text);
2362
2393
  const textBlocks = getAnthropicTextBlocks(choice.message.content);
2363
2394
  const toolUseBlocks = getAnthropicToolUseBlocks(choice.message.tool_calls);
2395
+ allThinkingBlocks.push(...thinkingBlocks);
2364
2396
  allTextBlocks.push(...textBlocks);
2365
2397
  allToolUseBlocks.push(...toolUseBlocks);
2366
2398
  if (choice.finish_reason === "tool_calls" || stopReason === "stop") stopReason = choice.finish_reason;
@@ -2370,7 +2402,11 @@ function translateToAnthropic(response) {
2370
2402
  type: "message",
2371
2403
  role: "assistant",
2372
2404
  model: response.model,
2373
- content: [...allTextBlocks, ...allToolUseBlocks],
2405
+ content: [
2406
+ ...allThinkingBlocks,
2407
+ ...allTextBlocks,
2408
+ ...allToolUseBlocks
2409
+ ],
2374
2410
  stop_reason: mapOpenAIStopReasonToAnthropic(stopReason),
2375
2411
  stop_sequence: null,
2376
2412
  usage: {
@@ -2380,6 +2416,13 @@ function translateToAnthropic(response) {
2380
2416
  }
2381
2417
  };
2382
2418
  }
2419
+ function getAnthropicThinkingBlocks(reasoningContent) {
2420
+ if (!reasoningContent) return [];
2421
+ return [{
2422
+ type: "thinking",
2423
+ thinking: reasoningContent
2424
+ }];
2425
+ }
2383
2426
  function getAnthropicTextBlocks(messageContent) {
2384
2427
  if (typeof messageContent === "string") return [{
2385
2428
  type: "text",
@@ -2476,7 +2519,47 @@ function translateChunkToAnthropicEvents(chunk, state) {
2476
2519
  });
2477
2520
  state.messageStartSent = true;
2478
2521
  }
2522
+ const reasoningContent = delta.reasoning_content ?? delta.reasoning_text;
2523
+ if (reasoningContent) {
2524
+ if (state.contentBlockOpen && !state.thinkingBlockOpen) {
2525
+ events.push({
2526
+ type: "content_block_stop",
2527
+ index: state.contentBlockIndex
2528
+ });
2529
+ state.contentBlockIndex++;
2530
+ state.contentBlockOpen = false;
2531
+ }
2532
+ if (!state.thinkingBlockOpen) {
2533
+ events.push({
2534
+ type: "content_block_start",
2535
+ index: state.contentBlockIndex,
2536
+ content_block: {
2537
+ type: "thinking",
2538
+ thinking: ""
2539
+ }
2540
+ });
2541
+ state.contentBlockOpen = true;
2542
+ state.thinkingBlockOpen = true;
2543
+ }
2544
+ events.push({
2545
+ type: "content_block_delta",
2546
+ index: state.contentBlockIndex,
2547
+ delta: {
2548
+ type: "thinking_delta",
2549
+ thinking: reasoningContent
2550
+ }
2551
+ });
2552
+ }
2479
2553
  if (delta.content) {
2554
+ if (state.thinkingBlockOpen) {
2555
+ events.push({
2556
+ type: "content_block_stop",
2557
+ index: state.contentBlockIndex
2558
+ });
2559
+ state.contentBlockIndex++;
2560
+ state.contentBlockOpen = false;
2561
+ state.thinkingBlockOpen = false;
2562
+ }
2480
2563
  if (isToolBlockOpen(state)) {
2481
2564
  events.push({
2482
2565
  type: "content_block_stop",
@@ -2505,44 +2588,55 @@ function translateChunkToAnthropicEvents(chunk, state) {
2505
2588
  }
2506
2589
  });
2507
2590
  }
2508
- if (delta.tool_calls) for (const toolCall of delta.tool_calls) {
2509
- if (toolCall.id && toolCall.function?.name) {
2510
- if (state.contentBlockOpen) {
2511
- events.push({
2512
- type: "content_block_stop",
2513
- index: state.contentBlockIndex
2514
- });
2515
- state.contentBlockIndex++;
2516
- state.contentBlockOpen = false;
2517
- }
2518
- const anthropicBlockIndex = state.contentBlockIndex;
2519
- state.toolCalls[toolCall.index] = {
2520
- id: toolCall.id,
2521
- name: toolCall.function.name,
2522
- anthropicBlockIndex
2523
- };
2591
+ if (delta.tool_calls) {
2592
+ if (state.thinkingBlockOpen) {
2524
2593
  events.push({
2525
- type: "content_block_start",
2526
- index: anthropicBlockIndex,
2527
- content_block: {
2528
- type: "tool_use",
2529
- id: toolCall.id,
2530
- name: toolCall.function.name,
2531
- input: {}
2532
- }
2594
+ type: "content_block_stop",
2595
+ index: state.contentBlockIndex
2533
2596
  });
2534
- state.contentBlockOpen = true;
2535
- }
2536
- if (toolCall.function?.arguments) {
2537
- const toolCallInfo = state.toolCalls[toolCall.index];
2538
- if (toolCallInfo) events.push({
2539
- type: "content_block_delta",
2540
- index: toolCallInfo.anthropicBlockIndex,
2541
- delta: {
2542
- type: "input_json_delta",
2543
- partial_json: toolCall.function.arguments
2597
+ state.contentBlockIndex++;
2598
+ state.contentBlockOpen = false;
2599
+ state.thinkingBlockOpen = false;
2600
+ }
2601
+ for (const toolCall of delta.tool_calls) {
2602
+ if (toolCall.id && toolCall.function?.name) {
2603
+ if (state.contentBlockOpen) {
2604
+ events.push({
2605
+ type: "content_block_stop",
2606
+ index: state.contentBlockIndex
2607
+ });
2608
+ state.contentBlockIndex++;
2609
+ state.contentBlockOpen = false;
2544
2610
  }
2545
- });
2611
+ const anthropicBlockIndex = state.contentBlockIndex;
2612
+ state.toolCalls[toolCall.index] = {
2613
+ id: toolCall.id,
2614
+ name: toolCall.function.name,
2615
+ anthropicBlockIndex
2616
+ };
2617
+ events.push({
2618
+ type: "content_block_start",
2619
+ index: anthropicBlockIndex,
2620
+ content_block: {
2621
+ type: "tool_use",
2622
+ id: toolCall.id,
2623
+ name: toolCall.function.name,
2624
+ input: {}
2625
+ }
2626
+ });
2627
+ state.contentBlockOpen = true;
2628
+ }
2629
+ if (toolCall.function?.arguments) {
2630
+ const toolCallInfo = state.toolCalls[toolCall.index];
2631
+ if (toolCallInfo) events.push({
2632
+ type: "content_block_delta",
2633
+ index: toolCallInfo.anthropicBlockIndex,
2634
+ delta: {
2635
+ type: "input_json_delta",
2636
+ partial_json: toolCall.function.arguments
2637
+ }
2638
+ });
2639
+ }
2546
2640
  }
2547
2641
  }
2548
2642
  if (choice.finish_reason) {
@@ -2581,7 +2675,8 @@ function translateErrorToAnthropicErrorEvent() {
2581
2675
  //#region src/routes/messages/handler.ts
2582
2676
  async function handleCompletion(c) {
2583
2677
  await checkRateLimit(state);
2584
- const openAIPayload = translateToOpenAI(await c.req.json());
2678
+ const anthropicPayload = await c.req.json();
2679
+ const openAIPayload = translateToOpenAI(anthropicPayload);
2585
2680
  if (state.manualApprove) await awaitApproval();
2586
2681
  const response = await createChatCompletions(openAIPayload);
2587
2682
  if (isNonStreaming(response)) {
@@ -2593,7 +2688,9 @@ async function handleCompletion(c) {
2593
2688
  messageStartSent: false,
2594
2689
  contentBlockIndex: 0,
2595
2690
  contentBlockOpen: false,
2596
- toolCalls: {}
2691
+ toolCalls: {},
2692
+ thinkingBlockOpen: false,
2693
+ thinkingRequested: Boolean(anthropicPayload.thinking)
2597
2694
  };
2598
2695
  try {
2599
2696
  for await (const rawEvent of response) {