Skip to content

feat: thinking blocks round-trip via native pass-through (signature ↔ multi-turn) #41

@HXYerror

Description

@HXYerror

Part of #38. Depends on #39, #40.

Background (verified by live test — 2026-05-10)

When calling api.githubcopilot.com/v1/messages with thinking: {type: "enabled", budget_tokens: N}, the upstream returns real thinking blocks with a signature field:

{
  "type": "thinking",
  "thinking": "I need to calculate 1234 * 5678...\n\n1234 * 5000 = 6,170,000...",
  "signature": "EqMPCkgIDRABGAIqQLsu3KN/ovAdOg1a1HQqToWQ..."
}

The signature is the Anthropic equivalent of OpenAI's encrypted_content — it must be echoed back verbatim in subsequent turns for multi-turn reasoning continuity.

Live test confirmed:

  • claude-sonnet-4.5 + thinking: {budget_tokens: 2000} → thinking block with signature ✅
  • claude-sonnet-4.6 + thinking: {budget_tokens: 2000} → thinking block with signature ✅
  • claude-sonnet-4.6 + thinking + tools together → both blocks in response ✅

Current state

  • AnthropicThinkingBlock in anthropic-types.ts — check if signature field is declared. If not, add it.
  • On the native pass-through path (feat: create-messages-native.ts — Anthropic pass-through service client #39), thinking blocks pass through byte-exact automatically — no special handling needed in the proxy.
  • On the input side (turn N+1): when client sends prior thinking blocks in the messages array, they are forwarded upstream as-is on the native path.

Tasks

  • Verify AnthropicThinkingBlock in anthropic-types.ts includes signature?: string. Add if missing.
  • No additional code needed for the native path — pass-through preserves the field. Document this explicitly with a code comment.
  • For the translation path (legacy models): add handling for inbound thinking blocks with signature in conversation history — currently they are flattened to text (non-stream-translation.ts:146-154). After this issue, they should be forwarded in a way that OpenAI-format upstream can interpret (or at minimum: not crash). Lower priority since legacy models don't support thinking anyway.
  • Add thinking to the test for count_tokens — verify the heuristic accounts for thinking tokens in the output budget
  • Multi-turn test: send turn 1 with thinking enabled → extract thinking block with signature → send turn 2 with the thinking block in messages → verify upstream accepts it without error

Acceptance criteria

  • Two-turn conversation with thinking enabled returns coherent responses (upstream doesn't reject the echoed signature)
  • signature field is preserved byte-exact through the proxy (verify with a hash comparison test)
  • anthropic-types.ts has signature?: string on thinking content blocks

File pointers

Metadata

Metadata

Assignees

No one assigned

    Labels

    anthropicAnthropic Messages API compatibilityreasoningReasoning / thinking / encrypted_content

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions