Commit graph

14 commits

Author SHA1 Message Date
ProofOfConcept
eafc2887a3 Kill StatusUpdate, Activity, DmnAnnotation, ContextInfoUpdate, AgentUpdate
Status bar reads directly from Agent and MindState on each render tick.
Activity is now a field on Agent — set by agent code directly, read by
UI via try_lock. DmnAnnotation, ContextInfoUpdate, AgentUpdate were
already dead (no senders).

UiMessage down to 4 variants: TextDelta, Reasoning, Debug, Info.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 21:34:27 -04:00
ProofOfConcept
1745e03550 Kill UiMessage variants replaced by state-driven rendering
sync_from_agent reads directly from agent entries, so remove:
- UserInput (pending input shown from MindState.input)
- ToolCall, ToolResult (shown from entries on completion)
- ToolStarted, ToolFinished (replaced by shared active_tools)
- replay_session_to_ui (sync_from_agent handles replay)

-139 lines. Remaining variants are streaming (TextDelta, Reasoning),
status bar state, or ephemeral UI messages (Info, Debug).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 21:21:08 -04:00
ProofOfConcept
48beb8b663 Revert to tokio::sync::Mutex, fix lock-across-await bugs, move input ownership to InteractScreen
The std::sync::Mutex detour caught every place a MutexGuard lived
across an await point in Agent::turn — the compiler enforced Send
safety that tokio::sync::Mutex silently allows. With those fixed,
switch back to tokio::sync::Mutex (std::sync blocks tokio worker
threads and panics inside the runtime).

Input and command dispatch now live in InteractScreen (chat.rs):
- Enter pushes directly to SharedMindState.input (no app.submitted hop)
- sync_from_agent displays pending input with dimmed color
- Slash command table moved from event_loop.rs to chat.rs
- cmd_switch_model kept as pub fn for tool-initiated switches

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 21:13:48 -04:00
Kent Overstreet
f29b4be09c Move chat code to chat.rs 2026-04-05 20:08:18 -04:00
Kent Overstreet
65d23692fb chat: route_entry returns Vec for multi-tool-call entries
An assistant entry can have text + multiple tool calls. route_entry
now returns Vec<(PaneTarget, String, Marker)> — tool calls go to
tools pane, text goes to conversation, all from the same entry.

Pop phase iterates the vec in reverse to pop correct number of
pane items per entry.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:43:48 -04:00
Kent Overstreet
222b2cbeb2 chat: PartialEq on ConversationEntry for proper diff
Add PartialEq to Message, FunctionCall, ToolCall, ContentPart,
ImageUrl, MessageContent, ConversationEntry. Sync now compares
entries directly instead of content lengths.

Phase 1 pops mismatched tail entries using PartialEq comparison.
Phase 2 pushes new entries with clone into last_entries buffer.

TODO: route_entry needs to handle multiple tool calls per entry.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:41:16 -04:00
Kent Overstreet
ca9f2b2b9a chat: double-buffered sync with content-length diffing
Store content lengths of rendered entries. On each tick:
- Generation changed → full pane reset
- Entries removed → pop from tail
- Last entry content length changed → pop and re-render (streaming)
- New entries → route and push

PaneState gains pop_line() for removing the last rendered entry.
This handles streaming (last entry growing), compaction (generation
bump), and normal appends.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:35:19 -04:00
Kent Overstreet
563771e979 chat: route_entry helper separates routing from sync
PaneTarget enum + route_entry() function: given a ConversationEntry,
returns which pane it belongs to (or None to skip). The sync loop
becomes: detect desync → pop, then route new entries.

Routing: User→Conversation, Assistant→ConversationAssistant,
tool_calls→Tools, Tool results→ToolResult, Memory/System→None.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:27:14 -04:00
Kent Overstreet
b89bafdf6b chat: full entry type routing in sync_from_agent
Route agent entries to correct panes:
- User messages → conversation (cyan, User marker)
- Assistant text → conversation (Assistant marker)
- Assistant tool_calls → tools pane (yellow)
- Tool results → tools pane (truncated at 20 lines)
- Memory/system-reminder entries → skipped
- System role → skipped

Two phases: detect generation change (reset panes if needed),
then route new entries. PaneState is the rendered view of agent
entries, updated incrementally.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:22:31 -04:00
Kent Overstreet
350c447ebc chat: state-driven sync from agent entries
InteractScreen holds agent ref, syncs conversation display from
agent.entries() on each tick via blocking_lock(). Tracks generation
counter and entry count to detect compactions and new entries.

Agent gets a generation counter, incremented on compaction and
non-last-entry mutations (age_out_images).

sync_from_agent() is the single path for pane updates. UiMessage
handle_ui_message still exists but will be removed once sync
handles all entry types (streaming, tool calls, DMN).

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:17:13 -04:00
Kent Overstreet
6f000bd0f6 user: hook up screen_legend from ScreenView::label()
Build legend string from actual screen labels instead of hardcoded
constant. Computed once at startup via OnceLock, accessible from
all screen draw methods.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 19:03:06 -04:00
Kent Overstreet
68f115b880 user: InteractScreen extracted, all screens use ScreenView trait
InteractScreen in chat.rs owns conversation/autonomous/tools panes,
textarea, input history, scroll state. App is now just shared state
(status, sampling params, agent_state, channel_status, idle_info).

Event loop holds InteractScreen separately for UiMessage routing.
Overlay screens (F2-F5) in screens vec. F-key switching preserves
state across screen changes.

handle_ui_message moved from App to InteractScreen.
handle_key split: global keys on App, screen keys in tick().
draw dispatch eliminated — each screen draws itself.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 18:57:54 -04:00
Kent Overstreet
927cddd864 user: ScreenView trait, overlay screens extracted from App
Convert F2-F5 screens to ScreenView trait with tick() method.
Each screen owns its view state (scroll, selection, expanded).
State persists across screen switches.

- ThalamusScreen: owns sampling_selected, scroll
- ConsciousScreen: owns scroll, selected, expanded
- SubconsciousScreen: owns selected, log_view, scroll
- UnconsciousScreen: owns scroll

Removed from App: Screen enum, debug_scroll, debug_selected,
debug_expanded, agent_selected, agent_log_view, sampling_selected,
set_screen(), per-screen key handling, draw dispatch.

App now only draws the interact (F1) screen. Overlay screens are
drawn by the event loop via ScreenView::tick. F-key routing and
screen instantiation to be wired in event_loop next.

InteractScreen (state-driven, reading from agent entries) is the
next step — will eliminate the input display race condition.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 17:54:40 -04:00
Kent Overstreet
79e384f005 split out src/mind 2026-04-04 02:46:32 -04:00
Renamed from src/user/tui/main.rs (Browse further)