fix(ux): plain-language, actionable user-facing messages (core)

Squashed integration of the user-facing message audit for this surface set.
Full per-finding receipts: /tmp/ux-audit/lanes/*-receipt.md (campaign artifacts).
This commit is contained in:
teknium1
2026-09-14 23:01:23 -07:00
committed by Teknium
parent 7fcade0100
commit 23036e20a6
234 changed files with 5635 additions and 1567 deletions
+17 -16
View File
@@ -251,16 +251,17 @@ def _result_status(result: dict) -> str:
else "error" if result.get("error") else "complete")
def _turn_outcome(result: Any) -> tuple[Any, str, str | None]:
def _turn_outcome(result: Any, error_surface: dict | None = None) -> tuple[Any, str, str | None]:
"""Reduce a run_conversation result to ``(raw_text, status, last_reasoning)``."""
if not isinstance(result, dict):
return str(result), "complete", None
raw = result.get("final_response", "")
status = _result_status(result)
# No visible response AND a real error: surface the error as the text (classic CLI
# parity). An empty successful turn still renders as empty.
# No visible response AND a real error: the assistant slot carries a plain account of the
# failure (title from ``error_surface``, raw provider detail on a ``Details:`` line, next
# step) rather than the bare provider body. An empty successful turn still renders as empty.
if (not raw) and result.get("error") and (result.get("failed") or result.get("partial")):
raw = f"Error: {result.get('error')}"
raw = turn_error_text(result.get("error"), error_surface)
# "Operation interrupted: waiting for model response (…)" is cancellation
# metadata, not assistant prose (gateway/run.py and ACP suppress it too).
# "Operation interrupted: waiting for model response (…)" is cancellation metadata, not assistant prose.
@@ -625,7 +626,18 @@ def _complete_turn_payload(session: dict, st: _TurnRun, status_note: str | None,
"""``(payload, raw, status)`` for message.complete; retains/clears the inflight turn and
settles the hosted-room terminal receipt."""
result, agent = st.result, st.agent
raw, status, last_reasoning = _turn_outcome(result)
# Advisory {layer, code, retryable} descriptor; computed before the retain so resume
# replay carries the same one, and before the text so the fallback copy can use it.
_error_surface = None
if _result_status(result) == "error":
try:
from agent.error_surface import build_error_surface_from_result
_error_surface = build_error_surface_from_result(
result, provider=str(getattr(agent, "provider", "") or ""),
model=str(getattr(agent, "model", "") or ""))
except Exception:
_error_surface = None
raw, status, last_reasoning = _turn_outcome(result, _error_surface)
payload = {"text": raw, "usage": _get_usage(agent), "status": status}
if last_reasoning:
payload["reasoning"] = last_reasoning
@@ -639,17 +651,6 @@ def _complete_turn_payload(session: dict, st: _TurnRun, status_note: str | None,
payload["failure_reason"] = result.get("failure_reason")
if rendered := render_message(raw, cols):
payload["rendered"] = rendered
# Advisory {layer, code, retryable} descriptor; computed before the retain so resume
# replay carries the same one.
_error_surface = None
if status == "error":
try:
from agent.error_surface import build_error_surface_from_result
_error_surface = build_error_surface_from_result(
result, provider=str(getattr(agent, "provider", "") or ""),
model=str(getattr(agent, "model", "") or ""))
except Exception:
_error_surface = None
error_value = result.get("error")
with session["history_lock"]:
if status == "error":