Skip to content

gemini reasoning fixes - #5984

Merged
akshaydeo merged 1 commit into
mainfrom
08-08-gemini_reasoning_fixes
Aug 9, 2026
Merged

gemini reasoning fixes#5984
akshaydeo merged 1 commit into
mainfrom
08-08-gemini_reasoning_fixes

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Gemini's thinking guide requires that thought blocks be resent to the model exactly as received — neither removed nor modified. Two converters violated this requirement in different ways: the egress path harvested a reasoning item's signature when it followed a function call but discarded the item's summary text, sending a signature-only block back to Gemini. The ingress path skipped standalone reasoning messages entirely, so their thought text never reached Gemini at all.

Changes

  • Introduced thoughtTextParts, a helper that renders a reasoning item's summary blocks as Gemini thought parts, used by both converters to ensure text travels alongside any harvested signature.
  • In the egress converter (ToGeminiResponsesResponse), when a reasoning item is consumed for its signature, its thought text is now collected and appended immediately after the function call part rather than being silently dropped.
  • In the ingress converter (convertResponsesMessagesToGeminiContents), standalone reasoning messages are no longer skipped outright. Their thought text is emitted as a model-role content block; the signature is still picked up by the look-ahead on the preceding function call, so it is not duplicated.
  • Added TestEgressKeepsThoughtTextAlongsideSignature to verify the egress fix: a reasoning item with both text and a signature that follows a function call must produce both a signed function call part and a thought text part.
  • Added TestIngressSendsThoughtTextForStandaloneReasoning to verify the ingress fix: a standalone reasoning message must produce a thought part in the converted contents.
  • Extended the e2e Postman collection to inject summary text into reasoning items before replay and assert that Gemini accepts the constructed thought parts without returning INVALID_ARGUMENT.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./core/providers/gemini/...

The two new unit tests (TestEgressKeepsThoughtTextAlongsideSignature and TestIngressSendsThoughtTextForStandaloneReasoning) directly cover the fixed paths. The e2e Postman collection can be run against a live Gemini endpoint to confirm the API accepts replayed thought text.

Breaking changes

  • Yes
  • No

Related issues

Security considerations

No auth, secrets, PII, or sandboxing implications. The change only affects how thought block content is serialised when constructing requests to the Gemini API.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@akshaydeo akshaydeo mentioned this pull request Aug 9, 2026
18 tasks
@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Preserved Gemini reasoning text and signatures during Responses API exchanges.
    • Prevented duplicate signatures around function calls and retained standalone reasoning content.
    • Improved compatibility with replayed reasoning items to avoid invalid request errors.
    • Improved reliability for multi-step reasoning and tool-call interactions.
  • Testing

    • Expanded coverage for Gemini reasoning replay and prompt-cache consistency.
    • Added direct-versus-routed cache parity checks across supported providers.
    • Improved provider and feature filtering validation for end-to-end test runs.

Walkthrough

Gemini Responses conversion now preserves reasoning summaries and signatures during replay. The provider harness adds direct-versus-Bifrost cache parity checks, deferred feature routing, and centralized collection identity matching.

Changes

Gemini reasoning replay

Layer / File(s) Summary
Preserve reasoning text and signatures
core/providers/gemini/responses.go
Reasoning summaries become Gemini thought parts. Function-call signatures retain associated text. Standalone reasoning messages emit thought text and signatures without duplication.
Validate reasoning replay behavior
core/providers/gemini/reasoningreplay_test.go, tests/e2e/api/collections/provider-harness.json
Regression tests and the provider harness verify thought text, signatures, successful requests, and the absence of INVALID_ARGUMENT.

Cache parity harness

