progress
This commit is contained in:
139
gui.py
139
gui.py
@@ -54,13 +54,19 @@ _KIND_COLORS = {
|
||||
|
||||
_HEAVY_KEYS = {"message", "text", "script", "output", "content"}
|
||||
|
||||
# Label colours used in rich rendering
|
||||
_LABEL_COLOR = (180, 180, 180)
|
||||
_VALUE_COLOR = (220, 220, 220)
|
||||
_KEY_COLOR = (140, 200, 255) # dict key / call index
|
||||
_NUM_COLOR = (180, 255, 180) # numbers / token counts
|
||||
_SUBHDR_COLOR = (220, 200, 120) # sub-section header
|
||||
|
||||
def _add_comms_field(parent: str, label: str, value: str, heavy: bool):
|
||||
"""Add a labelled field inside parent. Heavy fields get a clamped input_text box."""
|
||||
|
||||
def _add_text_field(parent: str, label: str, value: str):
|
||||
"""Render a labelled text value; long values get a scrollable box."""
|
||||
with dpg.group(horizontal=False, parent=parent):
|
||||
dpg.add_text(f"{label}:", color=(200, 200, 200))
|
||||
if heavy and len(value) > COMMS_CLAMP_CHARS:
|
||||
# Show clamped scrollable box
|
||||
dpg.add_text(f"{label}:", color=_LABEL_COLOR)
|
||||
if len(value) > COMMS_CLAMP_CHARS:
|
||||
dpg.add_input_text(
|
||||
default_value=value,
|
||||
multiline=True,
|
||||
@@ -69,7 +75,116 @@ def _add_comms_field(parent: str, label: str, value: str, heavy: bool):
|
||||
height=80,
|
||||
)
|
||||
else:
|
||||
dpg.add_text(value if value else "(empty)", wrap=460)
|
||||
dpg.add_text(value if value else "(empty)", wrap=460, color=_VALUE_COLOR)
|
||||
|
||||
|
||||
def _add_kv_row(parent: str, key: str, val, val_color=None):
|
||||
"""Single key: value row, horizontally laid out."""
|
||||
vc = val_color or _VALUE_COLOR
|
||||
with dpg.group(horizontal=True, parent=parent):
|
||||
dpg.add_text(f"{key}:", color=_LABEL_COLOR)
|
||||
dpg.add_text(str(val), color=vc)
|
||||
|
||||
|
||||
def _render_usage(parent: str, usage: dict):
|
||||
"""Render Anthropic usage dict as a compact token table."""
|
||||
if not usage:
|
||||
return
|
||||
dpg.add_text("usage:", color=_SUBHDR_COLOR, parent=parent)
|
||||
order = [
|
||||
"input_tokens",
|
||||
"cache_read_input_tokens",
|
||||
"cache_creation_input_tokens",
|
||||
"output_tokens",
|
||||
]
|
||||
shown: set = set()
|
||||
for key in order:
|
||||
if key in usage:
|
||||
shown.add(key)
|
||||
_add_kv_row(parent, f" {key.replace('_', ' ')}", usage[key], _NUM_COLOR)
|
||||
for key, val in usage.items():
|
||||
if key not in shown:
|
||||
_add_kv_row(parent, f" {key}", val, _NUM_COLOR)
|
||||
|
||||
|
||||
def _render_tool_calls_list(parent: str, tool_calls: list):
|
||||
"""Render a list of tool_call dicts inline."""
|
||||
if not tool_calls:
|
||||
dpg.add_text(" (none)", color=_VALUE_COLOR, parent=parent)
|
||||
return
|
||||
for i, tc in enumerate(tool_calls):
|
||||
dpg.add_text(f" call[{i}] {tc.get('name', '?')}", color=_KEY_COLOR, parent=parent)
|
||||
if "id" in tc:
|
||||
_add_kv_row(parent, " id", tc["id"])
|
||||
args = tc.get("args") or tc.get("input") or {}
|
||||
if isinstance(args, dict):
|
||||
for ak, av in args.items():
|
||||
_add_text_field(parent, f" {ak}", str(av))
|
||||
elif args:
|
||||
_add_text_field(parent, " args", str(args))
|
||||
|
||||
|
||||
# ---- kind-specific renderers ------------------------------------------------
|
||||
|
||||
def _render_payload_request(parent: str, payload: dict):
|
||||
_add_text_field(parent, "message", payload.get("message", ""))
|
||||
|
||||
|
||||
def _render_payload_response(parent: str, payload: dict):
|
||||
_add_kv_row(parent, "round", payload.get("round", ""))
|
||||
_add_kv_row(parent, "stop_reason", payload.get("stop_reason", ""), (255, 200, 120))
|
||||
text = payload.get("text", "")
|
||||
if text:
|
||||
_add_text_field(parent, "text", text)
|
||||
dpg.add_text("tool_calls:", color=_LABEL_COLOR, parent=parent)
|
||||
_render_tool_calls_list(parent, payload.get("tool_calls", []))
|
||||
usage = payload.get("usage")
|
||||
if usage:
|
||||
_render_usage(parent, usage)
|
||||
|
||||
|
||||
def _render_payload_tool_call(parent: str, payload: dict):
|
||||
_add_kv_row(parent, "name", payload.get("name", ""))
|
||||
if "id" in payload:
|
||||
_add_kv_row(parent, "id", payload["id"])
|
||||
_add_text_field(parent, "script", payload.get("script", ""))
|
||||
|
||||
|
||||
def _render_payload_tool_result(parent: str, payload: dict):
|
||||
_add_kv_row(parent, "name", payload.get("name", ""))
|
||||
if "id" in payload:
|
||||
_add_kv_row(parent, "id", payload["id"])
|
||||
_add_text_field(parent, "output", payload.get("output", ""))
|
||||
|
||||
|
||||
def _render_payload_tool_result_send(parent: str, payload: dict):
|
||||
for i, r in enumerate(payload.get("results", [])):
|
||||
dpg.add_text(f"result[{i}]", color=_KEY_COLOR, parent=parent)
|
||||
_add_kv_row(parent, " tool_use_id", r.get("tool_use_id", ""))
|
||||
_add_text_field(parent, " content", str(r.get("content", "")))
|
||||
|
||||
|
||||
def _render_payload_generic(parent: str, payload: dict):
|
||||
"""Fallback: render any unknown payload kind as labelled fields."""
|
||||
import json
|
||||
for key, val in payload.items():
|
||||
if isinstance(val, (dict, list)):
|
||||
val_str = json.dumps(val, ensure_ascii=False, indent=2)
|
||||
else:
|
||||
val_str = str(val)
|
||||
if key in _HEAVY_KEYS:
|
||||
_add_text_field(parent, key, val_str)
|
||||
else:
|
||||
_add_kv_row(parent, key, val_str)
|
||||
|
||||
|
||||
_KIND_RENDERERS = {
|
||||
"request": _render_payload_request,
|
||||
"response": _render_payload_response,
|
||||
"tool_call": _render_payload_tool_call,
|
||||
"tool_result": _render_payload_tool_result,
|
||||
"tool_result_send": _render_payload_tool_result_send,
|
||||
}
|
||||
|
||||
|
||||
def _render_comms_entry(parent: str, entry: dict, idx: int):
|
||||
@@ -92,15 +207,9 @@ def _render_comms_entry(parent: str, entry: dict, idx: int):
|
||||
dpg.add_text(kind, color=kind_color)
|
||||
dpg.add_text(f"{provider}/{model}", color=(180, 180, 180))
|
||||
|
||||
# Payload fields
|
||||
for key, val in payload.items():
|
||||
is_heavy = key in _HEAVY_KEYS
|
||||
if isinstance(val, (dict, list)):
|
||||
import json
|
||||
val_str = json.dumps(val, ensure_ascii=False, indent=2)
|
||||
else:
|
||||
val_str = str(val)
|
||||
_add_comms_field(parent, key, val_str, is_heavy)
|
||||
# Payload - use rich renderer if available, else generic fallback
|
||||
renderer = _KIND_RENDERERS.get(kind, _render_payload_generic)
|
||||
renderer(parent, payload)
|
||||
|
||||
dpg.add_separator()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user