Skip to content

fixes generateContent to keep safetyRatings and avgLogprobs - #5877

Merged
akshaydeo merged 1 commit into
devfrom
08-05-fixes_generatecontent_to_keep_safetyratings_and_avglogprobs
Aug 5, 2026
Merged

fixes generateContent to keep safetyRatings and avgLogprobs#5877
akshaydeo merged 1 commit into
devfrom
08-05-fixes_generatecontent_to_keep_safetyratings_and_avglogprobs

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

candidates[0].safetyRatings, candidates[0].avgLogprobs, and the native Gemini responseId were silently dropped when a Gemini/Vertex response passed through Bifrost's OpenAI-shaped Responses schema. Because Bifrost's schema has no fields for these values, they need to be round-tripped via ProviderExtraFields and restored on egress. This fix covers both the non-streaming (generateContent) and streaming (streamGenerateContent) paths.

Closes #5843

Changes

  • responses.go — non-streaming path: ToResponsesBifrostResponsesResponse now stashes responseId, safetyRatings, and avgLogprobs into ProviderExtraFields when converting inbound Gemini responses to Bifrost format. ToGeminiResponsesResponse reads them back out and restores them onto the outbound GenerateContentResponse.
  • responses.go — streaming path: GeminiResponsesStreamState gains SafetyRatings and AvgLogprobs fields. ToBifrostResponsesStream captures these from the terminal chunk (the only chunk that carries them, alongside finishReason). closeGeminiOpenItems writes them into ProviderExtraFields on the response.completed event. ToGeminiResponsesStreamResponse restores them onto the outbound stream chunk.
  • extractGeminiSafetyRatings / extractGeminiAvgLogprobs: Two helper functions handle both the in-memory pointer form (normal path) and the JSON-decoded []interface{}/map form that can appear after a JSON round-trip.
  • gemini_test.go: Regression test TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip covers the non-streaming round-trip, asserting all three fields survive ToResponsesBifrostResponsesResponseToGeminiResponsesResponse.
  • safetyratingsstream_test.go: New test file with TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip, which drives a two-chunk stream through the full forward (ToBifrostResponsesStream) and reverse (ToGeminiResponsesStreamResponse) conversion loop and asserts safetyRatings, avgLogprobs, and responseId are present on the terminal chunk.
  • SKILL.md: The investigate-issue skill now enforces AGENTS.md's "red before green" rule for Bug-classified issues — tests are written and confirmed failing before any fix code is applied, and the todo list ordering reflects this sequence.

Type of change

  • Bug fix

Affected areas

  • Core (Go)
  • Providers/Integrations

How to test

go test ./core/providers/gemini/... -run TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/... -run TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/...

Both new tests should pass. The streaming test validates that safetyRatings, avgLogprobs, and responseId appear on the response.completed chunk after a two-chunk stream round-trip. The non-streaming test validates the same fields survive a single GenerateContentResponse → Bifrost → GenerateContentResponse round-trip.

Breaking changes

  • No

Related issues

Closes #5843

Security considerations

None. The change only preserves existing provider-supplied metadata through an internal schema boundary; no new data is introduced or exposed.

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

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b1e6391d-9ef1-4772-ab9b-172d51b291f1

📥 Commits

Reviewing files that changed from the base of the PR and between 4afcdd5 and 9cfd415.

📒 Files selected for processing (4)
  • .claude/skills/investigate-issue/SKILL.md
  • core/providers/gemini/gemini_test.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/safetyratingsstream_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • core/providers/gemini/gemini_test.go
  • core/providers/gemini/safetyratingsstream_test.go
  • core/providers/gemini/responses.go

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Preserved Gemini response IDs, safety ratings, and average log probabilities during response conversions, including streaming responses.
    • Ensured this metadata remains available through complete round-trip conversions.
  • Tests

    • Added regression coverage for standard and streaming Gemini responses.
    • Strengthened bug-investigation testing guidance to verify failures before fixes and success afterward.

Walkthrough

The change preserves Gemini response IDs, safety ratings, and average log probabilities through standard and streaming conversions. It also updates bug investigation guidance to require red-before-green testing and result reporting.

Changes

Gemini response metadata preservation

Layer / File(s) Summary
Response metadata round-trip
core/providers/gemini/responses.go, core/providers/gemini/gemini_test.go
Gemini response metadata is serialized into and restored from ProviderExtraFields.
Streaming metadata round-trip
core/providers/gemini/responses.go, core/providers/gemini/safetyratingsstream_test.go
Streaming conversion captures terminal metadata, clears reused state, and restores metadata after reverse conversion. Regression tests cover the stream path.

Bug investigation workflow

Layer / File(s) Summary
Bug testing guidance
.claude/skills/investigate-issue/SKILL.md
Bug investigations now require implementation approval, failing tests before fixes, passing tests after fixes, and red-then-green result reporting.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Gemini
  participant BifrostResponses
  participant ProviderExtraFields
  Gemini->>BifrostResponses: responseId, safetyRatings, avgLogprobs
  BifrostResponses->>ProviderExtraFields: store provider metadata
  ProviderExtraFields->>BifrostResponses: restore provider metadata
  BifrostResponses->>Gemini: reconstructed response
Loading

Possibly related PRs

  • maximhq/bifrost#5260: Both changes preserve and reset terminal metadata during Gemini streaming conversions.
  • maximhq/bifrost#5527: Both changes update Gemini response conversion and round-trip tests for provider metadata.

Suggested reviewers: tejasghatte, pratham-mishra04, roroghost17

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The SKILL.md workflow update is unrelated to the Gemini response-conversion requirements in issue #5843. Remove the unrelated SKILL.md change or move it to a separate pull request focused on investigation workflow guidance.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main fix for preserving Gemini safety ratings and average log probabilities during generateContent conversion.
Description check ✅ Passed The description explains the problem, implementation, tests, affected areas, breaking status, related issue, and security impact.
Linked Issues check ✅ Passed The implementation preserves safetyRatings, avgLogprobs, and native responseId for both non-streaming and streaming Gemini responses, satisfying issue #5843.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 08-05-fixes_generatecontent_to_keep_safetyratings_and_avglogprobs

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@akshaydeo
akshaydeo marked this pull request as ready for review August 5, 2026 20:13
@akshaydeo
akshaydeo requested a review from a team as a code owner August 5, 2026 20:13

@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 `@core/providers/gemini/responses.go`:
- Around line 283-299: Preserve terminal candidate metadata and completion
events for empty or error responses: in
core/providers/gemini/responses.go:283-299, assign ProviderExtraFields before
every error-finish return; in ToGeminiResponsesResponse at
core/providers/gemini/responses.go:566-575, create or populate a candidate
whenever preserved metadata exists even when Output is empty; and in the stream
conversion at core/providers/gemini/responses.go:1179-1205, emit
response.completed for terminal chunks without text or tool items. Add
empty/error and ProviderExtraFields JSON round-trip coverage in
core/providers/gemini/gemini_test.go:3981-4035, plus a terminal-only
safety/error stream case in
core/providers/gemini/safetyratingsstream_test.go:50-89.
🪄 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: 9589b562-6d97-4056-a0a0-1e3f8f49810f

📥 Commits

Reviewing files that changed from the base of the PR and between 4afcdd5 and 82445b3.

📒 Files selected for processing (4)
  • .claude/skills/investigate-issue/SKILL.md
  • core/providers/gemini/gemini_test.go
  • core/providers/gemini/responses.go
  • core/providers/gemini/safetyratingsstream_test.go

Comment thread core/providers/gemini/responses.go
@akshaydeo
akshaydeo force-pushed the 08-05-fixes_generatecontent_to_keep_safetyratings_and_avglogprobs branch from 82445b3 to 9cfd415 Compare August 5, 2026 20:43
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai
coderabbitai Bot requested a review from roroghost17 August 5, 2026 20:44

akshaydeo commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Aug 5, 8:47 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Aug 5, 8:48 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo merged commit 2fb58b7 into dev Aug 5, 2026
15 checks passed
@akshaydeo
akshaydeo deleted the 08-05-fixes_generatecontent_to_keep_safetyratings_and_avglogprobs branch August 5, 2026 20:48
akshaydeo added a commit that referenced this pull request Aug 7, 2026
## Summary

`candidates[0].safetyRatings`, `candidates[0].avgLogprobs`, and the native Gemini `responseId` were silently dropped when a Gemini/Vertex response passed through Bifrost's OpenAI-shaped Responses schema. Because Bifrost's schema has no fields for these values, they need to be round-tripped via `ProviderExtraFields` and restored on egress. This fix covers both the non-streaming (`generateContent`) and streaming (`streamGenerateContent`) paths.

Closes #5843

## Changes

- **`responses.go`** **— non-streaming path**: `ToResponsesBifrostResponsesResponse` now stashes `responseId`, `safetyRatings`, and `avgLogprobs` into `ProviderExtraFields` when converting inbound Gemini responses to Bifrost format. `ToGeminiResponsesResponse` reads them back out and restores them onto the outbound `GenerateContentResponse`.
- **`responses.go`** **— streaming path**: `GeminiResponsesStreamState` gains `SafetyRatings` and `AvgLogprobs` fields. `ToBifrostResponsesStream` captures these from the terminal chunk (the only chunk that carries them, alongside `finishReason`). `closeGeminiOpenItems` writes them into `ProviderExtraFields` on the `response.completed` event. `ToGeminiResponsesStreamResponse` restores them onto the outbound stream chunk.
- **`extractGeminiSafetyRatings`** **/** **`extractGeminiAvgLogprobs`**: Two helper functions handle both the in-memory pointer form (normal path) and the JSON-decoded `[]interface{}`/`map` form that can appear after a JSON round-trip.
- **`gemini_test.go`**: Regression test `TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip` covers the non-streaming round-trip, asserting all three fields survive `ToResponsesBifrostResponsesResponse` → `ToGeminiResponsesResponse`.
- **`safetyratingsstream_test.go`**: New test file with `TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip`, which drives a two-chunk stream through the full forward (`ToBifrostResponsesStream`) and reverse (`ToGeminiResponsesStreamResponse`) conversion loop and asserts `safetyRatings`, `avgLogprobs`, and `responseId` are present on the terminal chunk.
- **`SKILL.md`**: The investigate-issue skill now enforces AGENTS.md's "red before green" rule for Bug-classified issues — tests are written and confirmed failing before any fix code is applied, and the todo list ordering reflects this sequence.

## Type of change

- [x] Bug fix

## Affected areas

- [x] Core (Go)
- [x] Providers/Integrations

## How to test

```sh
go test ./core/providers/gemini/... -run TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/... -run TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/...
```

Both new tests should pass. The streaming test validates that `safetyRatings`, `avgLogprobs`, and `responseId` appear on the `response.completed` chunk after a two-chunk stream round-trip. The non-streaming test validates the same fields survive a single `GenerateContentResponse` → Bifrost → `GenerateContentResponse` round-trip.

## Breaking changes

- [x] No

## Related issues

Closes #5843

## Security considerations

None. The change only preserves existing provider-supplied metadata through an internal schema boundary; no new data is introduced or exposed.

## 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
@akshaydeo akshaydeo mentioned this pull request Aug 7, 2026
18 tasks
atharvamhaske pushed a commit to atharvamhaske/bifrost that referenced this pull request Aug 13, 2026
…5877)

## Summary

`candidates[0].safetyRatings`, `candidates[0].avgLogprobs`, and the native Gemini `responseId` were silently dropped when a Gemini/Vertex response passed through Bifrost's OpenAI-shaped Responses schema. Because Bifrost's schema has no fields for these values, they need to be round-tripped via `ProviderExtraFields` and restored on egress. This fix covers both the non-streaming (`generateContent`) and streaming (`streamGenerateContent`) paths.

Closes maximhq#5843

## Changes

- **`responses.go`** **— non-streaming path**: `ToResponsesBifrostResponsesResponse` now stashes `responseId`, `safetyRatings`, and `avgLogprobs` into `ProviderExtraFields` when converting inbound Gemini responses to Bifrost format. `ToGeminiResponsesResponse` reads them back out and restores them onto the outbound `GenerateContentResponse`.
- **`responses.go`** **— streaming path**: `GeminiResponsesStreamState` gains `SafetyRatings` and `AvgLogprobs` fields. `ToBifrostResponsesStream` captures these from the terminal chunk (the only chunk that carries them, alongside `finishReason`). `closeGeminiOpenItems` writes them into `ProviderExtraFields` on the `response.completed` event. `ToGeminiResponsesStreamResponse` restores them onto the outbound stream chunk.
- **`extractGeminiSafetyRatings`** **/** **`extractGeminiAvgLogprobs`**: Two helper functions handle both the in-memory pointer form (normal path) and the JSON-decoded `[]interface{}`/`map` form that can appear after a JSON round-trip.
- **`gemini_test.go`**: Regression test `TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip` covers the non-streaming round-trip, asserting all three fields survive `ToResponsesBifrostResponsesResponse` → `ToGeminiResponsesResponse`.
- **`safetyratingsstream_test.go`**: New test file with `TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip`, which drives a two-chunk stream through the full forward (`ToBifrostResponsesStream`) and reverse (`ToGeminiResponsesStreamResponse`) conversion loop and asserts `safetyRatings`, `avgLogprobs`, and `responseId` are present on the terminal chunk.
- **`SKILL.md`**: The investigate-issue skill now enforces AGENTS.md's "red before green" rule for Bug-classified issues — tests are written and confirmed failing before any fix code is applied, and the todo list ordering reflects this sequence.