Layer / File(s) Summary
Generate direct cache parity checks
tests/e2e/api/runners/lib/direct-cache-parity.mjs, tests/e2e/api/runners/lib/direct-cache-parity.test.mjs
The harness generates provider-specific direct and Bifrost requests, cache-hit metrics, multi-round scripts, and baseline comparisons for OpenAI, Anthropic, and Gemini. Unit tests verify round ordering and state handling.
Wire parity coverage into the harness
Makefile, tests/e2e/api/runners/augment-provider-harness.mjs, tests/e2e/api/runners/filter-collection.mjs
The harness includes the generated parity folder. Exact deferred feature matches route execution to the cache pass. prompt-cache parity maps to cache-parity.
Centralize collection identity matching
tests/e2e/api/runners/lib/haystack.mjs, tests/e2e/api/runners/lib/haystack.test.mjs, tests/e2e/api/runners/filter-collection.mjs
Shared haystack utilities build searchable identity text, remove Base64 blobs, and test provider matching and missing-field handling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DirectProvider
  participant BifrostGateway
  participant NewmanAssertions
  DirectProvider->>NewmanAssertions: Record direct cache-hit rates
  BifrostGateway->>NewmanAssertions: Record Bifrost cache-hit rates
  NewmanAssertions->>NewmanAssertions: Compare Bifrost with direct baseline
Loading

Possibly related PRs

  • maximhq/bifrost#5982: Modifies the same Gemini reasoning replay conversion and coverage.
  • maximhq/bifrost#5260: Modifies Gemini Responses reasoning conversion for thought text and signatures.
  • maximhq/bifrost#5963: Modifies provider-harness cache-parity handling in Makefile and filter-collection.mjs.

Suggested reviewers: tejasghatte, pratham-mishra04, roroghost17

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change as fixes to Gemini reasoning handling.
Description check ✅ Passed The description covers the problem, changes, tests, affected areas, breaking changes, and security impact; omitted optional sections are not critical.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 08-08-gemini_reasoning_fixes

Comment @coderabbitai help to get the list of available commands.

akshaydeo commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

This was referenced Aug 9, 2026
@akshaydeo
akshaydeo marked this pull request as ready for review August 9, 2026 01:14

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/providers/gemini/reasoningreplay_test.go`:
- Around line 150-171: Update the assertions in the candidate-part inspection
around sawSignature and sawThoughtText to count matching thought text and
signature-bearing function-call parts instead of using booleans. Require exactly
one occurrence of each, while preserving the existing raw signature and summary
value checks.

In `@core/providers/gemini/responses.go`:
- Around line 3513-3519: The standalone reasoning handling in thoughtTextParts
must append encrypted content’s decoded ThoughtSignature exactly once, while
avoiding duplication when the preceding function call already consumed it;
update the logic around ResponsesReasoning in responses.go accordingly. In
core/providers/gemini/reasoningreplay_test.go lines 177-207, add or adjust
assertions to verify the original signature appears exactly once.

In `@tests/e2e/api/collections/provider-harness.json`:
- Around line 48797-48809: Update the replay-capture logic around
geminiReasoningReplayInput5982 to require a reasoning item with non-empty
encrypted_content before storing the replay. Track whether input contains such
an item, and skip assigning or persisting the replay when none exists, while
preserving the existing summary handling for valid reasoning items.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 6333aed6-1259-41d9-9aef-d1388c34226b

📥 Commits

Reviewing files that changed from the base of the PR and between 0e83b8b and f484dd3.

📒 Files selected for processing (3)
  • core/providers/gemini/reasoningreplay_test.go
  • core/providers/gemini/responses.go
  • tests/e2e/api/collections/provider-harness.json

Comment thread core/providers/gemini/reasoningreplay_test.go Outdated
Comment thread core/providers/gemini/responses.go
Comment thread tests/e2e/api/collections/provider-harness.json
@akshaydeo
akshaydeo force-pushed the 08-08-fixes_cohere_issue branch from 0e83b8b to 528ff4b Compare August 9, 2026 02:14
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from f484dd3 to 8ec8fab Compare August 9, 2026 02:14
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 8ec8fab to 3ae9a28 Compare August 9, 2026 08:22
@akshaydeo
akshaydeo requested a review from a team as a code owner August 9, 2026 08:22
@coderabbitai
coderabbitai Bot requested a review from roroghost17 August 9, 2026 08:23

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

🧹 Nitpick comments (2)
tests/e2e/api/runners/lib/direct-cache-parity.mjs (2)

171-190: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Write rounds swallow HTTP errors without any signal.

Line 174 returns on any response code at or above 400 and records nothing. No pm.test runs, so a failed write round produces a passing item. The read round still asserts "round 2 responded", so a systematic auth or model failure is caught there. A single failed write round, however, only shows up as a lower hit rate, which the best-of-rounds logic then reports as inconclusive. Add a console line so the cause is visible in tmp/newman-cli-cache-parity.log.

♻️ Proposed change
-if (pm.response.code >= 400) { return; }
+if (pm.response.code >= 400) {
+  console.log('[direct-cache-parity] ${cell.id} ${leg} round ${round} write failed (' +
+    pm.response.code + '): ' + pm.response.text());
+  return;
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/api/runners/lib/direct-cache-parity.mjs` around lines 171 - 190,
Add a console error/log message before the early return in roundOneScript when
pm.response.code is at least 400, including the cell, leg, round, and HTTP
status so failed write rounds are visible in tmp/newman-cli-cache-parity.log;
preserve the existing return behavior and successful-round handling.

