Commit graph

85 commits

Author SHA1 Message Date
Kent Overstreet
f00532bdb7 TurnResult: remove text field, simplify oneshot loop
- Remove TurnResult.text (was dead code - Agent::turn handles text internally)
- Simplify run_with_backend to just iterate over steps (Agent::turn loops
  for tool calls and handles empty responses internally)
- Change run/run_shared/run_forked_shared to return Result<(), String>
- Remove AgentResult.output field (no callers used it)
- Stub out legacy text-parsing code (audit, compare) that needs redesign
- Update digest.rs to not depend on text return
- Add level parameter to journal_new/journal_update for digest support

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-12 02:04:50 -04:00
ProofOfConcept
aad227e487 query: unify PEG and engine parsers
PEG parser now handles both expression syntax (degree > 5 | sort degree)
and pipeline syntax (all | type:episodic | sort:timestamp). Deleted
Stage::parse() and helpers from engine.rs — it's now pure execution.

All callers use parse_stages() from parser.rs as the single entry point.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-11 20:42:58 -04:00
ProofOfConcept
1c0967c4ec Agent:🆕 tool definitions from caller's tool list
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>
2026-04-11 19:43:24 -04:00
ProofOfConcept
4fc9676545 channels: parallel queries with timeout per daemon
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>
2026-04-11 00:45:01 -04:00
ProofOfConcept
1cf51876a8 journal_tail: thin wrapper around memory_query
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>
2026-04-10 16:09:46 -04:00
ProofOfConcept
db49f49958 Improve tool parameter schemas: add defaults, readable formatting
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>
2026-04-10 16:04:31 -04:00
ProofOfConcept
568ce417fc Modernize digest agent: autonomous with journal_tail levels
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>
2026-04-10 16:02:52 -04:00
ProofOfConcept
5b4f497d94 Move agent queries inline: {{nodes}} → {{tool: memory_query}}
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>
2026-04-10 15:53:54 -04:00
ProofOfConcept
92ef9b5215 Delete separator agent and interference_pairs tool
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>
2026-04-10 15:32:30 -04:00
ProofOfConcept
fd722662da Add graph_topology, graph_health, interference_pairs tools
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>
2026-04-10 15:25:57 -04:00
ProofOfConcept
be6ac762f6 memory_render: use cached store instead of loading from disk each call
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>
2026-04-10 15:22:49 -04:00
ProofOfConcept
15f3be27ce Show MCP server failures in the UI instead of debug log
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>
2026-04-09 22:46:48 -04:00
ProofOfConcept
3e0d52c451 Redirect noisy warnings to debug log to stop TUI corruption
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>
2026-04-09 22:46:48 -04:00
ProofOfConcept
a596e007b2 Mouse selection, copy/paste, yield_to_user fixes
- Mouse text selection with highlight rendering in panes
- OSC 52 clipboard copy on selection, middle-click paste via tmux buffer
- Bracketed paste support (Event::Paste)
- yield_to_user: no tool result appended, ends turn immediately
- yield_to_user: no parameters, just a control signal
- Drop arboard dependency, use crossterm OSC 52 + tmux for clipboard

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-09 18:10:54 -04:00
Kent Overstreet
6ec0e1c766 LSP client: spawn language servers, expose code intelligence tools
New lsp.rs: LspRegistry manages persistent LSP server connections.
Spawns child processes, speaks LSP protocol (Content-Length framed
JSON-RPC over stdio). Server indexes the project once; queries are
cheap.

Tools: lsp_definition, lsp_references, lsp_hover, lsp_symbols,
lsp_callers. Each takes file/line/character, queries the running
language server.

LspRegistry lives on Agent as Option<Arc>, shared across forks.
Still needs: config-driven server startup (like MCP).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-09 12:59:25 -04:00
Kent Overstreet
8b5614ba99 MCP client: spawn external tool servers, dispatch via JSON-RPC
New mcp_client.rs: McpRegistry manages MCP server connections.
Spawns child processes, speaks JSON-RPC 2.0 over stdio. Discovers
tools via tools/list, dispatches calls via tools/call.

dispatch_with_agent falls through to MCP after checking internal
tools. McpRegistry lives on Agent (shared across forks).

