mirror of
https://github.com/langchain-ai/langchain.git
synced 2026-10-05 09:25:14 +03:00
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:
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 = [
|
||||
|
||||
Reference in new issue
Block a user