lowest_scored_memory() now skips memories with score=None. Unscored
memories haven't been evaluated — dropping them before scored
low-value ones loses potentially important context.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Build a synthetic "Memory nodes (N scored, M unscored)" section in
the context screen by extracting Memory entries from the conversation
section. Each node shows its key and score. Inserted before the
conversation section so scores are visible at a glance.
This makes it easy to see whether scoring is keeping up — if unscored
count is high relative to scored, scoring needs to run more often.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
trim_entries is now a simple loop:
1. Drop duplicate memories and DMN entries
2. While over budget: if memories > 50% of entry tokens, drop
lowest-scored memory; otherwise drop oldest conversation entry
3. Snap to user message boundary
ContextBudget is gone — sections already have cached token totals:
- total_tokens() on ContextState replaces budget.total()
- format_budget() on ContextState replaces budget.format()
- trim() takes fixed_tokens: usize (system + identity + journal)
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
New types — not yet wired to callers:
- ContextEntry: wraps ConversationEntry with cached token count and
timestamp
- ContextSection: named group of entries with cached token total.
Private entries/tokens, read via entries()/tokens().
Mutation via push(entry), set(index, entry), del(index).
- ContextState: system/identity/journal/conversation sections + working_stack
- ConversationEntry::System variant for system prompt entries
Token counting happens once at push time. Sections maintain their
totals incrementally via push/set/del. No more recomputing from
scratch on every budget check.
Does not compile — callers need updating.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
compact() already computes context_budget() — pass it to trim_entries
so it has access to all budget components without recomputing them.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Scores are saved to memory-scores.json alongside the conversation log
after each scoring run, and loaded on startup — no more re-scoring
on restart.
trim_entries now evicts lowest-scored memories first (instead of
oldest-first) when memories exceed 50% of context. The 50% threshold
stays as a heuristic for memory-vs-conversation balance until we have
a scoring signal for conversation entries too. Unscored memories get
0.0, so they're evicted before scored ones.
save_memory_scores rebuilds from current entries, so evicted memories
are automatically expired from the scores file.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
subconscious_snapshots() was acquiring store→subconscious while
collect_results() holds subconscious→store — classic ABBA deadlock.
Fix: always acquire subconscious first, store second. Store is the
bottom-most lock in the ordering.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Moved persistent_state from per-agent to a single shared BTreeMap on
Subconscious. All agents read/write the same state — surface's walked
keys are visible to observe and reflect, etc.
- Subconscious.state: shared BTreeMap<String, String>
- walked() derives from state["walked"] instead of separate Vec
- subconscious-state.json is now a flat key-value map
- All agent outputs merge into the shared state on completion
- Loaded on startup, saved after any agent completes
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
SectionTree:
- 'e': expand all nodes
- 'c': collapse all nodes
- Home/End already wired from previous commit
Key legend shown at bottom border of each focused pane:
- Tree panes: nav, expand/collapse, expand/collapse all, paging
- Agent list: select, tab
- History: scroll, paging
Legend only appears on the focused pane to avoid clutter.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
SectionTree.handle_nav() now takes viewport height:
- PgUp/PgDn move both cursor and viewport by one page, keeping the
cursor at the same screen position
- Home/End jump to first/last item
- scroll_to_selected() uses actual viewport height instead of
hardcoded 30
Added render_scrollable() in widgets.rs: renders a Paragraph with a
vertical Scrollbar when content exceeds the viewport. Used by the
conscious and subconscious screens.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
New layout for F3 screen:
- Top-left: agent list using ratatui List widget with ListState
- Middle-left: expandable agent state (persistent across runs)
- Bottom-left: memory store activity by provenance, walked keys
- Right: context tree from fork point, reusing SectionTree
Tab/Shift-Tab cycles focus clockwise between panes; focused pane
gets white border. Each pane handles its own input when focused.
Extracted user/widgets.rs:
- SectionTree (moved from mod.rs): expand/collapse tree for ContextSection
- pane_block_focused(): standard bordered block with focus indicator
- format_age()/format_ts_age(): shared duration formatting
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- Agent state (outputs) persists across runs in subconscious-state.json,
loaded on startup, saved after each run completes
- Merge semantics: each run's outputs accumulate into persistent_state
rather than replacing
- Walked keys restored from surface agent state on load
- Store::recent_by_provenance() queries nodes by agent provenance for
the store activity view
- Switch outputs from HashMap to BTreeMap for stable display ordering
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
context_state_summary() was used for both compaction decisions (just
needs token counts) and debug screen display (needs full tree with
labels). Split into:
- Agent::context_budget() -> ContextBudget: cheap token counting by
category, used by compact(), restore_from_log(), mind event loop
- ContextBudget::format(): replaces sections_budget_string() which
fragily pattern-matched on section name strings
- context_state_summary(): now UI-only, formatting code stays here
Also extracted entry_sections() as shared helper with include_memories
param — false for context_state_summary (memories have own section),
true for conversation_sections_from() (subconscious screen shows all).
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Add provenance field to Agent, set to "agent:{name}" for forked
subconscious agents. Memory tools (write, link_add, supersede,
journal_new, journal_update) now read provenance from the Agent
context when available, falling back to "manual" for interactive use.
AutoAgent passes the forked agent to dispatch_with_agent so tools
can access it.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The final assistant response in run_with_backend wasn't being pushed
to the backend — only intermediate step responses were. This meant
the subconscious debug screen only showed the prompt, not the full
conversation.
Now push assistant response immediately after receiving it, before
checking for next steps. Remove the duplicate push in the multi-step
path.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
hippocampus: cursor navigation, transcript parsing, similarity
functions to pub(crate). counters::open() made private.
subconscious: all format_* prompts helpers to pub(super),
load_defs and keys_to_replay_items made private,
consolidate_full_with_progress made private.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Only Message, Role, MessageContent, ContentPart, ToolCall,
FunctionCall, Usage, ImageUrl are pub-exported from agent::api.
Internal types (ChatRequest, ChatCompletionChunk, ChunkChoice,
Delta, ReasoningConfig, ToolCallDelta, FunctionCallDelta) are
pub(crate) — invisible outside the crate.
All callers updated to import from agent::api:: instead of
agent::api::types::.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
scan_pid_files was removed as dead code but it was actually needed
by the hook path — the bug was that it was never wired in. Add
reap_agent_pids() directly to poc-hook.rs and call it on every
UserPromptSubmit. Kills timed-out agents (10min) and cleans up
pid files for dead processes.
Also remove dead subconscious/subconscious.rs (420 lines) — was
forked to claude/agent_cycles.rs and never removed.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
redb: add ReadableDatabase trait import for begin_read().
tui-markdown: disable highlight-code (drops syntect), fix
test deps leaking into normal dependencies.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Point to koverstreet/tui-markdown which replaces tracing with log.
tracing is now completely gone from the dependency tree.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
New src/agent/api/http.rs: ~240 lines, supports GET/POST, JSON/form
bodies, SSE streaming via chunk(), TLS via rustls. No tracing dep.
Removes reqwest from the main crate and telegram channel crate.
Cargo.lock drops ~900 lines of transitive dependencies.
tracing now only pulled in by tui-markdown.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
RPC trait methods changed from &mut self to self: Rc<Self> and
return types from Promise<(), Error> to impl Future<Output = Result<...>>.
Updated all Server impls across 6 files: DaemonImpl (rpc.rs),
NotifyForwarder (channels.rs), and ChannelServerImpl in all channel
crates (irc, telegram, tmux, socat). Local pry! macro replaces
capnp_rpc::pry to match the new impl Future return type.
Warning-clean workspace build.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Documents the root cause of the streaming display bug —
pop removes 1 line per entry but push produces N lines
(markdown, tool results). Includes concrete fix approach
using per-entry line count tracking.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
- subconscious.rs: use .get(fork_point..) instead of direct slice
to avoid panic when fork_point > entries.len()
- dmn.rs: batch all output injections (surface, reflection, thalamus)
under a single agent lock acquisition instead of three separate ones
- dmn.rs: use Store::cached() instead of Store::load() when rendering
surfaced memories
- Add scoring persistence analysis notes
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Store::cached() returns a process-global Arc<tokio::sync::Mutex<Store>>
that loads once and reloads only when log files change (is_stale()
checks file sizes). All memory and journal tools use cached_store()
instead of Store::load() per invocation.
Fixes CPU saturation from HashMap hashing when multiple subconscious
agents make concurrent tool calls.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
ConversationEntry::Memory gains score: Option<f64>. The scorer
writes scores directly onto entries when results arrive. Removes
Agent.memory_scores Vec and the memory_scores parameter from
context_state_summary().
Scores are serialized to/from the conversation log as memory_score.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
The forked agent is now behind Arc<tokio::sync::Mutex<Agent>>,
stored on SubconsciousAgent and passed to the spawned task. The
subconscious detail screen locks it via try_lock() to read entries
from the fork point — live during runs, persisted after completion.
Removes last_run_entries snapshot. Backend::Forked now holds the
shared Arc, all push operations go through the lock.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
F1 and F2 screens now call agent.context_state_summary() directly
via try_lock/lock instead of reading from a shared RwLock cache.
Removes SharedContextState, publish_context_state(), and
publish_context_state_with_scores().
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Keep name and last_run_entries on SubconsciousAgent directly,
not just on the AutoAgent (which gets replaced with a placeholder
during spawned runs). Snapshot reads stable fields.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Previously only fired after conscious turn completion. Now runs on
every wake — DMN timer, user input, background events. Subconscious
agents get checked regardless of what woke the loop.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Subconscious owns agents and shared walked state. trigger() and
collect_results() take the conscious agent Arc as a parameter.
Mind holds Subconscious behind a tokio Mutex and calls into it
from the event loop.
Drops ~170 lines from mind/mod.rs.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
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>
Track fork point in run_forked(), capture entries added during the
run. Subconscious screen shows these in a detail view (Enter to
drill in, Esc to go back) — only the subconscious agent's own
conversation, not the inherited conscious context.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
AutoAgent intercepts output() tool calls and stores results in an
in-memory HashMap instead of writing to the filesystem. Mind reads
auto.outputs after task completion. Eliminates the env-var-based
output dir which couldn't work with concurrent agents in one process.
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>
AutoAgent holds config + walked state. Backend is ephemeral per run:
- run(): standalone, global API client (oneshot CLI)
- run_forked(): forks conscious agent, resolves prompt templates
with current memory_keys and walked state
Mind creates AutoAgents once at startup, takes them out for spawned
tasks, puts them back on completion (preserving walked state).
Removes {{seen_previous}}, {{input:walked}}, {{memory_ratio}} from
subconscious agent prompts. Walked keys are now a Vec on AutoAgent,
resolved via {{walked}} from in-memory state.
Co-Authored-By: Proof of Concept <poc@bcachefs.org>