Still needs: config-driven server startup, system prompt integration.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-09 12:59:25 -04:00
ProofOfConcept
ec7e11db56 Add ast_grep tool: structural code search via ast-grep
AST-level pattern matching — find code by structure, not text.
e.g. find all `if let Some($X) = $Y { $$$BODY }` patterns.
Supports C, Rust, Python, JS/TS, Go, and 20+ languages.

Gracefully errors if sg binary isn't installed.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-09 11:38:24 -04:00
Kent Overstreet
dd85a56902 Output tool via Arc<Mutex<Subconscious>> closure — complete
ToolHandler is now Arc<dyn Fn(...)> supporting closures that capture
state. The output tool is created during init_output_tool() as a
closure capturing Arc<Mutex<Subconscious>>, writing directly to
Subconscious.state. No more POC_AGENT_OUTPUT_DIR filesystem hack.

- All tool handlers wrapped in Arc::new()
- Tool is Clone (not Copy) — .copied() → .cloned()
- Subconscious wrapped in Arc<Mutex<>> on Mind
- Dead filesystem-based output() function removed
- memory_tools returns 11 items (output removed from static list)

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 20:41:42 -04:00
Kent Overstreet
daba424a46 WIP: Fix Arc::new() wrapping on tool handlers — some import/paren issues remain
Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 20:38:42 -04:00
Kent Overstreet
12798eeae2 WIP: Output tool via Arc<Mutex<Subconscious>>, ToolHandler to Arc<dyn Fn>
- ToolHandler changed to Arc<dyn Fn(...)> (supports closures)
- Subconscious wrapped in Arc<Mutex<>> on Mind
- init_output_tool() pushes output tool closure capturing the Arc
- Output removed from static memory_tools()
- Most tool handlers wrapped in Arc::new() but some have paren issues

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 20:37:19 -04:00
Kent Overstreet
d167b11283 Revert output tool hacks (AST scanning + silent success)
These were wrong approaches — replacing with proper closure-based
output tool that writes directly to shared Subconscious state.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 20:07:20 -04:00
Kent Overstreet
68fbcc351f output() tool: don't error when no output dir (forked agents)
Forked agents don't have POC_AGENT_OUTPUT_DIR set. The output tool
now returns success regardless — forked agents extract output values
from the AST via run_with_backend. Subprocess agents still write
to disk when the dir is set.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 19:51:44 -04:00
Kent Overstreet
1776222b07 Fix tool permissions: remove global fallback in dispatch_with_agent
When an agent context is present, only dispatch tools in the agent's
tool list. The global fallback was bypassing per-agent tool
restrictions — a subconscious agent could call bash, edit, or any
tool even if its .agent file only allowed memory tools.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 19:19:05 -04:00
Kent Overstreet
31a41fa042 ActiveTools wrapper: replace SharedActiveTools Arc<Mutex<Vec>>
New ActiveTools struct with proper methods: push, remove, abort_all,
take_finished, take_foreground, iter, len. Lives directly on AgentState,
no separate Arc<Mutex> needed.

TUI reads active tools through agent.state.try_lock(). Turn loop uses
helpers instead of manual index iteration.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 16:45:56 -04:00
Kent Overstreet
9c9618d034 WIP: ActiveTools wrapper type, removing SharedActiveTools
New ActiveTools struct with proper methods: push, remove,
take_finished, take_foreground, iter, len. Turn loop uses
helpers instead of manual index iteration.

Removing SharedActiveTools (Arc<Mutex<Vec>>) — active tools
live directly in AgentState. A few UI callers still need
updating.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 16:41:14 -04:00
Kent Overstreet
1d61b091b0 WIP: Agent/AgentState — 36 errors remaining, all .lock() → .state.lock() or .context.lock()
Bulk replaced Arc<Mutex<Agent>> with Arc<Agent> across all files.
Fixed control.rs, memory.rs tool handlers. Fixed oneshot Backend.
Remaining errors are all agent.lock() → agent.state.lock() or
agent.context.lock() in mind/, user/, and a few in mod.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:40:36 -04:00
Kent Overstreet
e73135a8d0 WIP: Agent/AgentState split — core methods migrated
turn(), push_node(), assemble_prompt_tokens(), compact(),
restore_from_log(), load_startup_journal(), apply_tool_result()
all use separate context/state locks. ToolHandler signature
updated to Arc<Agent>.

Remaining: tool handlers, control.rs, memory.rs, digest.rs,
and all outer callers (mind, user, learn, oneshot, dmn).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:39:03 -04:00
Kent Overstreet
d0d876e067 WIP: Fix mind/, dmn, UI layer — 35 errors remaining
mind/mod.rs and mind/dmn.rs fully migrated to AST types.
user/context.rs, user/widgets.rs, user/chat.rs partially migrated.
Killed working_stack tool, tokenize_conv_entry, context_old.rs.

Remaining: learn.rs (22), oneshot.rs (5), subconscious.rs (3),
chat.rs (3), widgets.rs (1), context.rs (1).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:24:49 -04:00
Kent Overstreet
bf3e2a9b73 WIP: Rename context_new → context, delete old files, fix UI layer
Renamed context_new.rs to context.rs, deleted context_old.rs,
types.rs, openai.rs, parsing.rs. Updated all imports. Rewrote
user/context.rs and user/widgets.rs for new types. Stubbed
working_stack tool. Killed tokenize_conv_entry.

Remaining: mind/mod.rs, mind/dmn.rs, learn.rs, chat.rs,
subconscious.rs, oneshot.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:20:26 -04:00
Kent Overstreet
9bb626f18c Strip api/types.rs to just Usage
Killed Message, Role, ToolCall, FunctionCall, MessageContent,
ContentPart, ImageUrl — all dead. types.rs is now 8 lines.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:12:28 -04:00
Kent Overstreet
a68377907a WIP: Agent core migrated to AST types
agent/mod.rs fully uses AstNode/ContextState/PendingToolCall.
Killed: push_message, push_entry, append_streaming, finalize_streaming,
streaming_index, assemble_api_messages, age_out_images, working_stack,
context_sections, entries. ConversationLog rewritten for AstNode.

Remaining: api dead code (chat path), mind/, user/, oneshot, learn.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 14:59:38 -04:00
Kent Overstreet
9e49398689 Agent-aware provenance for memory tools
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>
2026-04-07 17:46:40 -04:00
Kent Overstreet
f33b1767da Restrict API types visibility — types module is now private
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>
2026-04-07 13:39:20 -04:00
Kent Overstreet
1cf4f504c0 Kill reqwest — minimal HTTP client on raw hyper + tokio-rustls
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>
2026-04-07 12:50:40 -04:00
Kent Overstreet
a8c239f3de Cache Store in process — stop reloading on every tool call
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>
2026-04-07 03:35:08 -04:00
ProofOfConcept
f390fa1617 Delete ui_channel.rs — relocate types, remove all UiMessage/UiSender plumbing
Types relocated:
- StreamTarget → mind/mod.rs (Mind decides Conversation vs Autonomous)
- SharedActiveTools + shared_active_tools() → agent/tools/mod.rs
- ContextSection + SharedContextState → agent/context.rs (already there)
- StatusInfo + ContextInfo → user/mod.rs (UI display state)

Removed UiSender from: Agent::turn, Mind, learn.rs, all function signatures.
The entire message-passing layer is gone. All state flows through
Agent fields (activities, entries, streaming) read by the UI via try_lock.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-05 22:34:48 -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
3e1be4d353 agent: switch from tokio::sync::Mutex to std::sync::Mutex
The agent lock is never held across await points — turns lock briefly,
do work, drop, then do async API calls. std::sync::Mutex works and
can be locked from sync contexts (screen tick inside terminal.draw).

Fixes: blocking_lock() panic when called inside tokio runtime.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-05 20:08:25 -04:00
Kent Overstreet
2a84fb325d channels: find_daemon path walking, consistent pane_id, auto-start
find_daemon() replaces daemon_sock() — walks the dot-delimited channel
path from most-specific to least looking for a daemon socket, and
auto-starts via the supervisor if none is found. All channel tools
(recv, send, open, close) use the same resolution path.

