Bug Description
Reporter: Cygnus (Discord; please ping in replies) via the WebUI testers thread.
Cygnus is now seeing CLI sessions appear inline in her sidebar (this is the recent feature shipping correctly), but when she opens one she sees only the user/assistant prose — none of the tool calls that the agent actually made during the CLI run are rendered. For short tool-heavy CLI sessions this leaves the transcript almost empty.
Ooo, finally experiencing the CLI Sessions opening in new *chats. Neat...
- I remember an update about some way to filter them out - where do I find that?
- How do I make CLI tools show everything they're doing? I'm not seeing their tool calls. Since they're so short, I'd like to see everything
- I feel like this is something another sidebar would be excellent for, maybe
(May 7 2026, 01:32 UTC)
Root cause — get_cli_session_messages() strips tool-call columns
api/models.py:1621 get_cli_session_messages() reads CLI session content from state.db.messages with this query:
cur.execute("""
SELECT role, content, timestamp
FROM messages
WHERE session_id = ?
ORDER BY timestamp ASC
""", (sid,))
msgs = []
for row in cur.fetchall():
msgs.append({
'role': row['role'],
'content': row['content'],
'timestamp': row['timestamp'],
})
But the actual state.db.messages schema (verified live on this host) has all the metadata we need:
0 id INTEGER
1 session_id TEXT NOT NULL
2 role TEXT NOT NULL
3 content TEXT
4 tool_call_id TEXT
5 tool_calls TEXT ← assistant message's tool_calls JSON, dropped today
6 tool_name TEXT ← tool-result row's tool name, dropped today
7 timestamp REAL NOT NULL
8 token_count INTEGER
9 finish_reason TEXT
10 reasoning TEXT
11 reasoning_details TEXT
12 codex_reasoning_items TEXT
13 reasoning_content TEXT
14 codex_message_items TEXT
The tool_calls column on assistant rows holds the JSON of every tool call the agent made for that turn; the tool_call_id + tool_name + content columns on role='tool' rows hold the result. Both halves are dropped on the floor by the current SELECT.
I verified live on this host's state.db:
('assistant', 110) # text-bearing assistant reply
('assistant', 0) # text-empty assistant — these are pure tool_calls turns!
('assistant', 0)
('tool', '{"success": true, "name": "hermes-agent-setup", ...}')
('tool', '{"success": false, "error": "Skill ... not found"}')
Two of those five recent assistant rows have zero text content — they're tool-only turns whose entire payload lives in the tool_calls column the loader doesn't pull. The corresponding role='tool' rows that hold the results are also being read but their tool_name / tool_call_id are stripped, so the WebUI's tool-card renderer (static/messages.js near tool_calls handling) has nothing to attach them to even if they reached the client.
Suggested fix
-
Extend the SELECT to pull every column the WebUI's tool-call renderer expects. Add tool_call_id, tool_calls, tool_name (at minimum). Optionally also pull reasoning / reasoning_content / reasoning_details so CLI sessions that use Anthropic's extended thinking show their reasoning blocks too.
-
Pass them through into the per-message dicts. The frontend already understands tool_calls metadata on assistant messages (see static/sessions.js:968-973 hasMessageToolMetadata check). For role='tool' rows, the existing tool-result rendering path should pick them up once the fields arrive.
-
Bump the version stamp on import_cli_session() so re-imports rebuild with the richer metadata. Otherwise a previously-imported CLI session stays empty even after the loader is fixed.
A defensive companion: when role='assistant' AND content is empty AND tool_calls is empty too (a malformed row from an interrupted CLI turn), don't render the empty bubble — currently we'd render a blank assistant message.
Severity
M2 — visible data loss for any user opening a CLI/external session in the WebUI. Doesn't affect WebUI-native sessions (those have full metadata in their JSON files). Cygnus's framing — "since they're so short, I'd like to see everything" — is exactly the use case this is broken for: short tool-heavy quick CLI invocations are exactly the ones where text content is minimal and tool calls ARE the content.
Reporter
@CygnusIgnis via WebUI Discord testers thread, May 7 2026.
Related
Bug Description
Reporter: Cygnus (Discord; please ping in replies) via the WebUI testers thread.
Cygnus is now seeing CLI sessions appear inline in her sidebar (this is the recent feature shipping correctly), but when she opens one she sees only the user/assistant prose — none of the tool calls that the agent actually made during the CLI run are rendered. For short tool-heavy CLI sessions this leaves the transcript almost empty.
Root cause —
get_cli_session_messages()strips tool-call columnsapi/models.py:1621get_cli_session_messages()reads CLI session content fromstate.db.messageswith this query:But the actual
state.db.messagesschema (verified live on this host) has all the metadata we need:The
tool_callscolumn on assistant rows holds the JSON of every tool call the agent made for that turn; thetool_call_id+tool_name+contentcolumns onrole='tool'rows hold the result. Both halves are dropped on the floor by the current SELECT.I verified live on this host's
state.db:Two of those five recent assistant rows have zero text content — they're tool-only turns whose entire payload lives in the
tool_callscolumn the loader doesn't pull. The correspondingrole='tool'rows that hold the results are also being read but theirtool_name/tool_call_idare stripped, so the WebUI's tool-card renderer (static/messages.jsnear tool_calls handling) has nothing to attach them to even if they reached the client.Suggested fix
Extend the SELECT to pull every column the WebUI's tool-call renderer expects. Add
tool_call_id,tool_calls,tool_name(at minimum). Optionally also pullreasoning/reasoning_content/reasoning_detailsso CLI sessions that use Anthropic's extended thinking show their reasoning blocks too.Pass them through into the per-message dicts. The frontend already understands tool_calls metadata on assistant messages (see
static/sessions.js:968-973hasMessageToolMetadatacheck). Forrole='tool'rows, the existing tool-result rendering path should pick them up once the fields arrive.Bump the version stamp on
import_cli_session()so re-imports rebuild with the richer metadata. Otherwise a previously-imported CLI session stays empty even after the loader is fixed.A defensive companion: when
role='assistant'ANDcontentis empty ANDtool_callsis empty too (a malformed row from an interrupted CLI turn), don't render the empty bubble — currently we'd render a blank assistant message.Severity
M2 — visible data loss for any user opening a CLI/external session in the WebUI. Doesn't affect WebUI-native sessions (those have full metadata in their JSON files). Cygnus's framing — "since they're so short, I'd like to see everything" — is exactly the use case this is broken for: short tool-heavy quick CLI invocations are exactly the ones where text content is minimal and tool calls ARE the content.
Reporter
@CygnusIgnis via WebUI Discord testers thread, May 7 2026.
Related