The system prompt was advertising all tools to every agent, but
the runtime only dispatched the agent's actual subset. This caused
unconscious agents to call tools that returned "Unknown tool."
Agent::new now takes the tool list explicitly. Each caller passes
its own tools — the prompt and runtime always match. MCP tool
definitions are still appended for agents that use them.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The old code wrote a JSON object with named section keys, which
serde_json serialized in alphabetical order — putting conversation
before system, making logs misleading. Write a single flat array
in section order instead, matching what the model actually sees.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Move state_path to a field on State (default thalamus-state.json) so
the Claude daemon can use its own file without collision. Add a
serde(flatten) extra map to Persisted so callers can round-trip
additional fields (e.g. claude_pane) through save/load.
save() is now &mut self.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
turn_started, call_started, call_timeout_secs were declared and
initialized but never read.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
SectionTree.scroll is now a ScrollPaneState. All callers of
render_scrollable replaced with ScrollPane::render_stateful_widget.
Deleted render_scrollable and its imports — no hand-rolled scroll
rendering remains outside of scroll_pane.rs.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
Replace bare history_scroll: u16 with ScrollPaneState. The history
pane now uses ScrollPane for rendering, getting proper height caching
and scrollbar for free.
Also relax ScrollItem lifetime bounds from 'static to 'a so
non-static Lines (built on the fly during render) can be used.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
Both had scroll: u16 fields that were never connected to any key
handling or rendering. The unconscious screen renders fixed-size
graph health gauges; thalamus builds a paragraph but never scrolled
it. Neither needs scroll state.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
draw_conversation_pane and draw_pane now delegate all scroll
bookkeeping and rendering to the ScrollPane widget. The conversation
pane builds MarkedLine items (line + gutter marker), applies
selection highlighting, and passes them to the widget. The simpler
panes just pass lines directly.
Removed dead code from scroll_pane: BorrowedItem, scroll_to_bottom,
heights(), ensure_heights_for_lines — all superseded by the widget
doing the work internally through the ScrollItem trait.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
New ScrollPaneState centralizes height caching, scroll offset,
pin-to-bottom, visible range computation, and screen-to-item
coordinate mapping. Replaces the hand-rolled scroll bookkeeping
that was duplicated across draw_conversation_pane and draw_pane.
-170 lines from chat.rs. The scroll_pane module also includes a
ScrollPane StatefulWidget ready to wire up for the next step:
collapsing the draw functions into render_stateful_widget calls.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
Design document for wiring the model's internal uncertainty, error
detection, and emotional valence circuits to the observe agent.
Based on contrastive activation probing (CAA, ACL 2024). Most of the
infrastructure already exists in extract_steering_vector.py and
vllm_export_hook.py — the bottleneck is building contrastive datasets.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
One misbehaving channel daemon (accepting connections but not
responding to capnp RPCs) would block channel_list indefinitely.
Spawn each daemon query as a separate task with a 3-second timeout.
A hung daemon now shows as disconnected instead of hanging the
entire tool call.
Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
Instead of reimplementing filtering logic, journal_tail builds a
query string (type + sort + age + limit) and delegates to query().
Supports format and after parameters. Removes keys_only in favor
of format:"compact". Digest agent updated to use dates not key names.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Format memory_query and journal_tail parameter JSON as indented
multi-line for readability. Add JSON Schema "default" values and
document the "format" parameter on memory_query.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Rewrite digest.agent to be fully autonomous — it uses journal_tail
to discover what needs digesting and generates digests during its
run. No more pre-populated {{CONTENT}}/{{LEVEL}} placeholders.
Extend journal_tail with level parameter (0=journal, 1=daily,
2=weekly, 3=monthly) and keys_only mode. Also include node keys
in full output for better agent context.
Remove stale format:"neighborhood" case from memory_query.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Add "format": "full" option to memory_query that renders with
full content, graph metrics, and hub analysis (format_nodes_section).
Convert 6 agents (linker, challenger, connector, extractor, replay,
transfer) to inline their queries via {{tool: memory_query}} instead
of separate header query + {{nodes}} placeholder.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Text cosine similarity was being used as a crutch for operations
the graph structure should handle: interference detection, orphan
linking, triangle closing, hub differentiation. These are all
graph-structural operations that the agents (linker, extractor)
handle with actual semantic understanding.
Removed: similarity.rs (stemming + cosine), rewrite.rs (orphan
linking, triangle closing, hub differentiation), detect_interference,
and all CLI commands and consolidation steps that used them.
-794 lines.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Interference detection via O(n²) text cosine similarity is
redundant — the graph structure should surface similar nodes
through link topology, shared neighbors, and community detection.
The other agents (linker, extractor) already maintain these
relationships.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Convert {{topology}}, {{health}}, {{pairs}} placeholders to
{{tool:}} calls. Made format_topology_header, format_health_section,
format_pairs_section pub so tools can call them.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Use the new {{tool:}} placeholder mechanism instead of the
special-purpose {{node:}} resolver. All 17 unconscious agent
files converted.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Agent templates can now inline tool call results with
{{tool: tool_name args}}. Dispatches to the same store
operations the tools use, but runs synchronously during
prompt resolution. Supports memory_render, memory_query,
memory_search, memory_links, and journal_tail.
This replaces the need for special-purpose placeholders —
{{pairs}}, {{rename}}, etc. can be expressed as queries
through {{tool: memory_query {"query": "..."}}} instead.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
MemoryNode::load() was calling Store::load() on every render,
hitting disk each time. Use cached_store() + MemoryNode::from_store()
so repeated renders (4 per agent template) share the cached store.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
compute_run_stats() walks the conversation AST after each agent
completes, counting messages and tool calls by tool name. Stats
are returned from save_agent_log(), stored on UnconsciousAgent,
and displayed in the agent list UI.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Save all context sections (system, identity, journal, conversation)
to per-agent log files for both subconscious and unconscious agents.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Pick the agent that ran longest ago (or never) instead of
scanning alphabetically. Fairness via min_by_key(last_run).
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Instead of managing idle timers in the mind event loop, the
unconscious agents run on a dedicated task that watches a
conscious_active channel. 60s after conscious activity stops,
agents start looping. Conscious activity cancels the timer.
Expose mind state (DMN, scoring, unconscious timer) on the
thalamus screen.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Subconscious agents inject DMN nodes (reflections, thalamus nudges)
into the conversation. These were being counted as conversation
advancement, causing agents to trigger each other in a feedback loop
even with no conscious activity.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Gate unconscious agents on 60s of no conscious activity using
sleep_until() instead of polling. Remove COOLDOWN constant — once
idle, agents run back-to-back to keep the GPU busy.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
Step prompts in oneshot agents are instructions, not user messages —
use system_msg instead of user_msg.
Co-Authored-By: ProofOfConcept <poc@bcachefs.org>
The full matrix scorer was deleted during the AST conversion. Restore
it: /score runs score_memories() which computes divergence for every
memory × response pair, stores the MemoryScore on MindState, and
displays per-memory weights with bar charts on the F2 screen.
Both scoring paths now use ActivityGuard::update() for live progress
in the status bar instead of creating a new activity per iteration.
Also bumps score API timeout from 120s to 300s and adds progress
logging throughout.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
tool_call labels now show the arguments truncated to 80 chars:
tool: memory_render({"key":"identity"})
instead of just:
tool_call: memory_render
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
MCP server spawn failures were going to dbglog where the user
wouldn't see them. Route through the agent's notify so they appear
on the status bar.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Duplicate key warnings fire on every store load and were writing to
stderr, corrupting the TUI display. Log write warnings and MCP
server failures are similarly routine. Route these to dbglog.
Serious errors (rkyv snapshot failures, store corruption) remain on
stderr — those are real problems the user needs to see.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The status bar timer was showing turn/call elapsed times (0s, 0/60s)
instead of the activity's actual elapsed time. Use activity_started
from the ActivityEntry directly.
Add a 1s tick to the UI select loop when an activity is active so
the timer updates live.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Instead of two separate notifications piling up on the status bar,
use a single ActivityGuard that updates in place during overflow
retries and auto-completes when the turn finishes.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Lets long-running operations update their status bar message without
creating/dropping a new activity per iteration. Useful for loops
like memory scoring where you want "scoring: 3/25 keyname" updating
in place.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Memory node keys were running into the token count column. Bump the
name column from 40 to 70 characters.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>