mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-18 04:41:56 +00:00
fix(agent/gemini-cloudcode): seed delta defaults for reasoning-only stream chunks
_make_stream_chunk built delta_kwargs with only `role`, so a reasoning-only chunk produced a SimpleNamespace without a `.content` attribute. Downstream consumers that read `delta.content` then raised AttributeError on Gemini 2.5 Flash, where the thinking delta arrives before any content delta. Seed `content`, `tool_calls`, `reasoning`, and `reasoning_content` as None up front, matching the pattern already used in gemini_native_adapter.py. Key-present arguments still override the defaults. Fixes #24974 References: Related open PR #24984 (luyao618) applies the same 1-line fix; this PR adds a regression test that #24984 omits Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
72b5dd8658
commit
26933c2f59
2 changed files with 36 additions and 1 deletions
|
|
@ -450,7 +450,13 @@ def _make_stream_chunk(
|
||||||
finish_reason: Optional[str] = None,
|
finish_reason: Optional[str] = None,
|
||||||
reasoning: str = "",
|
reasoning: str = "",
|
||||||
) -> _GeminiStreamChunk:
|
) -> _GeminiStreamChunk:
|
||||||
delta_kwargs: Dict[str, Any] = {"role": "assistant"}
|
delta_kwargs: Dict[str, Any] = {
|
||||||
|
"role": "assistant",
|
||||||
|
"content": None,
|
||||||
|
"tool_calls": None,
|
||||||
|
"reasoning": None,
|
||||||
|
"reasoning_content": None,
|
||||||
|
}
|
||||||
if content:
|
if content:
|
||||||
delta_kwargs["content"] = content
|
delta_kwargs["content"] = content
|
||||||
if tool_call_delta is not None:
|
if tool_call_delta is not None:
|
||||||
|
|
|
||||||
|
|
@ -913,6 +913,35 @@ class TestTranslateStreamEvent:
|
||||||
assert chunks[-1].choices[0].finish_reason == "tool_calls"
|
assert chunks[-1].choices[0].finish_reason == "tool_calls"
|
||||||
|
|
||||||
|
|
||||||
|
class TestMakeStreamChunk:
|
||||||
|
def test_reasoning_only_chunk_has_content_none(self):
|
||||||
|
from agent.gemini_cloudcode_adapter import _make_stream_chunk
|
||||||
|
|
||||||
|
chunk = _make_stream_chunk(model="m", reasoning="think")
|
||||||
|
delta = chunk.choices[0].delta
|
||||||
|
assert delta.content is None
|
||||||
|
assert delta.reasoning == "think"
|
||||||
|
|
||||||
|
def test_content_only_chunk_has_reasoning_none(self):
|
||||||
|
from agent.gemini_cloudcode_adapter import _make_stream_chunk
|
||||||
|
|
||||||
|
chunk = _make_stream_chunk(model="m", content="hello")
|
||||||
|
delta = chunk.choices[0].delta
|
||||||
|
assert delta.content == "hello"
|
||||||
|
assert delta.reasoning is None
|
||||||
|
assert delta.tool_calls is None
|
||||||
|
|
||||||
|
def test_finish_only_chunk_has_all_fields_none(self):
|
||||||
|
from agent.gemini_cloudcode_adapter import _make_stream_chunk
|
||||||
|
|
||||||
|
chunk = _make_stream_chunk(model="m", finish_reason="stop")
|
||||||
|
delta = chunk.choices[0].delta
|
||||||
|
assert delta.content is None
|
||||||
|
assert delta.reasoning is None
|
||||||
|
assert delta.tool_calls is None
|
||||||
|
assert chunk.choices[0].finish_reason == "stop"
|
||||||
|
|
||||||
|
|
||||||
class TestGeminiCloudCodeClient:
|
class TestGeminiCloudCodeClient:
|
||||||
def test_client_exposes_openai_interface(self):
|
def test_client_exposes_openai_interface(self):
|
||||||
from agent.gemini_cloudcode_adapter import GeminiCloudCodeClient
|
from agent.gemini_cloudcode_adapter import GeminiCloudCodeClient
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue