mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(cli): the paused-chat refusal prints as written; /discard says when another lost turn remains
The refusal behind a lost turn went through the final-response markdown renderer: `strip` rewrote the quoted prompt (`*bug*`, `__init__.py`, backticks) and `render` merged the `/discard <id>` line into one paragraph. A gateway refusal (failure_reason "gateway_connection") is Hermes's own copy, so the panel now prints it raw. /discard said "You can send messages again" even when another lost turn still refused the next message. It now reads the refreshed pending list and says how many paused turns are left, and uses "Discarded ... it was not re-run" like messaging's gateway.discard.done (a kept result is not thrown away).
This commit is contained in:
1 parent
d5f28ed2ec
commit
485f5ce6ce
2 files changed
+67
-4
No files matched your search
@@ -528,11 +528,15 @@ class CLIChatTurnMixin:
|
||||
lost = lost_admission(connection.reattach(self.session_id), admission_id)
|
||||
connection.call("prompt.resolve_unknown", session_id=self.session_id,
|
||||
admission_id=lost["admission_id"], execution_generation=lost["execution_generation"])
|
||||
connection.reattach(self.session_id) # the cached pending list the next prompt checks
|
||||
# The cached pending list the next prompt checks: any other lost turn still refuses it.
|
||||
snapshot = connection.reattach(self.session_id)
|
||||
except GatewayClientError as exc:
|
||||
_cprint(f" /discard: {exc}")
|
||||
return
|
||||
_cprint(f" Dropped {lost['admission_id']}; it will not be re-run. You can send messages again.")
|
||||
left = sum(row["status"] == "unknown" for row in snapshot.get("pending", []))
|
||||
_cprint(f" Discarded {lost['admission_id']}; it was not re-run. "
|
||||
+ (f"{left} more paused turn{'s' if left > 1 else ''} to /discard first." if left
|
||||
else "You can send messages again."))
|
||||
|
||||
def _chat_render_turn(self, turn, agent_thread, interrupt_msg):
|
||||
"""Post-turn display: errors, interrupt marker, reasoning/response panels, bell, re-queues.
|
||||
@@ -724,6 +728,10 @@ class CLIChatTurnMixin:
|
||||
(self._stream_started and self._stream_box_opened) or _interrupted_streamed
|
||||
) and not is_error_response
|
||||
modern = getattr(self, "_modern_layout", False)
|
||||
# A gateway refusal is Hermes's own copy (quoted user text, a /discard line to copy):
|
||||
# markdown stripping or rendering would rewrite the quote and merge the lines.
|
||||
mode = ("raw" if turn.result and turn.result.get("failure_reason") == "gateway_connection"
|
||||
else self.final_response_markdown)
|
||||
if turn.use_streaming_tts and turn.box_opened and not is_error_response:
|
||||
# Text already printed sentence-by-sentence; just close the box.
|
||||
if modern:
|
||||
@@ -740,12 +748,12 @@ class CLIChatTurnMixin:
|
||||
elif modern:
|
||||
from hermes_cli.cli_modern_layout import answer_label, closing_separator
|
||||
_cprint(answer_label())
|
||||
ChatConsole().print(_render_final_assistant_content(response, mode=self.final_response_markdown),
|
||||
ChatConsole().print(_render_final_assistant_content(response, mode=mode),
|
||||
style=_resp_text, soft_wrap=True) # terminal wraps; resize re-flows
|
||||
_cprint(closing_separator(True))
|
||||
else:
|
||||
ChatConsole().print(Panel(
|
||||
_render_final_assistant_content(response, mode=self.final_response_markdown),
|
||||
_render_final_assistant_content(response, mode=mode),
|
||||
title=f"[{_resp_color} bold]{label}[/]", title_align="left", border_style=_resp_color,
|
||||
style=_resp_text, box=rich_box.HORIZONTALS, padding=(1, 0),
|
||||
width=self._scrollback_box_width(),
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
"""The classic CLI's refusal behind a lost turn and its ``/discard`` reply say only what is true."""
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ["strip", "render"])
|
||||
def test_refused_notice_prints_the_users_text_and_discard_line_as_written(monkeypatch, mode):
|
||||
"""The notice is Hermes's copy, not a model answer: the markdown display modes must neither
|
||||
rewrite the quoted prompt nor merge the ``/discard`` line into the paragraph around it."""
|
||||
import cli as cli_mod
|
||||
from rich.console import Console
|
||||
from hermes_cli.gateway_chat_view import pending_lines
|
||||
|
||||
text = "fix the *bug* in __init__.py and `run` it"
|
||||
notice = "Your message was not sent.\n" + "\n".join(pending_lines([
|
||||
{"admission_id": "a1", "status": "unknown", "text": text},
|
||||
{"admission_id": "q1", "status": "queued", "text": "next"}]))
|
||||
console = Console(record=True, width=200)
|
||||
monkeypatch.setattr(cli_mod, "ChatConsole", lambda: console)
|
||||
stub = SimpleNamespace(final_response_markdown=mode, _last_turn_interrupted=False, _streamed_text_this_turn="",
|
||||
_stream_started=False, _stream_box_opened=False, _modern_layout=False,
|
||||
_scrollback_box_width=lambda: 200)
|
||||
turn = SimpleNamespace(use_streaming_tts=False, box_opened=False, result={
|
||||
"failed": True, "failure_reason": "gateway_connection", "error": notice, "final_response": ""})
|
||||
|
||||
cli_mod.HermesCLI._chat_print_response_panel(stub, turn, notice)
|
||||
|
||||
lines = [line.strip() for line in console.export_text().splitlines()]
|
||||
assert f'"{text}"' in lines and "/discard a1" in lines, lines
|
||||
|
||||
|
||||
def test_discard_says_when_another_lost_turn_still_blocks_the_chat(monkeypatch):
|
||||
import cli as cli_mod
|
||||
|
||||
class Connection:
|
||||
pending = [{"admission_id": a, "status": "unknown", "execution_generation": 4} for a in ("a1", "a2")]
|
||||
|
||||
def reattach(self, _session_id):
|
||||
return {"pending": list(self.pending)}
|
||||
|
||||
def call(self, _method, **params):
|
||||
self.pending = [row for row in self.pending if row["admission_id"] != params["admission_id"]]
|
||||
|
||||
printed = []
|
||||
monkeypatch.setattr(cli_mod, "_cprint", lambda line: printed.append(line))
|
||||
stub = SimpleNamespace(session_id="s")
|
||||
connection = Connection()
|
||||
monkeypatch.setattr("hermes_cli.gateway_side.connection_for", lambda _cli: connection)
|
||||
|
||||
cli_mod.HermesCLI._handle_discard_command(stub, "/discard a1")
|
||||
cli_mod.HermesCLI._handle_discard_command(stub, "/discard a2")
|
||||
|
||||
assert "send messages again" not in printed[0] and "/discard" in printed[0], printed
|
||||
assert "send messages again" in printed[1], printed
|
||||
Reference in new issue
Block a user