Say what a tool did, not where it ran
An agent event set its label to the SSH profile's name, so the transcript read "homeserver · ls -la" -- naming the machine rather than the thing that was done. Built-in tools set no label at all and fell back to the function name, so a saved memory read "memory_add". The status line said "Running shell_run…" and the approval card had its own hand-written wording. Four places, four answers, nothing checking that any of them agreed. services/tool_labels.py is the one table all of them read now. Bash, Read, Write, List, Web search, Memory saved; an icon each, instead of everything being the sparkle. The precedence is inverted on purpose. Tool events are persisted in Message.tool_calls_json, so every agent row already on disk carries the profile name -- a resolver that preferred the stored value would fix nothing for any transcript that already exists. So a name the table knows resolves from the table, and a name it does not -- a custom HTTP tool, an MCP tool, whose labels are per row and cannot be tabulated -- keeps its own. One rule, both cases correct. The machine moves to `detail`, where "where this ran" belongs. tool_label and tool_icon are Jinja globals because a message bubble is rendered from four handlers, and a fifth thing each of them must remember to pass is a fifth thing one of them will forget. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -42,16 +42,31 @@ FAMILY_AGENT = "agent"
|
||||
# stored on every message forever.
|
||||
MAX_EVENT_CHARS = 4000
|
||||
|
||||
# And how much of a diff. Same reasoning as the constant above and the same
|
||||
# ceiling in spirit: a generated file's diff can be larger than the file, and
|
||||
# this one is stored on the row forever and re-parsed on every page load.
|
||||
MAX_DIFF_LINES = 200
|
||||
|
||||
_STRING = {"type": "string"}
|
||||
|
||||
|
||||
def _event(name: str, context: AgentContext, summary: str, **extra: Any) -> dict[str, Any]:
|
||||
"""One line in the transcript for one call.
|
||||
|
||||
No `label`. What a tool is called is decided by `services/tool_labels.py`,
|
||||
for every tool at once -- this used to write the SSH profile's name here, so
|
||||
a bubble said "homeserver · ls -la" and named the machine rather than the
|
||||
thing that was done. The machine is a fact about *where*, so it belongs with
|
||||
the directory in `detail`, which the template already renders in the body.
|
||||
"""
|
||||
where = context.label
|
||||
if context.project_dir:
|
||||
where = f"{where}:{context.project_dir}"
|
||||
return {
|
||||
"name": name,
|
||||
"kind": "agent",
|
||||
"label": f"{context.label}",
|
||||
"query": summary,
|
||||
"detail": context.project_dir or "",
|
||||
"detail": where,
|
||||
"results": [],
|
||||
**extra,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user