fix(fireworks): drop reasoning history blocks (#39973)

Fixed Fireworks requests failing after switching from a model that
stores reasoning blocks in conversation history.

---

Users switching from an OpenAI Responses model to Fireworks could
receive a 400 because canonical `reasoning` blocks remained in
conversation history. `ChatFireworks` now drops those provider-specific
blocks before serializing Chat Completions requests, matching its
handling of other unsupported reasoning formats.

Made by [Open
SWE](https://openswe.vercel.app/agents/15bd8573-dbbf-55f8-8f22-d5295ec6de11)

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
This commit is contained in:
Mason Daughertyandopen-swe[bot] authored and GitHub committed 2026-08-27 17:28:40 -04:00
1 parent 4fe9d3062f
commit 033ff67b33
2 files changed
+33 -12

No files matched your search

@@ -222,6 +222,25 @@ def _allowed_content_part_keys() -> frozenset[str]:
_ALLOWED_CONTENT_PART_KEYS: frozenset[str] = _allowed_content_part_keys()
_DROPPED_CONTENT_BLOCK_TYPES: frozenset[str] = frozenset(
{
"tool_use",
"thinking",
"reasoning",
"reasoning_content",
"function_call",
"code_interpreter_call",
}
)
"""Content block types the chat completions wire format does not carry.
These arise from provider-specific or canonical v1 content (e.g. Anthropic
`tool_use`/`thinking` blocks, or a `reasoning` block on an AIMessage) that
reaches `_convert_message_to_dict` as conversation history. Fireworks rejects
them, so they are dropped rather than forwarded.
"""
def _sanitize_chat_completions_content(content: Any) -> Any:
"""Strip non-wire keys from content blocks before serializing to Fireworks.
@@ -292,13 +311,7 @@ def _format_message_content(content: Any) -> Any:
for block in content:
if isinstance(block, dict) and "type" in block:
btype = block["type"]
if btype in (
"tool_use",
"thinking",
"reasoning_content",
"function_call",
"code_interpreter_call",
):
if btype in _DROPPED_CONTENT_BLOCK_TYPES:
continue
if is_data_content_block(block):
formatted.append(
@@ -44,6 +44,7 @@ from langchain_core.messages import (
from langchain_fireworks import ChatFireworks
from langchain_fireworks.chat_models import (
_ALLOWED_CONTENT_PART_KEYS,
_DROPPED_CONTENT_BLOCK_TYPES,
FireworksContextOverflowError,
_acompletion_with_retry,
_completion_with_retry,
@@ -402,16 +403,23 @@ def test_format_message_content_passes_through_existing_image_url() -> None:
assert formatted == blocks
@pytest.mark.parametrize(
"btype",
[
def test_dropped_content_block_types_membership() -> None:
"""Pin the drop-list so a removal is a deliberate, visible change.
The parametrized test below derives its cases from the constant, so it
tracks additions for free but cannot catch a deletion.
"""
assert {
"tool_use",
"thinking",
"reasoning",
"reasoning_content",
"function_call",
"code_interpreter_call",
],
)
} == _DROPPED_CONTENT_BLOCK_TYPES
@pytest.mark.parametrize("btype", sorted(_DROPPED_CONTENT_BLOCK_TYPES))
def test_format_message_content_drops_unsupported_block_types(btype: str) -> None:
"""Block types not part of the OpenAI chat completions wire format are stripped."""
blocks = [