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>
This commit is contained in:
Kent Overstreet 2026-04-08 20:41:42 -04:00
parent daba424a46
commit dd85a56902
13 changed files with 14 additions and 16 deletions

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/bash.rs — Execute shell commands
//
// Runs commands through bash -c with a configurable timeout.

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/channels.rs — Channel tools (list, recv, send, notifications)
//
// Shared by consciousness agent and the MCP server.

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/control.rs — Agent control tools
//
// These set agent state directly via the Arc<Mutex<Agent>> handle,

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/edit.rs — Search-and-replace file editing
use anyhow::{Context, Result};

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/glob_tool.rs — Find files by pattern
//
// Fast file discovery using glob patterns. Returns matching paths

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/grep.rs — Search file contents
//
// Prefers ripgrep (rg) for speed, falls back to grep -r if rg

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/memory.rs — Native memory graph operations
//
// Direct library calls into the store — no subprocess spawning.
@ -32,7 +33,7 @@ async fn get_provenance(agent: &Option<std::sync::Arc<crate::agent::Agent>>) ->
// ── Definitions ────────────────────────────────────────────────
pub fn memory_tools() -> [super::Tool; 12] {
pub fn memory_tools() -> [super::Tool; 11] {
use super::Tool;
[
Tool { name: "memory_render", description: "Read a memory node's content and links.",
@ -236,20 +237,6 @@ async fn query(args: &serde_json::Value) -> Result<String> {
.map_err(|e| anyhow::anyhow!("{}", e))
}
fn output(args: &serde_json::Value) -> Result<String> {
let key = get_str(args, "key")?;
if key.starts_with("pid-") || key.contains('/') || key.contains("..") {
anyhow::bail!("invalid output key: {}", key);
}
let value = get_str(args, "value")?;
let dir = std::env::var("POC_AGENT_OUTPUT_DIR")
.map_err(|_| anyhow::anyhow!("no output directory set"))?;
let path = std::path::Path::new(&dir).join(key);
std::fs::write(&path, value)
.with_context(|| format!("writing output {}", path.display()))?;
Ok(format!("{}: {}", key, value))
}
// ── Journal tools ──────────────────────────────────────────────
async fn journal_tail(args: &serde_json::Value) -> Result<String> {

View file

@ -143,7 +143,7 @@ pub async fn dispatch_with_agent(
let tool = if let Some(ref a) = agent {
// Only dispatch tools the agent is allowed to use
let guard = a.state.lock().await;
guard.tools.iter().find(|t| t.name == name).copied()
guard.tools.iter().find(|t| t.name == name).cloned()
} else {
// No agent context — allow all tools (CLI/MCP path)
tools().into_iter().find(|t| t.name == name)

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/read.rs — Read file contents
use anyhow::{Context, Result};

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/vision.rs — Image viewing tool
//
// Reads image files from disk and returns them as base64 data URIs

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/web.rs — Web fetch and search
use anyhow::{Context, Result};

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// tools/write.rs — Write file contents
use anyhow::{Context, Result};

View file

@ -1,3 +1,4 @@
use std::sync::Arc;
// Episodic digest generation: daily, weekly, monthly, auto
//
// Three digest levels form a temporal hierarchy: daily digests summarize