Capability-aware reasoning and extended thinking translation#238
Open
lyzgeorge wants to merge 9 commits intoericc-ch:masterfrom
Open
Capability-aware reasoning and extended thinking translation#238lyzgeorge wants to merge 9 commits intoericc-ch:masterfrom
lyzgeorge wants to merge 9 commits intoericc-ch:masterfrom
Conversation
Normalize reasoning effort, thinking budget, and Anthropic reasoning streams so both proxy surfaces stay aligned with Copilot model capabilities. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot advertises adaptive_thinking and reasoning_effort under `capabilities.supports`, not at the top level of `capabilities`. The previous gate looked at the wrong field, so Anthropic `thinking` was always stripped and reasoning never reached upstream for /v1/messages. Read the correct fields and gate each surface on what the model actually supports. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a Reasoning & Extended Thinking section to the README, highlight the feature in the intro and features list, and cover the capability gating with new handler tests for the Anthropic /v1/messages surface and additional cases for /v1/chat/completions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agent-Logs-Url: https://github.com/lyzgeorge/copilot-api/sessions/10f76b26-728d-41d8-8fb3-432974af4318 Co-authored-by: lyzgeorge <8285196+lyzgeorge@users.noreply.github.com>
…plete Agent-Logs-Url: https://github.com/lyzgeorge/copilot-api/sessions/10f76b26-728d-41d8-8fb3-432974af4318 Co-authored-by: lyzgeorge <8285196+lyzgeorge@users.noreply.github.com>
Agent-Logs-Url: https://github.com/lyzgeorge/copilot-api/sessions/83622886-a808-4ba6-820c-75ed8300f3ab Co-authored-by: lyzgeorge <8285196+lyzgeorge@users.noreply.github.com>
…type feat: allow arbitrary `reasoning_effort` values via pass-through
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/v1/chat/completions) and Anthropic (/v1/messages) surfaces routereasoning_effort,thinking_budget, and Anthropicthinkingconfig to whichever upstream knob each Copilot model advertises undercapabilities.supports.reasoning_text/reasoning_opaquethrough non-stream responses and emits nativecontent_block_start/thinking_delta/signature_delta/content_block_stopevents on the streaming path, so Claude Code and similar clients see real thinking UIs.src/routes/reasoning-context.tshelper shared by both handlers, plus handler-level tests for/v1/chat/completionsand/v1/messagesthat verify adaptive-thinking, reasoning-effort-only, disabled-thinking, and unsupported-model paths.Why
Copilot advertises reasoning capabilities under
capabilities.supports.adaptive_thinkingandcapabilities.supports.reasoning_effort, but neither surface read those fields. As a result,thinking: enabledon/v1/messageswas silently dropped, and/v1/chat/completionswould happily forwardthinking_budgetto models that don't accept it. The new helper reads the advertised capabilities and translates requests accordingly — e.g. Anthropicthinking: enabledbecomesreasoning_effort: highon gpt-5 family models andreasoning_effort: high+thinking_budgeton Claude Sonnet 4.6.What changed
src/routes/reasoning-context.ts(new):buildAnthropicReasoningContextandbuildOpenAIReasoningContext, gated onsupports.reasoning_effortandsupports.adaptive_thinking.src/routes/messages/handler.ts: resolves the selected model, builds the reasoning context, passes it intotranslateToOpenAI, and debug-logs when an unsupported model causes thinking to be stripped.src/routes/messages/non-stream-translation.ts:translateToOpenAInow takes aReasoningContextand emitsreasoning_effort/thinking_budget;translateToAnthropicpreservesreasoning_textas a thinking block andreasoning_opaqueon the response, maintaining per-choice ordering.src/routes/messages/stream-translation.ts: trackscurrentBlockTypeexplicitly and emits Anthropic-native thinking/text/tool-use transitions, includingsignature_deltascoped to each thinking block. Forwards cached prompt tokens ascache_read_input_tokensonmessage_delta.src/routes/chat-completions/handler.ts: builds an OpenAI reasoning context, drops unsupportedthinking_budgetwith a debug log, and normalizes the payload before sending to Copilot.src/routes/messages/count-tokens-handler.ts: reuses the same reasoning-context helper so token counts match what we actually send upstream.src/services/copilot/create-chat-completions.ts: typesreasoning_effort,thinking_budget,stream_options, and reasoning fields onDelta/ResponseMessage.src/services/copilot/get-models.ts: extendsModelSupportswithadaptive_thinkingandreasoning_effort.tests/chat-completions-handler.test.tsandtests/messages-handler.test.ts(integration-style usingfetchmocking so no module-level mocks leak across suites), plus reasoning-context helper coverage intests/anthropic-request.test.tsand streaming/non-stream reasoning cases intests/anthropic-response.test.ts.Test plan
bun test tests/— 48 tests, all passingbun run typecheckbun run lint/v1/chat/completionsagainstgpt-5-miniandclaude-sonnet-4.6withreasoning_effortinminimal/low/medium/high/v1/messagesagainstgpt-5-miniandclaude-sonnet-4.6withthinking: enabledandthinking: disabledreasoning_text/reasoning_opaqueflow through non-stream responsesNotes
capabilities.supports.*) is split out as its own commit (3a65946) so the history shows the root cause clearly..worktrees/was added to.gitignorein a separate chore commit so local worktree directories don't pollutegit status.