Fix tmux daemon to use pane_id consistently for both pipe-pane and
send-keys (send-keys -t <label> doesn't work, needs the %N pane id).
Store label→pane_id mapping in State instead of bare label vec.

Gracefully handle missing tmux.json5 — start with empty pane list
since panes are added dynamically via the open RPC.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 19:22:49 -04:00
ProofOfConcept
e8e9386856 channels: add open/close RPCs for dynamic pane management
Add open/close to the channel capnp schema. The tmux daemon implements
open by finding a pane by name (pane title or window name) and
attaching pipe-pane; close detaches and removes from state.

Tool handlers channel_open and channel_close added to the tool
registry.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 19:22:49 -04:00
ProofOfConcept
a14e85afe1 api: extract collect_stream() from agent turn loop
Move the entire stream event processing loop (content accumulation,
leaked tool call detection/dispatch, ToolCallDelta assembly, UI
forwarding, display buffering) into api::collect_stream(). The turn
loop now calls collect_stream() and processes the StreamResult.

Also move FunctionCall, ToolCall, ToolCallDelta to api/types.rs where
they belong (API wire format, not tool definitions). Move parsing.rs
to api/parsing.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-04 18:19:21 -04:00
ProofOfConcept
6845644f7b api: move wire types and parsing to api module
Move FunctionCall, FunctionCallDelta, ToolCall, ToolCallDelta from
tools/mod.rs to api/types.rs — these are API wire format, not tool
definitions. Re-export from tools for existing callers.

Move parsing.rs to api/parsing.rs — leaked tool call parsing is API
plumbing.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 18:19:21 -04:00
Kent Overstreet
375a8d9738 move working_stack code to correct file 2026-04-04 18:19:21 -04:00
ProofOfConcept
e9d803c4ea tools: add journal tools to main registry, fix journal MCP access
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>
2026-04-04 18:19:21 -04:00
ProofOfConcept
1554d88694 tools: delete dispatch_shared, use dispatch everywhere
dispatch_shared was a legacy wrapper — replaced by dispatch() which
goes through the unified Tool registry. One dispatch path for all
callers (interactive agent, subconscious agents, MCP server).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 18:19:21 -04:00
ProofOfConcept
51e632c997 tools: delete ToolDef and FunctionDef
ToolDef and FunctionDef are gone. Tool definitions are static strings
on the Tool struct. The API layer builds JSON from Tool::to_json().

- ChatRequest.tools is now Option<serde_json::Value>
- start_stream takes &[Tool] instead of Option<&[ToolDef]>
- openai::stream_events takes &serde_json::Value for tools
- memory_and_journal_tools() returns Vec<Tool> for subconscious agents
- Subconscious agents filter by t.name instead of t.function.name

No more runtime JSON construction for tool definitions.
No more ToolDef::new(). No more FunctionDef.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 18:19:21 -04:00
ProofOfConcept
d195160b1e tools: Tool is Copy, clean dispatch without Arc clone
Tool derives Copy (all fields are Copy: &'static str + fn pointer).
dispatch_with_agent copies the Tool out of the agent lock guard,
drops the guard, then calls the handler. No Arc cloning needed.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 18:19:21 -04:00
ProofOfConcept
d9e1c2c59f tools: dispatch_with_agent uses agent's tool list
When agent is provided, looks up the tool in agent.tools first.
Falls back to global registry for agent-less dispatch (MCP server,
subconscious agents).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 18:19:21 -04:00
ProofOfConcept
e9b26f5d45 tools: modernize working_stack, remove special-case dispatch
working_stack now uses the Tool format with an Agent handle —
it locks the agent and modifies the stack directly. The special-case
interception in the turn loop is removed. All tools go through
the unified registry dispatch.

Also passes agent handle to all spawned tool tasks so any tool
that needs Agent access can use it.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 18:19:21 -04:00
ProofOfConcept
37fad63ba9 tools: delete ToolOutput, dispatch returns String
ToolOutput was just { text: String } — replaced with plain String.
dispatch() and dispatch_shared() return String directly.
ActiveToolCall handle is (ToolCall, String).
Error results are prefixed with "Error: " by convention.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-04 18:19:21 -04:00