## Type of change

- [x] Bug fix

## Affected areas

- [x] Core (Go)
- [x] Providers/Integrations

## How to test

```sh
go test ./core/providers/gemini/... -run TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/... -run TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/...
```

Both new tests should pass. The streaming test validates that `safetyRatings`, `avgLogprobs`, and `responseId` appear on the `response.completed` chunk after a two-chunk stream round-trip. The non-streaming test validates the same fields survive a single `GenerateContentResponse` → Bifrost → `GenerateContentResponse` round-trip.

## Breaking changes

- [x] No

## Related issues

Closes maximhq#5843

## Security considerations

None. The change only preserves existing provider-supplied metadata through an internal schema boundary; no new data is introduced or exposed.

## 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
akhsaul pushed a commit to akhsaul/bifrost that referenced this pull request Aug 27, 2026
…5877)

## Summary

`candidates[0].safetyRatings`, `candidates[0].avgLogprobs`, and the native Gemini `responseId` were silently dropped when a Gemini/Vertex response passed through Bifrost's OpenAI-shaped Responses schema. Because Bifrost's schema has no fields for these values, they need to be round-tripped via `ProviderExtraFields` and restored on egress. This fix covers both the non-streaming (`generateContent`) and streaming (`streamGenerateContent`) paths.

Closes maximhq#5843

## Changes

- **`responses.go`** **— non-streaming path**: `ToResponsesBifrostResponsesResponse` now stashes `responseId`, `safetyRatings`, and `avgLogprobs` into `ProviderExtraFields` when converting inbound Gemini responses to Bifrost format. `ToGeminiResponsesResponse` reads them back out and restores them onto the outbound `GenerateContentResponse`.
- **`responses.go`** **— streaming path**: `GeminiResponsesStreamState` gains `SafetyRatings` and `AvgLogprobs` fields. `ToBifrostResponsesStream` captures these from the terminal chunk (the only chunk that carries them, alongside `finishReason`). `closeGeminiOpenItems` writes them into `ProviderExtraFields` on the `response.completed` event. `ToGeminiResponsesStreamResponse` restores them onto the outbound stream chunk.
- **`extractGeminiSafetyRatings`** **/** **`extractGeminiAvgLogprobs`**: Two helper functions handle both the in-memory pointer form (normal path) and the JSON-decoded `[]interface{}`/`map` form that can appear after a JSON round-trip.
- **`gemini_test.go`**: Regression test `TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip` covers the non-streaming round-trip, asserting all three fields survive `ToResponsesBifrostResponsesResponse` → `ToGeminiResponsesResponse`.
- **`safetyratingsstream_test.go`**: New test file with `TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip`, which drives a two-chunk stream through the full forward (`ToBifrostResponsesStream`) and reverse (`ToGeminiResponsesStreamResponse`) conversion loop and asserts `safetyRatings`, `avgLogprobs`, and `responseId` are present on the terminal chunk.
- **`SKILL.md`**: The investigate-issue skill now enforces AGENTS.md's "red before green" rule for Bug-classified issues — tests are written and confirmed failing before any fix code is applied, and the todo list ordering reflects this sequence.

## Type of change

- [x] Bug fix

## Affected areas

- [x] Core (Go)
- [x] Providers/Integrations

## How to test

```sh
go test ./core/providers/gemini/... -run TestGenAISafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/... -run TestGeminiSafetyRatingsAvgLogprobsResponseIDStreamRoundTrip
go test ./core/providers/gemini/...
```

Both new tests should pass. The streaming test validates that `safetyRatings`, `avgLogprobs`, and `responseId` appear on the `response.completed` chunk after a two-chunk stream round-trip. The non-streaming test validates the same fields survive a single `GenerateContentResponse` → Bifrost → `GenerateContentResponse` round-trip.

## Breaking changes

- [x] No

## Related issues

Closes maximhq#5843

## Security considerations

None. The change only preserves existing provider-supplied metadata through an internal schema boundary; no new data is introduced or exposed.

## 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
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.

[Bug]: generateContent (Gemini format) drops candidates[0].safetyRatings and avgLogprobs on Vertex AI responses

1 participant