consciousness/src/agent/tools/read.rs
ProofOfConcept 53ad8cc9df tools: static string definitions, no runtime JSON construction
Tool definitions are now &'static str (name, description,
parameters_json) instead of runtime-constructed serde_json::Value.
No more json!() macro, no more ToolDef::new() for tool definitions.

The JSON schema strings are written directly as string literals.
When sent to the API, they can be interpolated without
serialization/deserialization.

Multi-tool modules return fixed-size arrays instead of Vecs:
- memory: [Tool; 12], journal: [Tool; 3]
- channels: [Tool; 4]
- control: [Tool; 3]
- web: [Tool; 2]

ToolDef/FunctionDef remain for backward compat (API wire format,
summarize_args) but are no longer used in tool definitions.

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

39 lines
1.6 KiB
Rust

// tools/read.rs — Read file contents
use anyhow::{Context, Result};
use serde::Deserialize;
pub fn tool() -> super::Tool {
super::Tool {
name: "read_file",
description: "Read the contents of a file. Returns the file contents with line numbers.",
parameters_json: r#"{"type":"object","properties":{"file_path":{"type":"string","description":"Absolute path to the file to read"},"offset":{"type":"integer","description":"Line number to start reading from (1-based)"},"limit":{"type":"integer","description":"Maximum number of lines to read"}},"required":["file_path"]}"#,
handler: |_a, v| Box::pin(async move { read_file(&v) }),
}
}
#[derive(Deserialize)]
struct Args {
file_path: String,
#[serde(default = "default_offset")]
offset: usize,
limit: Option<usize>,
}
fn default_offset() -> usize { 1 }
fn read_file(args: &serde_json::Value) -> Result<String> {
let a: Args = serde_json::from_value(args.clone()).context("invalid read_file arguments")?;
let content = std::fs::read_to_string(&a.file_path)
.with_context(|| format!("Failed to read {}", a.file_path))?;
let lines: Vec<&str> = content.lines().collect();
let start = a.offset.saturating_sub(1);
let end = a.limit.map_or(lines.len(), |l| (start + l).min(lines.len()));
if start >= lines.len() {
return Ok(format!("(file has {} lines, offset {} is past end)", lines.len(), a.offset));
}
let mut out = String::new();
for (i, line) in lines[start..end].iter().enumerate() {
out.push_str(&format!("{}\t{}\n", start + i + 1, line));
}
Ok(out)
}