Skip to content

fix(ai-gateway): preserve Gemini thought signatures - #5377

Open
chrarnoldus wants to merge 2 commits into
mainfrom
bemused-velociraptor
Open

fix(ai-gateway): preserve Gemini thought signatures#5377
chrarnoldus wants to merge 2 commits into
mainfrom
bemused-velociraptor

Conversation

@chrarnoldus

Copy link
Copy Markdown
Contributor

Summary

  • normalize native Gemini thought text and signatures into OpenRouter reasoning_details
  • restore google-gemini-v1 encrypted details to native thought_signature fields on follow-up requests
  • replace mutually exclusive response-transform booleans with a single enum and retain legacy client signature support

Verification

  • pnpm --filter web exec jest --runInBand --forceExit --runTestsByPath src/lib/ai-gateway/rewriteModelResponse.test.ts src/lib/ai-gateway/experiments/build-direct-provider.test.ts src/lib/ai-gateway/providers/apply-provider-specific-logic.test.ts src/lib/ai-gateway/providers/provider-definitions.test.ts 'src/app/api/openrouter/[...path]/route.test.ts' (180 tests passed)
  • pnpm --filter web typecheck
  • pnpm --filter web lint
  • git diff --check

@chrarnoldus chrarnoldus self-assigned this Aug 19, 2026
extra_body: CustomLlmExtraBodySchema.optional(),
remove_from_body: z.array(z.string()).optional(),
use_gemini_reasoning_transform: z.boolean().optional(),
reasoning_details_transform: ReasoningDetailsTransformSchema.optional(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Stored use_gemini_reasoning_transform configs are silently dropped

CustomLlmApiConfigSchema is a default Zod object, so unknown keys are stripped. Existing custom_llm2.definition and model_experiment_variant_version.upstream blobs still store use_gemini_reasoning_transform: true from #5217. safeParse succeeds, the flag is discarded, and reasoning_details_transform stays undefined.

buildDirectProvider then sets responseTransforms: null, disabling Gemini thought/signature mapping for every already-configured custom LLM and experiment. rotateApiKey also persists the stripped blob.

Map use_gemini_reasoning_transform: truereasoning_details_transform: 'gemini-thought' on parse (and omit on false/absent).


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

details.push({
type: ReasoningDetailType.Text,
text: value.content,
index: 0,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Every Gemini reasoning block is emitted with index: 0

OpenRouter-style clients merge reasoning_details by index and concatenate data/text for the same index (see mergeReasoningDetail in the extension stream client). Thought text, a message-level signature, and every tool-call signature all use index: 0, so a single delta or assembled stream can collapse distinct encrypted blobs into data: sig1+sig2 or overwrite type.

Text chunks can share an index; each encrypted signature needs its own index (and must not share one with text).


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

continue;
}

const toolCall =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Id-less encrypted details attach to the first tool call

The response transform emits message-level thought_signature as reasoning.encrypted with no id. On the inverse, a missing detail.id always selects toolCalls[0].

An assistant turn that has both a root signature and tool_calls (typical after a thought-then-function stream) therefore writes the message signature onto the first tool call instead of the message. Last write also overwrites any earlier signature on that call.

Only fall back to toolCalls[0] when the message has a single tool call and no separate message-level signature; otherwise attach id-less details to the message.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

session_id: sessionId,
});

applyReasoningDetailsTransform(provider, requestToMutate);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: reasoning_effort is now read after remove_from_body

applyReasoningDetailsTransform runs after transformRequest. For Gemini that is required so extra_body.google is merged first, but buildDirectProvider also deletes remove_from_body keys first.

Previously the Gemini path captured reasoning_effort before those deletes. A custom/experiment config with remove_from_body: ['reasoning_effort'] plus gemini-thought now always looks like “effort absent” (include_thoughts: true, no thinking_level).

Read reasoning_effort before applying remove_from_body, or exclude it from that deletion when the Gemini transform is enabled.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 1
WARNING 3
SUGGESTION 0
Issue Details (click to expand)

CRITICAL

File Line Issue
packages/db/src/schema-types.ts 2062 Stored use_gemini_reasoning_transform configs are silently stripped

WARNING

File Line Issue
apps/web/src/lib/ai-gateway/reasoning-details-transform.ts 52 All Gemini reasoning blocks share index: 0, so clients concatenate/overwrite signatures
apps/web/src/lib/ai-gateway/providers/apply-provider-specific-logic.ts 105 Id-less encrypted details attach to the first tool call
apps/web/src/lib/ai-gateway/providers/apply-provider-specific-logic.ts 332 reasoning_effort is now read after remove_from_body
Files Reviewed (13 files)
  • apps/web/src/app/api/openrouter/[...path]/route.test.ts - 0 issues
  • apps/web/src/lib/ai-gateway/experiments/build-direct-provider.test.ts - 0 issues
  • apps/web/src/lib/ai-gateway/experiments/build-direct-provider.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/apply-provider-specific-logic.test.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/apply-provider-specific-logic.ts - 2 issues
  • apps/web/src/lib/ai-gateway/providers/openrouter/request-helpers.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/provider-definitions.test.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/provider-definitions.ts - 0 issues
  • apps/web/src/lib/ai-gateway/providers/types.ts - 0 issues
  • apps/web/src/lib/ai-gateway/reasoning-details-transform.ts - 1 issue
  • apps/web/src/lib/ai-gateway/rewriteModelResponse.test.ts - 0 issues
  • apps/web/src/lib/ai-gateway/rewriteModelResponse.ts - 0 issues
  • packages/db/src/schema-types.ts - 1 issue

Fix these issues in Kilo Cloud


Reviewed by grok-4.6 · Input: 163.4K · Output: 29.2K · Cached: 831K

Review guidance: REVIEW.md from base branch main

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant