Skip to content

fix: fixes forwarding of reasoning content while conversion of Responses to Chat - #3584

Merged
akshaydeo merged 2 commits into
devfrom
05-19-fix_fixes_forwarding_of_reasoning_content_while_conversion_of_responses_to_chat
May 19, 2026
Merged

akshaydeo merged 2 commits into
devfrom
05-19-fix_fixes_forwarding_of_reasoning_content_while_conversion_of_responses_to_chat

Conversation

@roroghost17

@roroghost17 roroghost17 commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Reasoning content (e.g. from DeepSeek thinking mode or Anthropic extended thinking) was being silently dropped when converting between the Responses and Chat message formats. This caused multi-turn flows that route through the Responses→Chat fallback path to 400 on providers that require reasoning content to be echoed back. This PR fixes the bidirectional conversion so reasoning is preserved across both directions.

Changes

  • ToResponsesMessages: Reasoning content on an assistant ChatMessage is now emitted as a reasoning-typed ResponsesMessage before any tool calls or text content, matching the order providers expect and allowing clients to echo it back correctly.
  • ToChatMessages: Reasoning messages are no longer silently skipped. Instead, they are buffered and attached to the next assistant turn (whether that turn carries text content or tool calls), populating both Reasoning and ReasoningDetails fields including signatures, summaries, and encrypted content.
  • Null-safety guards were added in the UI log detail view and column helpers to prevent crashes when input_history contains null/undefined entries (which can occur when reasoning messages are injected into history).

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

# Core/Transports
go version
go test ./...

Specific test cases added:

  • TestToChatMessages_AttachesReasoningToNextAssistantMessage — verifies reasoning is buffered and attached to the following assistant text message, including signature preservation.
  • TestToChatMessages_AttachesReasoningToToolCallAssistantMessage — verifies reasoning is attached to tool-call assistant messages.
  • TestToResponsesMessages_EmitsReasoningMessageBeforeToolCalls — verifies reasoning is emitted first when an assistant message has both reasoning and tool calls.
  • TestToResponsesMessages_EmitsReasoningMessageBeforeTextContent — verifies reasoning is emitted first when an assistant message has both reasoning and text content.

Breaking changes

  • Yes
  • No

Related issues

Fixes multi-turn DeepSeek thinking mode and Anthropic extended thinking flows that were returning 400 errors due to missing reasoning content in echoed history.

Security considerations

No auth, secrets, PII, or sandboxing implications. Reasoning content is treated the same as other message content.

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 May 19, 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a087ac4-6afd-4396-91b8-43bed0fa5998

📥 Commits

Reviewing files that changed from the base of the PR and between 8c26def and 0773eb1.

📒 Files selected for processing (4)
  • core/schemas/mux.go
  • core/schemas/mux_test.go
  • ui/app/workspace/logs/sheets/logDetailView.tsx
  • ui/app/workspace/logs/views/columns.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • ui/app/workspace/logs/sheets/logDetailView.tsx
  • ui/app/workspace/logs/views/columns.tsx
  • core/schemas/mux_test.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Assistant reasoning is now emitted as a separate message before tool calls or assistant text and is buffered/attached to the next assistant response for clearer reasoning flow.
  • Bug Fixes

    • More robust handling of empty or falsy entries in message logs.
    • Safer retrieval of most-recent message content to avoid runtime errors.
  • Tests

    • Added tests validating reasoning message emission, buffering, and attachment behavior.

Walkthrough

Export now emits assistant reasoning as standalone Responses reasoning messages; import buffers incoming reasoning and attaches it to the next assistant chat turn. Tests validate ordering and attachment. UI rendering gains defensive checks against falsy history entries.

Changes

Reasoning message handling and UI safety

