fix(display): render <missing old_text> in memory previews instead of empty quotes (#12852)

When the model omits old_text on memory replace/remove, the tool preview
rendered as '~memory: ""' / '-memory: ""', which obscured what went wrong.
Render '<missing old_text>' in that case so the failure mode is legible
in the activity feed.

Narrow salvage from #12456 / #12831 — only the display-layer fix, not the
schema/API changes.
This commit is contained in:
Teknium 2026-04-19 22:45:47 -07:00 committed by GitHub
parent 6a228d52f7
commit fc5fda5e38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 17 additions and 4 deletions

View file

@ -225,9 +225,11 @@ def build_tool_preview(tool_name: str, args: dict, max_len: int | None = None) -
content = _oneline(args.get("content", "")) content = _oneline(args.get("content", ""))
return f"+{target}: \"{content[:25]}{'...' if len(content) > 25 else ''}\"" return f"+{target}: \"{content[:25]}{'...' if len(content) > 25 else ''}\""
elif action == "replace": elif action == "replace":
return f"~{target}: \"{_oneline(args.get('old_text', '')[:20])}\"" old = _oneline(args.get("old_text") or "") or "<missing old_text>"
return f"~{target}: \"{old[:20]}\""
elif action == "remove": elif action == "remove":
return f"-{target}: \"{_oneline(args.get('old_text', '')[:20])}\"" old = _oneline(args.get("old_text") or "") or "<missing old_text>"
return f"-{target}: \"{old[:20]}\""
return action return action
if tool_name == "send_message": if tool_name == "send_message":
@ -939,9 +941,13 @@ def get_cute_tool_message(
if action == "add": if action == "add":
return _wrap(f"┊ 🧠 memory +{target}: \"{_trunc(args.get('content', ''), 30)}\" {dur}") return _wrap(f"┊ 🧠 memory +{target}: \"{_trunc(args.get('content', ''), 30)}\" {dur}")
elif action == "replace": elif action == "replace":
return _wrap(f"┊ 🧠 memory ~{target}: \"{_trunc(args.get('old_text', ''), 20)}\" {dur}") old = args.get("old_text") or ""
old = old if old else "<missing old_text>"
return _wrap(f"┊ 🧠 memory ~{target}: \"{_trunc(old, 20)}\" {dur}")
elif action == "remove": elif action == "remove":
return _wrap(f"┊ 🧠 memory -{target}: \"{_trunc(args.get('old_text', ''), 20)}\" {dur}") old = args.get("old_text") or ""
old = old if old else "<missing old_text>"
return _wrap(f"┊ 🧠 memory -{target}: \"{_trunc(old, 20)}\" {dur}")
return _wrap(f"┊ 🧠 memory {action} {dur}") return _wrap(f"┊ 🧠 memory {action} {dur}")
if tool_name == "skills_list": if tool_name == "skills_list":
return _wrap(f"┊ 📚 skills list {args.get('category', 'all')} {dur}") return _wrap(f"┊ 📚 skills list {args.get('category', 'all')} {dur}")

View file

@ -83,6 +83,13 @@ class TestBuildToolPreview:
assert result is not None assert result is not None
assert "user" in result assert "user" in result
def test_memory_replace_missing_old_text_marked(self):
# Avoid empty quotes "" in the preview when old_text is missing/None.
result = build_tool_preview("memory", {"action": "replace", "target": "memory"})
assert result == '~memory: "<missing old_text>"'
result = build_tool_preview("memory", {"action": "remove", "target": "memory", "old_text": None})
assert result == '-memory: "<missing old_text>"'
def test_session_search_preview(self): def test_session_search_preview(self):
result = build_tool_preview("session_search", {"query": "find something"}) result = build_tool_preview("session_search", {"query": "find something"})
assert result is not None assert result is not None