128-140: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

The Gemini shape ignores cell.bifrostModel.

bifrostUrl builds the path from cell.directModel, and body never uses its model argument, because Gemini carries the model in the URL. Line 314 still computes model from cell.bifrostModel || cell.directModel, so that value has no effect for Gemini cells. No Gemini cell sets bifrostModel today, so the behavior is correct now. Add the fallback to keep the contract uniform if a Gemini cell later needs an explicit gateway model id.

♻️ Proposed change
-    bifrostUrl: (cell) => `{{baseUrl}}/genai/v1beta/models/${cell.directModel}:generateContent`,
+    bifrostUrl: (cell) =>
+      `{{baseUrl}}/genai/v1beta/models/${cell.bifrostModel || cell.directModel}:generateContent`,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/api/runners/lib/direct-cache-parity.mjs` around lines 128 - 140,
Update the Gemini shape’s bifrostUrl to build the model path from the provided
model argument, preserving the fallback computed as cell.bifrostModel ||
cell.directModel at the caller. Keep directUrl based on cell.directModel and
leave the request body unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Around line 2153-2155: Update the deferred-feature loop around DEFERRED_KEYS
so it sets CACHE_PASS and SKIP_MAIN only when FEATURE=cache-parity is unscoped,
preserving the existing main-pass filtering for RERUN_FAILED or FOLDER inputs;
alternatively ensure those scopes are forwarded to the cache pass. Revise the
help text near the interactive-menu guidance to state that FEATURE=cache-parity
is also protected, while other spellings such as FEATURE=cache still require
PARALLEL=0.

In `@tests/e2e/api/runners/lib/direct-cache-parity.mjs`:
- Around line 193-226: Update tests/e2e/api/runners/lib/direct-cache-parity.mjs
lines 193-226 by passing the round number into roundTwoScript and using it in
the assertion and console labels, so Gemini reports its actual final round
(round 6) instead of round 2. Also update the cost comment at lines 150-163 to
state that Gemini cells require 12 live calls rather than four.
- Around line 180-187: Update the round-1 reset logic in the generated script
around roundTwoScript so it clears both seriesVarFor(cell.id, leg) and
varFor(cell.id, leg), including when the write round returns an error. Perform
both unsets before the pm.response.code >= 400 guard, while preserving the
existing round-2 series accumulation behavior.

In `@tests/e2e/api/runners/lib/haystack.mjs`:
- Around line 28-33: Update identityOf to preserve description.content when
item.description is an object with a string content field, while retaining
existing string-description handling and folder behavior. Add a regression test
covering an object-form description such as { content, type } and verify its
content appears in the generated identity.

In `@tests/e2e/api/runners/lib/haystack.test.mjs`:
- Around line 1-75: Move the direct Node.js tests around buildHaystack,
including the test helper and provider-routing cases, out of tests/e2e/** into
the repository’s non-E2E unit-test location. Preserve their assertions and
direct execution style there; do not convert them to E2E fixture or
data-testid-based tests.

---

Nitpick comments:
In `@tests/e2e/api/runners/lib/direct-cache-parity.mjs`:
- Around line 171-190: Add a console error/log message before the early return
in roundOneScript when pm.response.code is at least 400, including the cell,
leg, round, and HTTP status so failed write rounds are visible in
tmp/newman-cli-cache-parity.log; preserve the existing return behavior and
successful-round handling.
- Around line 128-140: Update the Gemini shape’s bifrostUrl to build the model
path from the provided model argument, preserving the fallback computed as
cell.bifrostModel || cell.directModel at the caller. Keep directUrl based on
cell.directModel and leave the request body unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fe736cc1-1d9e-4c28-9d3f-1b4076aa23a3

📥 Commits

Reviewing files that changed from the base of the PR and between 8ec8fab and 3ae9a28.

📒 Files selected for processing (6)
  • Makefile
  • tests/e2e/api/runners/augment-provider-harness.mjs
  • tests/e2e/api/runners/filter-collection.mjs
  • tests/e2e/api/runners/lib/direct-cache-parity.mjs
  • tests/e2e/api/runners/lib/haystack.mjs
  • tests/e2e/api/runners/lib/haystack.test.mjs

Comment thread tests/e2e/api/runners/lib/direct-cache-parity.mjs Outdated
Comment thread tests/e2e/api/runners/lib/direct-cache-parity.mjs Outdated
Comment thread tests/e2e/api/runners/lib/haystack.mjs
Comment thread tests/e2e/api/runners/lib/haystack.test.mjs
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 3ae9a28 to fe11728 Compare August 9, 2026 08:38
@akshaydeo
akshaydeo force-pushed the 08-08-fixes_cohere_issue branch from 528ff4b to 4279ccb Compare August 9, 2026 08:38
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from fe11728 to 9ab7e63 Compare August 9, 2026 15:14
@akshaydeo
akshaydeo force-pushed the 08-08-fixes_cohere_issue branch from 4279ccb to 41db2b1 Compare August 9, 2026 15:14
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 9ab7e63 to 11b1779 Compare August 9, 2026 15:19

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
Makefile (3)

1867-1873: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep CI output quiet during install-newman.

When a package is missing, npm install still writes stdout even when CI mode is enabled. This violates the documented status-table-only output. The recipe also checks only $$CI; use both $(CI) and $$CI when CI=1 is passed as a make variable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 1867 - 1873, Update the install-newman recipe so npm
install stdout is suppressed when CI is enabled, while preserving stderr and
failure propagation. Use a CI condition that recognizes both the Make variable
$(CI) and the shell environment variable $$CI, and apply it to both Newman
installation commands and the readiness message.

1775-1799: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Preserve failure diagnostics in CLI_HARNESS_FILTER.

The /unsupported for / and /not configured in bifrost/ patterns match anywhere in a line. They can remove a real t.Fatal or provider error. Match the exact harness skip strings or anchor the patterns to the harness prefix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 1775 - 1799, Update the awk rules in
CLI_HARNESS_FILTER so skip-message filtering matches only the exact
harness-generated skip strings or lines with their known harness prefix, rather
than any line containing “unsupported for ” or “not configured in bifrost”.
Preserve filtering of legitimate skip messages while leaving t.Fatal bodies and
provider errors untouched.

1862-1865: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Keep HARNESS_PROVIDERS as the single provider source.

HARNESS_PROVIDERS contains eight providers, but the help at Line 1902 lists only six. Parallel mode also hard-codes another list at Line 2192. Use HARNESS_PROVIDERS for PROVIDERS and keep the help text aligned.

♻️ Proposed fix
-		PROVIDERS="openai anthropic bedrock gemini vertex azure passthrough openrouter"; \
+		PROVIDERS="$(HARNESS_PROVIDERS)"; \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 1862 - 1865, Use HARNESS_PROVIDERS as the single
source for the PROVIDERS value, removing any separate provider list or
hard-coded assignment in the parallel-mode configuration. Update the help text
near the harness options to enumerate all providers from HARNESS_PROVIDERS,
including passthrough and openrouter, so documentation and execution remain
aligned.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Makefile`:
- Around line 2155-2157: Update the deferred-key check in the Makefile loop over
DEFERRED_KEYS to normalize FEATURE and each deferred key for case-insensitive
matching, then tokenize comma-separated FEATURE predicates and detect deferred
keys within the complete predicate. Preserve the existing RERUN_FAILED guard,
and pass the full normalized FEATURE predicate to the deferred filter so
additional conditions such as “foo” are not discarded.
- Around line 2353-2354: Update the cache parity filter command near the
provider option so its failure branch exits nonzero instead of only logging and
continuing. Ensure a failed deferred cache collection prevents the cache-only
path from succeeding and preserves the existing error message.