Layer / File(s) Summary
Reasoning emission in ToResponsesMessages
core/schemas/mux.go
When an assistant message contains Reasoning, emit a separate ResponsesMessageTypeReasoning message before processing tool calls or text content.
Reasoning buffering and attachment in ToChatMessages
core/schemas/mux.go
Introduce pendingReasoning and pendingReasoningDetails buffer state plus attachPendingReasoning helper. Intercept ResponsesMessageTypeReasoning messages to accumulate reasoning text blocks and metadata, then attach buffered reasoning to the next assistant turn during tool-call aggregation, regular message appending, and final tool-call handling.
Reasoning conversion validation
core/schemas/mux_test.go
Add four tests validating bidirectional reasoning conversion: ToChatMessages merges reasoning into both regular and tool-call assistant messages; ToResponsesMessages emits reasoning messages before tool calls or text content with correct ordering and types.
UI defensive null-safety for message entries
ui/app/workspace/logs/sheets/logDetailView.tsx, ui/app/workspace/logs/views/columns.tsx
Filter falsy input_history entries and use optional chaining/early returns when reading last message content to avoid downstream crashes from null/undefined items.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • #1977: Overlaps with emitting ResponsesMessageTypeReasoning from ChatAssistantMessage.Reasoning and related conversion behavior.

Suggested reviewers

  • danpiths
  • akshaydeo

Poem

🐰
I buffered a thought in a soft little nest,
Then attached it to answers when those came to rest.
The UI now skips the empty and false,
So messages land tidy and neat, no remorse.
Hooray for reasoning, tidy and blessed. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% 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
Title check ✅ Passed The title accurately describes the main change: fixing the forwarding of reasoning content during Responses-to-Chat conversion, which directly matches the core objective.
Description check ✅ Passed The description comprehensively covers all required template sections: summary, changes, type, affected areas, testing steps, breaking changes, related issues, security, and checklist.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 05-19-fix_fixes_forwarding_of_reasoning_content_while_conversion_of_responses_to_chat

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 and usage tips.

@CLAassistant

CLAassistant commented May 19, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

roroghost17 commented May 19, 2026

Copy link
Copy Markdown
Contributor Author

@roroghost17
roroghost17 marked this pull request as ready for review May 19, 2026 08:04
@coderabbitai
coderabbitai Bot requested review from akshaydeo and danpiths May 19, 2026 08:05

@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 `@ui/app/workspace/logs/views/columns.tsx`:
- Around line 86-94: When building the preview from log.input_history or
log.responses_input_history (variables: input_history, responses_input_history,
lastInput, lastMessage), don't assume the final array slot is non-null; instead
walk the array backwards to find the last truthy entry (e.g., loop from length-1
down to 0 or use .slice().reverse().find(Boolean)) and then pass that entry's
content into getMessageFromContent; if none found, return ""—apply this for both
input_history and responses_input_history branches so earlier valid content
isn't dropped when the last element is null/undefined.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e6b13709-d379-444a-871b-ee55bfbf6be5

📥 Commits

Reviewing files that changed from the base of the PR and between 2d82365 and 8c26def.

📒 Files selected for processing (4)
  • core/schemas/mux.go
  • core/schemas/mux_test.go
  • ui/app/workspace/logs/sheets/logDetailView.tsx
  • ui/app/workspace/logs/views/columns.tsx

Comment thread ui/app/workspace/logs/views/columns.tsx
@greptile-apps

greptile-apps Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

The core conversion logic is sound for all well-formed inputs; the only gap is an end-of-sequence edge case where buffered reasoning is silently dropped if no assistant turn follows.

The bidirectional buffering and flush logic works correctly for all inputs covered by the new tests. The only gap is an end-of-sequence edge case in ToChatMessages where buffered reasoning is dropped if no assistant turn follows; this is benign in practice today but could mask future issues.

core/schemas/mux.go — post-loop handling of orphaned pending reasoning.

Important Files Changed

Filename Overview
core/schemas/mux.go Bidirectional reasoning conversion logic added; orphaned pending reasoning is silently dropped if no assistant turn follows the last reasoning block in a sequence.
core/schemas/mux_test.go Four new test cases covering the new buffering/emit logic; well-structured and cover key scenarios.
ui/app/workspace/logs/sheets/logDetailView.tsx Null guard added for individual messages inside input_history filter; straightforward defensive fix.
ui/app/workspace/logs/views/columns.tsx Optional chaining and null guard added to prevent crashes when input_history or responses_input_history contains null entries.

