mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-08 13:12:08 +00:00
fix(codex): stream commentary deltas through the reasoning channel
Follow-up to the salvaged #58696 (devatnull) + #41343 (annguyenNous) commits: instead of fully suppressing commentary/analysis-phase stream deltas, fire on_reasoning_delta so the CLI/gateway display them like thinking text. Matches Codex CLI semantics where commentary is never the turn's final answer, while keeping the narration visible in the reasoning display. Adds devatnull to AUTHOR_MAP.
This commit is contained in:
parent
538173f679
commit
b3b1e58ad6
3 changed files with 20 additions and 5 deletions
|
|
@ -605,9 +605,10 @@ def _consume_codex_event_stream(
|
|||
_raise_stream_error(event)
|
||||
|
||||
# Track the phase of the active streamed message item. Codex/Harmony
|
||||
# ``commentary``/``analysis`` text is protocol/tool preamble, not the
|
||||
# final answer. We still collect completed output items for replay, but
|
||||
# suppress those deltas from live user-visible callbacks.
|
||||
# ``commentary``/``analysis`` text is mid-turn preamble/progress
|
||||
# narration, never the final answer. We still collect completed output
|
||||
# items for replay, but route those deltas to the reasoning callback so
|
||||
# they display like thinking text instead of assistant content.
|
||||
if event_type == "response.output_item.added":
|
||||
item = _event_field(event, "item")
|
||||
item_type = _item_field(item, "type", "")
|
||||
|
|
@ -623,7 +624,15 @@ def _consume_codex_event_stream(
|
|||
if "output_text.delta" in event_type or event_type == "response.output_text.delta":
|
||||
delta_text = _event_field(event, "delta", "")
|
||||
is_commentary_delta = active_message_phase in {"commentary", "analysis"}
|
||||
if delta_text and not is_commentary_delta:
|
||||
if delta_text and is_commentary_delta:
|
||||
# Commentary streams through the reasoning channel, not the
|
||||
# visible answer stream (and stays out of output_text).
|
||||
if on_reasoning_delta is not None:
|
||||
try:
|
||||
on_reasoning_delta(delta_text)
|
||||
except Exception:
|
||||
logger.debug("Codex stream on_reasoning_delta raised", exc_info=True)
|
||||
elif delta_text:
|
||||
collected_text_deltas.append(delta_text)
|
||||
if not has_tool_calls:
|
||||
if not first_delta_fired:
|
||||
|
|
|
|||
|
|
@ -489,6 +489,7 @@ AUTHOR_MAP = {
|
|||
"Rivuza@users.noreply.github.com": "Rivuza",
|
||||
"annguyenNous@users.noreply.github.com": "annguyenNous",
|
||||
"285874597+annguyenNous@users.noreply.github.com": "annguyenNous",
|
||||
"perkintahmaz50@gmail.com": "devatnull",
|
||||
"kylekahraman@users.noreply.github.com": "kylekahraman",
|
||||
"130975919+kylekahraman@users.noreply.github.com": "kylekahraman",
|
||||
"seppe@fushia.be": "seppegadeyne",
|
||||
|
|
|
|||
|
|
@ -629,7 +629,7 @@ def test_run_codex_stream_returns_collected_items_when_stream_ends_without_termi
|
|||
assert response.output == [output_item]
|
||||
|
||||
|
||||
def test_consume_codex_stream_suppresses_commentary_phase_deltas(monkeypatch):
|
||||
def test_consume_codex_stream_routes_commentary_phase_deltas_to_reasoning(monkeypatch):
|
||||
from agent.codex_runtime import _consume_codex_event_stream
|
||||
|
||||
commentary_item = SimpleNamespace(
|
||||
|
|
@ -646,6 +646,7 @@ def test_consume_codex_stream_suppresses_commentary_phase_deltas(monkeypatch):
|
|||
arguments="{}",
|
||||
)
|
||||
streamed = []
|
||||
reasoning_streamed = []
|
||||
|
||||
response = _consume_codex_event_stream(
|
||||
_FakeCreateStream([
|
||||
|
|
@ -665,9 +666,11 @@ def test_consume_codex_stream_suppresses_commentary_phase_deltas(monkeypatch):
|
|||
]),
|
||||
model="gpt-5-codex",
|
||||
on_text_delta=streamed.append,
|
||||
on_reasoning_delta=reasoning_streamed.append,
|
||||
)
|
||||
|
||||
assert streamed == []
|
||||
assert reasoning_streamed == ["I’ll call the tool now."]
|
||||
assert response.output == [commentary_item, function_item]
|
||||
assert response.output_text == ""
|
||||
|
||||
|
|
@ -1635,6 +1638,7 @@ def test_normalize_codex_response_marks_commentary_only_message_as_incomplete(mo
|
|||
|
||||
assert finish_reason == "incomplete"
|
||||
assert (assistant_message.content or "") == ""
|
||||
assert "inspect the repository" in (assistant_message.reasoning or "")
|
||||
assert assistant_message.codex_message_items
|
||||
assert assistant_message.codex_message_items[0]["phase"] == "commentary"
|
||||
assert "inspect the repository" in assistant_message.codex_message_items[0]["content"][0]["text"]
|
||||
|
|
@ -1651,6 +1655,7 @@ def test_normalize_codex_response_does_not_fallback_to_output_text_for_commentar
|
|||
|
||||
assert finish_reason == "incomplete"
|
||||
assert (assistant_message.content or "") == ""
|
||||
assert "call the tool" in (assistant_message.reasoning or "")
|
||||
assert assistant_message.codex_message_items[0]["phase"] == "commentary"
|
||||
|
||||
def test_normalize_codex_response_final_answer_overrides_top_level_incomplete(monkeypatch):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue