Normalize real OpenRouter reasoning-only responses #24

Merged
lost-rob0t merged 4 commits from fix/openrouter-reasoning-response into main 2026-08-12 02:09:40 +00:00
lost-rob0t commented 2026-08-12 02:08:32 +00:00 (Migrated from github.com)

Follow-up to #5 based on a real post-merge main CI failure.

The failed live run proved OpenRouter accepted the request and returned HTTP 200, but the dynamically routed free model consumed the tiny output budget in reasoning output and returned no user-facing content or tool calls. The adapter incorrectly classified that as an invalid empty response.

Fix

  • normalize OpenRouter/OpenAI-compatible message.reasoning and message.reasoning_details
  • preserve them in the canonical assistant/model response
  • treat text, tool calls, reasoning, or reasoning details as valid assistant output
  • continue rejecting a truly empty assistant choice
  • preserve reasoning fields when sending assistant messages back through the compatible adapter
  • allow the OpenRouter reasoning generation option

Tests

  • deterministic text response coverage remains
  • deterministic tool-call-only coverage remains
  • add reasoning-only and reasoning-details-only successful response cases
  • explicitly verify a truly empty HTTP-200 choice still fails structurally
  • live smoke still performs one real outbound OpenRouter request and requires provider/model metadata, HTTP 200, response_received=true, valid usage metadata when present, and at least one actual assistant output channel
  • safe CI evidence adds booleans for text_present and reasoning_present; no response content or reasoning text is logged

No retries, mocks, fixtures, interception, fake fallback, Python runtime, or credential persistence are introduced.

Follow-up to #5 based on a real post-merge `main` CI failure. The failed live run proved OpenRouter accepted the request and returned HTTP 200, but the dynamically routed free model consumed the tiny output budget in reasoning output and returned no user-facing `content` or tool calls. The adapter incorrectly classified that as an invalid empty response. ## Fix - normalize OpenRouter/OpenAI-compatible `message.reasoning` and `message.reasoning_details` - preserve them in the canonical assistant/model response - treat text, tool calls, reasoning, or reasoning details as valid assistant output - continue rejecting a truly empty assistant choice - preserve reasoning fields when sending assistant messages back through the compatible adapter - allow the OpenRouter `reasoning` generation option ## Tests - deterministic text response coverage remains - deterministic tool-call-only coverage remains - add reasoning-only and reasoning-details-only successful response cases - explicitly verify a truly empty HTTP-200 choice still fails structurally - live smoke still performs one real outbound OpenRouter request and requires provider/model metadata, HTTP 200, response_received=true, valid usage metadata when present, and at least one actual assistant output channel - safe CI evidence adds booleans for `text_present` and `reasoning_present`; no response content or reasoning text is logged No retries, mocks, fixtures, interception, fake fallback, Python runtime, or credential persistence are introduced.
Sign in to join this conversation.
No description provided.