Reviews (2): Last reviewed commit: "fix: fixes forwarding of reasoning conte..." | Re-trigger Greptile

Comment thread core/schemas/mux.go Outdated
Comment thread core/schemas/mux.go
Comment thread ui/app/workspace/logs/sheets/logDetailView.tsx
@roroghost17
roroghost17 force-pushed the 05-19-fix_fixes_forwarding_of_reasoning_content_while_conversion_of_responses_to_chat branch from 8c26def to 0773eb1 Compare May 19, 2026 09:00
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 19, 2026
akshaydeo
akshaydeo previously approved these changes May 19, 2026

akshaydeo commented May 19, 2026

Copy link
Copy Markdown
Contributor

Merge activity

  • May 19, 9:12 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 19, 9:15 AM UTC: Graphite couldn't merge this PR because it was not satisfying all requirements (PR does not have required approvals).
  • May 19, 9:30 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • May 19, 9:31 AM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo changed the base branch from 05-19-fix_fixes_nil_pointer_deref_in_stream_cancellations to graphite-base/3584 May 19, 2026 09:13
@akshaydeo
akshaydeo changed the base branch from graphite-base/3584 to dev May 19, 2026 09:13
@akshaydeo
akshaydeo dismissed stale reviews from coderabbitai[bot] and themself May 19, 2026 09:13

The base branch was changed.

@akshaydeo
akshaydeo merged commit b600aea into dev May 19, 2026
10 of 11 checks passed
@akshaydeo
akshaydeo deleted the 05-19-fix_fixes_forwarding_of_reasoning_content_while_conversion_of_responses_to_chat branch May 19, 2026 09:31
akshaydeo pushed a commit that referenced this pull request May 20, 2026
…ses to Chat (#3584)

## Summary

Reasoning content (e.g. from DeepSeek thinking mode or Anthropic extended thinking) was being silently dropped when converting between the Responses and Chat message formats. This caused multi-turn flows that route through the Responses→Chat fallback path to 400 on providers that require reasoning content to be echoed back. This PR fixes the bidirectional conversion so reasoning is preserved across both directions.

## Changes

- **`ToResponsesMessages`**: Reasoning content on an assistant `ChatMessage` is now emitted as a `reasoning`-typed `ResponsesMessage` *before* any tool calls or text content, matching the order providers expect and allowing clients to echo it back correctly.
- **`ToChatMessages`**: Reasoning messages are no longer silently skipped. Instead, they are buffered and attached to the next assistant turn (whether that turn carries text content or tool calls), populating both `Reasoning` and `ReasoningDetails` fields including signatures, summaries, and encrypted content.
- Null-safety guards were added in the UI log detail view and column helpers to prevent crashes when `input_history` contains `null`/`undefined` entries (which can occur when reasoning messages are injected into history).

## Type of change

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

## Affected areas

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

## How to test

```sh
# Core/Transports
go version
go test ./...
```

Specific test cases added:
- `TestToChatMessages_AttachesReasoningToNextAssistantMessage` — verifies reasoning is buffered and attached to the following assistant text message, including signature preservation.
- `TestToChatMessages_AttachesReasoningToToolCallAssistantMessage` — verifies reasoning is attached to tool-call assistant messages.
- `TestToResponsesMessages_EmitsReasoningMessageBeforeToolCalls` — verifies reasoning is emitted first when an assistant message has both reasoning and tool calls.
- `TestToResponsesMessages_EmitsReasoningMessageBeforeTextContent` — verifies reasoning is emitted first when an assistant message has both reasoning and text content.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Fixes multi-turn DeepSeek thinking mode and Anthropic extended thinking flows that were returning 400 errors due to missing reasoning content in echoed history.

## Security considerations

No auth, secrets, PII, or sandboxing implications. Reasoning content is treated the same as other message content.

## Checklist

- [x] 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)
- [x] I verified the CI pipeline passes locally if applicable
@akshaydeo akshaydeo mentioned this pull request May 20, 2026
Shaik-Sirajuddin added a commit to Shaik-Sirajuddin/bifrost that referenced this pull request Jul 4, 2026
- maximhq#4780: tool_search_tool_result was silently dropped on /v1/responses
  (streaming, non-streaming ingest, and Anthropic egress/replay). Calls are
  keyed by tool_use ID rather than a single slot, since Claude can emit
  multiple tool_search calls before any of their results arrive; caller
  provenance (code-execution-spawned searches) round-trips correctly.