In `@tests/e2e/api/runners/lib/direct-cache-parity.mjs`:
- Around line 286-290: Update the inconclusive branch in the direct-cache parity
runner to retain single-run flake protection while tracking repeated one-sided
results across runs; once the aggregate threshold is reached with direct still
engaging and Bifrost never engaging, fail via pm.test instead of returning
successfully. Add a generated-item unit test covering this persistent-failure
path.
- Line 202: Update roundOneScript so failed responses (status 400 or higher)
execute the same response assertion as roundTwoScript before returning, ensuring
each failed cache-flow request fails its test. Preserve the existing variable
reset before the response guard.

---

Outside diff comments:
In `@Makefile`:
- Around line 1867-1873: Update the install-newman recipe so npm install stdout
is suppressed when CI is enabled, while preserving stderr and failure
propagation. Use a CI condition that recognizes both the Make variable $(CI) and
the shell environment variable $$CI, and apply it to both Newman installation
commands and the readiness message.
- Around line 1775-1799: Update the awk rules in CLI_HARNESS_FILTER so
skip-message filtering matches only the exact harness-generated skip strings or
lines with their known harness prefix, rather than any line containing
“unsupported for ” or “not configured in bifrost”. Preserve filtering of
legitimate skip messages while leaving t.Fatal bodies and provider errors
untouched.
- Around line 1862-1865: Use HARNESS_PROVIDERS as the single source for the
PROVIDERS value, removing any separate provider list or hard-coded assignment in
the parallel-mode configuration. Update the help text near the harness options
to enumerate all providers from HARNESS_PROVIDERS, including passthrough and
openrouter, so documentation and execution remain aligned.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: dff0f0e4-e339-4578-946e-690d0d3c3520

