SubconsciousSharedState holds walked keys shared between all
subconscious agents. Enables splitting surface-observe into separate
surface and observe agents that share the same walked state.
Walked is passed to run_forked() at run time instead of living on
AutoAgent. UI shows walked count in the subconscious screen header.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
F3 screen now displays SubconsciousSnapshot from Mind's AutoAgents
instead of the old process-based AgentSnapshot. Shows running status
(phase + turn), last run time, and walked key count.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Replace pop+push of streaming entries with finalize_streaming() which
finds the unstamped assistant entry and updates it in place. The
streaming entry IS the assistant message — just stamp it when done.
Also: set dirty flag on agent_changed/turn_watch so the TUI actually
redraws when the agent state changes. Publish context state on F2
switch so the debug screen shows current data.
Age out images during compact() so old screenshots don't bloat the
request payload on startup.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- Budget now counts exact message tokens matching what assemble_api_messages
sends, not raw string content. Eliminates undercounting from formatting
overhead (journal headers, personality separators, working stack).
- Load journal before trimming so trim accounts for journal cost.
- Compact before every turn, not just after turn completion. Prevents
agent_cycle surfaced memories from pushing context over budget.
- Move agent_cycle orchestration from Agent::turn to Mind::start_turn —
surfaced memories and reflections now precede the user message.
- Move AgentCycleState from Agent to Mind — it's orchestration, not
per-agent state. memory_scoring_in_flight and memory_scores stay on
Agent where they belong.
- Tag DMN entries as ConversationEntry::Dmn — compaction evicts them
first since they're ephemeral. Compaction also prefers evicting
memories over conversation when memories exceed 50% of entry tokens.
- Kill /retry slash command.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
active_screen is now the F-key number (1-based), dispatch is just
screens[active_screen - 1].tick() everywhere. Eliminates the
special-cased interact variable and duplicated if/else branching.
Also adds diff_mind_state() for dirty-flag tracking and gates the
bottom-of-loop render on dirty, avoiding redundant redraws.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
append_text was the TextDelta streaming handler — replaced by
append_streaming on Agent entries. needs_assistant_marker tracked
turn boundaries for the old message path. target removed from
Agent::turn — routing now determined by entry content.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Streaming text now goes directly to agent entries via append_streaming().
sync_from_agent diffs the growing entry each tick. The streaming entry
is popped when the response completes; build_response_message pushes
the final version.
All status feedback uses RAII ActivityGuards:
- push_activity() for long-running work (thinking, streaming, scoring)
- notify() for instant feedback (compacted, DMN state changes, commands)
- Guards auto-remove on Drop, appending "(complete)" and lingering 5s
- expire_activities() cleans up timed-out notifications on render tick
UiMessage enum reduced to a single Info variant with zero sends.
The channel infrastructure remains for now (Mind/Agent still take
UiSender in signatures) — mechanical cleanup for a follow-up.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
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>
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>
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>
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>
Create overlay screens vec (ConsciousScreen, SubconsciousScreen,
UnconsciousScreen, ThalamusScreen). F-keys switch active_screen.
Screen tick() called during render phase with pending key event.
Screen actions (Switch, Hotkey) applied after draw.
Interact (F1) still draws via App::draw_main(). Overlay screens
draw via ScreenView::tick(). State persists across switches.
Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
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>
All crossterm imports go through ratatui::crossterm. Direct crossterm
dep kept only for the event-stream feature flag (EventStream for
async terminal input).
Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
The top-level run() that creates Mind, wires channels, spawns the
Mind event loop, and starts the UI event loop is orchestration —
it belongs with the UI entry point, not in the cognitive layer.
Renamed to event_loop::start(cli). mind/mod.rs is now purely the
Mind struct: state machine, MindCommand, and the run loop.
Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
Mind::run() owns the cognitive event loop: user input, turn results,
DMN ticks, hotkey actions. The UI event loop (user/event_loop.rs) owns
the terminal: key events, render ticks, channel status display.
They communicate through channels: UI sends MindMessage (user input,
hotkey actions) to Mind. Mind sends UiMessage (status, info) to UI.
UI reads shared state (active tools, context) directly for rendering.
Removes direct coupling between Mind and App:
- cycle_reasoning no longer takes &mut App
- AdjustSampling updates agent only, UI reads from shared state
- /quit handled by UI directly, not routed through Mind
Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
Disables memory scoring, surface, and observe agents when set.
Useful for testing with external backends (e.g. OpenRouter) where
background agent traffic would be slow and unnecessary.
Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
journal_tools() was only in memory_and_journal_tools() for
subconscious agents — not in the main tools() registry. Added
so consciousness and MCP server can use journal_new/tail/update.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
F5 screen now shows temperature, top_p, top_k with interactive
adjustment:
- Up/down: select parameter
- Left/right: adjust value (0.05 steps for temp/top_p, 5 for top_k)
- Updates Agent and display immediately via HotkeyAction
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Move temperature from a per-call parameter to an Agent field,
add top_p and top_k. All three are sent to the API via a new
SamplingParams struct, displayed on the F5 thalamus screen.
Defaults: temperature=0.6, top_p=0.95, top_k=20 (Qwen3.5 defaults).
Also adds top_p and top_k to ChatRequest so they're sent in the
API payload. Previously only temperature was sent.
UI controls for adjusting these at runtime are not yet implemented.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The agent lock was held for the entire duration of turn() — including
API streaming and tool dispatch awaits. This blocked the UI thread
whenever it needed the lock (render tick, compaction check, etc.),
causing 20+ second freezes.
Fix: turn() takes Arc<Mutex<Agent>> and manages locking internally.
Lock is held briefly for prepare/process phases, released during all
I/O (streaming, tool awaits, sleep retries). Also:
- check_compaction: spawns task instead of awaiting on event loop
- start_memory_scoring: already spawned, no change needed
- dispatch_tool_call_unlocked: drops lock before tool handle await
- Subconscious screen: renders all agents from state dynamically
(no more hardcoded SUBCONSCIOUS_AGENTS list)
- Memory scoring shows n/m progress in snapshots
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Mechanical rename: src/agent/ -> src/user/, all crate::agent:: ->
crate::user:: references updated. Binary poc-agent renamed to
consciousness with CLI name and user-facing strings updated.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>