- maximhq#3233: tools[].strict is now dropped only for Anthropic-family providers
  that don't support it (Vertex), and kept for native Anthropic.
- maximhq#3802: added a regression test confirming reasoning_content survives
  assistant tool-call turns with extended thinking (already fixed by maximhq#3584).
- web_search_call: same bug class as maximhq#4780 — missing from response.completed
  and vulnerable to the same multi-call concurrency bug; fixed identically.
Shaik-Sirajuddin added a commit to Shaik-Sirajuddin/bifrost that referenced this pull request Jul 4, 2026
- maximhq#4780: tool_search_tool_result was silently dropped on /v1/responses
  (streaming, non-streaming ingest, and Anthropic egress/replay). Calls are
  keyed by tool_use ID rather than a single slot, since Claude can emit
  multiple tool_search calls before any of their results arrive; caller
  provenance (code-execution-spawned searches) round-trips correctly.
- maximhq#3233: tools[].strict is now dropped only for Anthropic-family providers
  that don't support it (Vertex), and kept for native Anthropic.
- maximhq#3802: added a regression test confirming reasoning_content survives
  assistant tool-call turns with extended thinking (already fixed by maximhq#3584).
- web_search_call: same bug class as maximhq#4780 — missing from response.completed
  and vulnerable to the same multi-call concurrency bug; fixed identically.
Shaik-Sirajuddin added a commit to Shaik-Sirajuddin/bifrost that referenced this pull request Jul 4, 2026
- maximhq#4780: tool_search_tool_result was silently dropped on /v1/responses
  (streaming, non-streaming ingest, and Anthropic egress/replay). Calls are
  keyed by tool_use ID rather than a single slot, since Claude can emit
  multiple tool_search calls before any of their results arrive; caller
  provenance (code-execution-spawned searches) round-trips correctly.
- maximhq#3233: tools[].strict is now dropped only for Anthropic-family providers
  that don't support it (Vertex), and kept for native Anthropic.
- maximhq#3802: added a regression test confirming reasoning_content survives
  assistant tool-call turns with extended thinking (already fixed by maximhq#3584).
- web_search_call: same bug class as maximhq#4780 — missing from response.completed
  and vulnerable to the same multi-call concurrency bug; fixed identically.
Shaik-Sirajuddin added a commit to Shaik-Sirajuddin/bifrost that referenced this pull request Jul 15, 2026
- maximhq#4780: tool_search_tool_result was silently dropped on /v1/responses
  (streaming, non-streaming ingest, and Anthropic egress/replay). Calls are
  keyed by tool_use ID rather than a single slot, since Claude can emit
  multiple tool_search calls before any of their results arrive; caller
  provenance (code-execution-spawned searches) round-trips correctly.
- maximhq#3233: tools[].strict is now dropped only for Anthropic-family providers
  that don't support it (Vertex), and kept for native Anthropic.
- maximhq#3802: added a regression test confirming reasoning_content survives
  assistant tool-call turns with extended thinking (already fixed by maximhq#3584).
- web_search_call: same bug class as maximhq#4780 — missing from response.completed
  and vulnerable to the same multi-call concurrency bug; fixed identically.
akhsaul pushed a commit to akhsaul/bifrost that referenced this pull request Aug 27, 2026
…ses to Chat (maximhq#3584)

## Summary

Reasoning content (e.g. from DeepSeek thinking mode or Anthropic extended thinking) was being silently dropped when converting between the Responses and Chat message formats. This caused multi-turn flows that route through the Responses→Chat fallback path to 400 on providers that require reasoning content to be echoed back. This PR fixes the bidirectional conversion so reasoning is preserved across both directions.

## Changes

- **`ToResponsesMessages`**: Reasoning content on an assistant `ChatMessage` is now emitted as a `reasoning`-typed `ResponsesMessage` *before* any tool calls or text content, matching the order providers expect and allowing clients to echo it back correctly.
- **`ToChatMessages`**: Reasoning messages are no longer silently skipped. Instead, they are buffered and attached to the next assistant turn (whether that turn carries text content or tool calls), populating both `Reasoning` and `ReasoningDetails` fields including signatures, summaries, and encrypted content.
- Null-safety guards were added in the UI log detail view and column helpers to prevent crashes when `input_history` contains `null`/`undefined` entries (which can occur when reasoning messages are injected into history).

## Type of change

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

## Affected areas

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

## How to test

```sh
# Core/Transports
go version
go test ./...
```

Specific test cases added:
- `TestToChatMessages_AttachesReasoningToNextAssistantMessage` — verifies reasoning is buffered and attached to the following assistant text message, including signature preservation.
- `TestToChatMessages_AttachesReasoningToToolCallAssistantMessage` — verifies reasoning is attached to tool-call assistant messages.
- `TestToResponsesMessages_EmitsReasoningMessageBeforeToolCalls` — verifies reasoning is emitted first when an assistant message has both reasoning and tool calls.
- `TestToResponsesMessages_EmitsReasoningMessageBeforeTextContent` — verifies reasoning is emitted first when an assistant message has both reasoning and text content.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Fixes multi-turn DeepSeek thinking mode and Anthropic extended thinking flows that were returning 400 errors due to missing reasoning content in echoed history.

## Security considerations

No auth, secrets, PII, or sandboxing implications. Reasoning content is treated the same as other message content.

## Checklist

- [x] 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)
- [x] I verified the CI pipeline passes locally if applicable
occcat pushed a commit to occcat/bifrost that referenced this pull request Sep 2, 2026
…ses to Chat (maximhq#3584)

## Summary

Reasoning content (e.g. from DeepSeek thinking mode or Anthropic extended thinking) was being silently dropped when converting between the Responses and Chat message formats. This caused multi-turn flows that route through the Responses→Chat fallback path to 400 on providers that require reasoning content to be echoed back. This PR fixes the bidirectional conversion so reasoning is preserved across both directions.

## Changes

- **`ToResponsesMessages`**: Reasoning content on an assistant `ChatMessage` is now emitted as a `reasoning`-typed `ResponsesMessage` *before* any tool calls or text content, matching the order providers expect and allowing clients to echo it back correctly.
- **`ToChatMessages`**: Reasoning messages are no longer silently skipped. Instead, they are buffered and attached to the next assistant turn (whether that turn carries text content or tool calls), populating both `Reasoning` and `ReasoningDetails` fields including signatures, summaries, and encrypted content.
- Null-safety guards were added in the UI log detail view and column helpers to prevent crashes when `input_history` contains `null`/`undefined` entries (which can occur when reasoning messages are injected into history).

## Type of change

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

## Affected areas

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

## How to test

```sh
# Core/Transports
go version
go test ./...
```

Specific test cases added:
- `TestToChatMessages_AttachesReasoningToNextAssistantMessage` — verifies reasoning is buffered and attached to the following assistant text message, including signature preservation.
- `TestToChatMessages_AttachesReasoningToToolCallAssistantMessage` — verifies reasoning is attached to tool-call assistant messages.
- `TestToResponsesMessages_EmitsReasoningMessageBeforeToolCalls` — verifies reasoning is emitted first when an assistant message has both reasoning and tool calls.
- `TestToResponsesMessages_EmitsReasoningMessageBeforeTextContent` — verifies reasoning is emitted first when an assistant message has both reasoning and text content.

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

Fixes multi-turn DeepSeek thinking mode and Anthropic extended thinking flows that were returning 400 errors due to missing reasoning content in echoed history.

## Security considerations

No auth, secrets, PII, or sandboxing implications. Reasoning content is treated the same as other message content.

## Checklist

- [x] 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)
- [x] 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.

3 participants