📥 Commits

Reviewing files that changed from the base of the PR and between fe11728 and 9ab7e63.

📒 Files selected for processing (6)
  • Makefile
  • tests/e2e/api/runners/lib/direct-cache-parity.mjs
  • tests/e2e/api/runners/lib/direct-cache-parity.test.mjs
  • tests/e2e/api/runners/lib/harness-deferral.test.mjs
  • tests/e2e/api/runners/lib/haystack.mjs
  • tests/e2e/api/runners/lib/haystack.test.mjs

Comment thread Makefile
Comment thread Makefile
Comment thread tests/e2e/api/runners/lib/direct-cache-parity.mjs Outdated
Comment thread tests/e2e/api/runners/lib/direct-cache-parity.mjs

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/e2e/api/runners/lib/haystack.test.mjs`:
- Around line 88-91: Strengthen the test “a non-string description content is
still ignored” by asserting that object-valued description content does not
appear in the generated haystack. Compare each result with the corresponding
no-description output or assert the nested sentinel is absent, while preserving
coverage for both non-string description shapes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b8f20d5e-dc9d-49e3-9fb8-eb463c9202f4

📥 Commits

Reviewing files that changed from the base of the PR and between 41db2b1 and 11b1779.

📒 Files selected for processing (11)
  • Makefile
  • core/providers/gemini/reasoningreplay_test.go
  • core/providers/gemini/responses.go
  • tests/e2e/api/collections/provider-harness.json
  • tests/e2e/api/runners/augment-provider-harness.mjs
  • tests/e2e/api/runners/filter-collection.mjs
  • tests/e2e/api/runners/lib/direct-cache-parity.mjs
  • tests/e2e/api/runners/lib/direct-cache-parity.test.mjs
  • tests/e2e/api/runners/lib/harness-deferral.test.mjs
  • tests/e2e/api/runners/lib/haystack.mjs
  • tests/e2e/api/runners/lib/haystack.test.mjs
🚧 Files skipped from review as they are similar to previous changes (9)
  • tests/e2e/api/collections/provider-harness.json
  • tests/e2e/api/runners/lib/direct-cache-parity.test.mjs
  • tests/e2e/api/runners/augment-provider-harness.mjs
  • Makefile
  • core/providers/gemini/responses.go
  • tests/e2e/api/runners/filter-collection.mjs
  • tests/e2e/api/runners/lib/direct-cache-parity.mjs
  • tests/e2e/api/runners/lib/haystack.mjs
  • core/providers/gemini/reasoningreplay_test.go

Comment thread tests/e2e/api/runners/lib/haystack.test.mjs
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 11b1779 to ed89655 Compare August 9, 2026 15:31

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/e2e/api/runners/lib/direct-cache-parity.test.mjs (1)

13-13: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Add a regression check for direct-before-Bifrost ordering.

ITEMS is generated from an ordering that the parity flow requires. No test compares the positions of the direct and Bifrost items for the same cell. If Bifrost runs first, its read script has no direct baseline and skips the parity assertion. The unit suite can remain green while parity coverage becomes ineffective.

Add an assertion that each cell's direct round 1 item appears before its Bifrost round 1 item. The companion generator documents this runtime requirement. (raw.githubusercontent.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/api/runners/lib/direct-cache-parity.test.mjs` at line 13, Add a
regression assertion in the direct-cache parity test that, for every cell, the
direct round 1 item occurs before the corresponding Bifrost round 1 item in
ITEMS. Use the companion generator’s cell and item identifiers to match each
pair, ensuring the required ordering is validated before the parity flow runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/e2e/api/runners/lib/direct-cache-parity.test.mjs`:
- Around line 29-48: Strengthen the reset tests for the generated script around
itemNamed("gemini/gemini-2.5-flash direct round 1") by matching the exact
operation that clears dcp_gemini_2_5_flash_direct_hit, rather than accepting
arbitrary references or comments, and require both reset and error-guard indexes
to be non-negative before comparing their order. Tighten the error-path
assertion to verify the failure expectation and that the round-1 assertion is
located inside the pm.response.code >= 400 guard, not merely that a pm.test and
round label occur afterward.

---

Nitpick comments:
In `@tests/e2e/api/runners/lib/direct-cache-parity.test.mjs`:
- Line 13: Add a regression assertion in the direct-cache parity test that, for
every cell, the direct round 1 item occurs before the corresponding Bifrost
round 1 item in ITEMS. Use the companion generator’s cell and item identifiers
to match each pair, ensuring the required ordering is validated before the
parity flow runs.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0b55f2b1-3b01-45fc-ad52-8cdae824d06d

📥 Commits

Reviewing files that changed from the base of the PR and between 11b1779 and ed89655.

📒 Files selected for processing (4)
  • Makefile
  • tests/e2e/api/runners/lib/direct-cache-parity.mjs
  • tests/e2e/api/runners/lib/direct-cache-parity.test.mjs
  • tests/e2e/api/runners/lib/harness-deferral.test.mjs
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/e2e/api/runners/lib/direct-cache-parity.mjs
  • Makefile

Comment thread tests/e2e/api/runners/lib/direct-cache-parity.test.mjs Outdated
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from ed89655 to 7ae71d7 Compare August 9, 2026 15:45
@akshaydeo
akshaydeo force-pushed the 08-08-fixes_cohere_issue branch 2 times, most recently from e004065 to d35b3e8 Compare August 9, 2026 15:49
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 7ae71d7 to 1782cdb Compare August 9, 2026 15:49
@akshaydeo
akshaydeo force-pushed the 08-08-fixes_cohere_issue branch from d35b3e8 to eee6e49 Compare August 9, 2026 16:01
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 1782cdb to 0c12959 Compare August 9, 2026 16:01
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 9, 2026
@akshaydeo
akshaydeo force-pushed the 08-08-fixes_cohere_issue branch from eee6e49 to ce1ee47 Compare August 9, 2026 16:09
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 0c12959 to 5f0a4aa Compare August 9, 2026 16:09
@akshaydeo
akshaydeo force-pushed the 08-08-fixes_cohere_issue branch from ce1ee47 to da05279 Compare August 9, 2026 16:15
@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 5f0a4aa to 23df3f3 Compare August 9, 2026 16:15

akshaydeo commented Aug 9, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Aug 9, 4:17 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Aug 9, 4:25 PM UTC: Graphite rebased this pull request as part of a merge.
  • Aug 9, 4:26 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo changed the base branch from 08-08-fixes_cohere_issue to graphite-base/5984 August 9, 2026 16:21
@akshaydeo
akshaydeo changed the base branch from graphite-base/5984 to main August 9, 2026 16:23
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review August 9, 2026 16:23

The base branch was changed.

@mintlify

mintlify Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
bifrost 🟡 Building Aug 9, 2026, 4:24 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@akshaydeo
akshaydeo force-pushed the 08-08-gemini_reasoning_fixes branch from 23df3f3 to e80f5d5 Compare August 9, 2026 16:24
@akshaydeo
akshaydeo merged commit 108a8c6 into main Aug 9, 2026
14 checks passed
@akshaydeo
akshaydeo deleted the 08-08-gemini_reasoning_fixes branch August 9, 2026 16:26
@akshaydeo akshaydeo mentioned this pull request Aug 10, 2026
18 tasks
akshaydeo added a commit that referenced this pull request Aug 10, 2026
## Summary

Fixes a series of bugs in reasoning/thinking block handling across the Anthropic, Bedrock, Cohere, and Gemini provider converters that caused replayed reasoning to be dropped, rejected, or corrupted during multi-turn conversations. Bumps the version to 1.7.8.

## Changes

- Anthropic, Bedrock, and Cohere converters now fall through to `ResponsesReasoning` instead of being shadowed by an `else if`, preventing replayed reasoning from being silently dropped when `ContentBlocks` is non-nil but empty.
- Bedrock no longer sends reasoning blocks with an absent `text` key — a nil pointer with `omitempty` caused Converse to reject the turn with "Member must not be null" on both the Responses and chat conversion paths.
- Bedrock now attaches the replayed signature to the first reasoning summary block via `reasoningSignatureForBedrock`, rather than discarding it.
- Bedrock invoke thinking blocks now always include the `thinking` key even when text is empty, preventing signature-only replay blocks from being dropped by Bifrost's decoder.
- Cohere now emits encrypted reasoning alongside the summary rather than replacing it, and the `[ENCRYPTED_REASONING: ...]` marker is parsed back into `EncryptedContent` on ingress so it no longer surfaces as visible reasoning text to clients.
- Gemini streaming path now base64-decodes `encrypted_content` before assigning it to `thoughtSignature`, fixing a double-encoding bug that caused Gemini to reject the signature.
- Gemini now carries `thoughtSignature` from thought parts into `encrypted_content` and the reasoning block signature, and emits signature-only thought parts so clients can replay them.
- Standalone Gemini reasoning messages are no longer skipped when converting Responses history to Gemini contents — thought text is resent as required, and the signature is emitted when no preceding function call consumed it.
- A consumed reasoning item's thought text is now carried alongside the signature taken by a preceding Gemini function call, ensuring the thought block reaches Gemini unmodified.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go version
go test ./...
```

Validate multi-turn conversations with reasoning/thinking blocks against Anthropic, Bedrock, Cohere, and Gemini providers. Confirm that:
- Replayed reasoning blocks are preserved across turns.
- Bedrock does not return "Member must not be null" errors on reasoning turns.
- Cohere encrypted reasoning does not appear as visible text to clients.
- Gemini signatures are correctly decoded and accepted on streaming responses.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Closes #5982, #5984

## Security considerations

None beyond ensuring that encrypted reasoning content (`encrypted_content`) is handled correctly and not exposed to clients as plaintext.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
atharvamhaske pushed a commit to atharvamhaske/bifrost that referenced this pull request Aug 13, 2026
## Summary

Gemini's thinking guide requires that thought blocks be resent to the model exactly as received — neither removed nor modified. Two converters violated this requirement in different ways: the egress path harvested a reasoning item's signature when it followed a function call but discarded the item's summary text, sending a signature-only block back to Gemini. The ingress path skipped standalone reasoning messages entirely, so their thought text never reached Gemini at all.

## Changes

- Introduced `thoughtTextParts`, a helper that renders a reasoning item's summary blocks as Gemini thought parts, used by both converters to ensure text travels alongside any harvested signature.
- In the egress converter (`ToGeminiResponsesResponse`), when a reasoning item is consumed for its signature, its thought text is now collected and appended immediately after the function call part rather than being silently dropped.
- In the ingress converter (`convertResponsesMessagesToGeminiContents`), standalone reasoning messages are no longer skipped outright. Their thought text is emitted as a model-role content block; the signature is still picked up by the look-ahead on the preceding function call, so it is not duplicated.
- Added `TestEgressKeepsThoughtTextAlongsideSignature` to verify the egress fix: a reasoning item with both text and a signature that follows a function call must produce both a signed function call part and a thought text part.
- Added `TestIngressSendsThoughtTextForStandaloneReasoning` to verify the ingress fix: a standalone reasoning message must produce a thought part in the converted contents.
- Extended the e2e Postman collection to inject summary text into reasoning items before replay and assert that Gemini accepts the constructed thought parts without returning `INVALID_ARGUMENT`.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/providers/gemini/...
```

The two new unit tests (`TestEgressKeepsThoughtTextAlongsideSignature` and `TestIngressSendsThoughtTextForStandaloneReasoning`) directly cover the fixed paths. The e2e Postman collection can be run against a live Gemini endpoint to confirm the API accepts replayed thought text.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

## Security considerations

No auth, secrets, PII, or sandboxing implications. The change only affects how thought block content is serialised when constructing requests to the Gemini API.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
atharvamhaske pushed a commit to atharvamhaske/bifrost that referenced this pull request Aug 13, 2026
## Summary

Fixes a series of bugs in reasoning/thinking block handling across the Anthropic, Bedrock, Cohere, and Gemini provider converters that caused replayed reasoning to be dropped, rejected, or corrupted during multi-turn conversations. Bumps the version to 1.7.8.

## Changes

- Anthropic, Bedrock, and Cohere converters now fall through to `ResponsesReasoning` instead of being shadowed by an `else if`, preventing replayed reasoning from being silently dropped when `ContentBlocks` is non-nil but empty.
- Bedrock no longer sends reasoning blocks with an absent `text` key — a nil pointer with `omitempty` caused Converse to reject the turn with "Member must not be null" on both the Responses and chat conversion paths.
- Bedrock now attaches the replayed signature to the first reasoning summary block via `reasoningSignatureForBedrock`, rather than discarding it.
- Bedrock invoke thinking blocks now always include the `thinking` key even when text is empty, preventing signature-only replay blocks from being dropped by Bifrost's decoder.
- Cohere now emits encrypted reasoning alongside the summary rather than replacing it, and the `[ENCRYPTED_REASONING: ...]` marker is parsed back into `EncryptedContent` on ingress so it no longer surfaces as visible reasoning text to clients.
- Gemini streaming path now base64-decodes `encrypted_content` before assigning it to `thoughtSignature`, fixing a double-encoding bug that caused Gemini to reject the signature.
- Gemini now carries `thoughtSignature` from thought parts into `encrypted_content` and the reasoning block signature, and emits signature-only thought parts so clients can replay them.
- Standalone Gemini reasoning messages are no longer skipped when converting Responses history to Gemini contents — thought text is resent as required, and the signature is emitted when no preceding function call consumed it.
- A consumed reasoning item's thought text is now carried alongside the signature taken by a preceding Gemini function call, ensuring the thought block reaches Gemini unmodified.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go version
go test ./...
```

Validate multi-turn conversations with reasoning/thinking blocks against Anthropic, Bedrock, Cohere, and Gemini providers. Confirm that:
- Replayed reasoning blocks are preserved across turns.
- Bedrock does not return "Member must not be null" errors on reasoning turns.
- Cohere encrypted reasoning does not appear as visible text to clients.
- Gemini signatures are correctly decoded and accepted on streaming responses.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Closes maximhq#5982, maximhq#5984

## Security considerations

None beyond ensuring that encrypted reasoning content (`encrypted_content`) is handled correctly and not exposed to clients as plaintext.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
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