mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-25 14:53:34 +00:00
Replace memory_list with memory_tree tool
The memory_tree tool provides a hierarchical view of the workspace with configurable depth (default 1). This is more useful for exploring nested directory structures. Co-Authored-By: Claude Opus 4.5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.5
parent
3718cfa767
commit
3f7624eefc
@@ -347,7 +347,7 @@ Four tools for LLM use:
|
|||||||
- **`memory_search`** - Hybrid search, MUST be called before answering questions about prior work
|
- **`memory_search`** - Hybrid search, MUST be called before answering questions about prior work
|
||||||
- **`memory_write`** - Write to any path (memory, daily_log, or custom paths)
|
- **`memory_write`** - Write to any path (memory, daily_log, or custom paths)
|
||||||
- **`memory_read`** - Read any file by path
|
- **`memory_read`** - Read any file by path
|
||||||
- **`memory_list`** - List directory contents
|
- **`memory_tree`** - View workspace structure as a tree (depth parameter, default 1)
|
||||||
|
|
||||||
### Hybrid Search (RRF)
|
### Hybrid Search (RRF)
|
||||||
|
|
||||||
|
|||||||
+83
-33
@@ -316,39 +316,94 @@ impl Tool for MemoryReadTool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tool for listing workspace files.
|
/// Tool for viewing workspace structure as a tree.
|
||||||
///
|
///
|
||||||
/// Use this to explore the workspace structure.
|
/// Returns a hierarchical view of files and directories with configurable depth.
|
||||||
pub struct MemoryListTool {
|
pub struct MemoryTreeTool {
|
||||||
workspace: Arc<Workspace>,
|
workspace: Arc<Workspace>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryListTool {
|
impl MemoryTreeTool {
|
||||||
/// Create a new memory list tool.
|
/// Create a new memory tree tool.
|
||||||
pub fn new(workspace: Arc<Workspace>) -> Self {
|
pub fn new(workspace: Arc<Workspace>) -> Self {
|
||||||
Self { workspace }
|
Self { workspace }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Recursively build tree structure.
|
||||||
|
async fn build_tree(
|
||||||
|
&self,
|
||||||
|
path: &str,
|
||||||
|
current_depth: usize,
|
||||||
|
max_depth: usize,
|
||||||
|
) -> Result<Vec<serde_json::Value>, ToolError> {
|
||||||
|
if current_depth > max_depth {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let entries = self
|
||||||
|
.workspace
|
||||||
|
.list(path)
|
||||||
|
.await
|
||||||
|
.map_err(|e| ToolError::ExecutionFailed(format!("List failed: {}", e)))?;
|
||||||
|
|
||||||
|
let mut result = Vec::new();
|
||||||
|
for entry in entries {
|
||||||
|
let mut node = serde_json::json!({
|
||||||
|
"name": entry.name(),
|
||||||
|
"path": entry.path,
|
||||||
|
"is_directory": entry.is_directory,
|
||||||
|
});
|
||||||
|
|
||||||
|
if entry.is_directory && current_depth < max_depth {
|
||||||
|
// Recurse into directory
|
||||||
|
let children =
|
||||||
|
Box::pin(self.build_tree(&entry.path, current_depth + 1, max_depth)).await?;
|
||||||
|
if !children.is_empty() {
|
||||||
|
node["children"] = serde_json::Value::Array(children);
|
||||||
|
}
|
||||||
|
} else if !entry.is_directory {
|
||||||
|
// Include file metadata
|
||||||
|
if let Some(updated) = entry.updated_at {
|
||||||
|
node["updated_at"] = serde_json::Value::String(updated.to_rfc3339());
|
||||||
|
}
|
||||||
|
if let Some(preview) = &entry.content_preview {
|
||||||
|
node["preview"] = serde_json::Value::String(preview.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl Tool for MemoryListTool {
|
impl Tool for MemoryTreeTool {
|
||||||
fn name(&self) -> &str {
|
fn name(&self) -> &str {
|
||||||
"memory_list"
|
"memory_tree"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn description(&self) -> &str {
|
fn description(&self) -> &str {
|
||||||
"List files and directories in the workspace. Use this to explore \
|
"View the workspace structure as a tree. Use this to explore \
|
||||||
the workspace structure and discover available files."
|
the workspace hierarchy and discover available files and directories."
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parameters_schema(&self) -> serde_json::Value {
|
fn parameters_schema(&self) -> serde_json::Value {
|
||||||
serde_json::json!({
|
serde_json::json!({
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"directory": {
|
"path": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Directory to list (empty string or '/' for root)",
|
"description": "Root path to start from (empty string for workspace root)",
|
||||||
"default": ""
|
"default": ""
|
||||||
|
},
|
||||||
|
"depth": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Maximum depth to traverse (1 = immediate children only)",
|
||||||
|
"default": 1,
|
||||||
|
"minimum": 1,
|
||||||
|
"maximum": 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -361,27 +416,20 @@ impl Tool for MemoryListTool {
|
|||||||
) -> Result<ToolOutput, ToolError> {
|
) -> Result<ToolOutput, ToolError> {
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
||||||
let directory = params
|
let path = params.get("path").and_then(|v| v.as_str()).unwrap_or("");
|
||||||
.get("directory")
|
|
||||||
.and_then(|v| v.as_str())
|
|
||||||
.unwrap_or("");
|
|
||||||
|
|
||||||
let entries = self
|
let depth = params
|
||||||
.workspace
|
.get("depth")
|
||||||
.list(directory)
|
.and_then(|v| v.as_u64())
|
||||||
.await
|
.unwrap_or(1)
|
||||||
.map_err(|e| ToolError::ExecutionFailed(format!("List failed: {}", e)))?;
|
.clamp(1, 10) as usize;
|
||||||
|
|
||||||
|
let tree = self.build_tree(path, 1, depth).await?;
|
||||||
|
|
||||||
let output = serde_json::json!({
|
let output = serde_json::json!({
|
||||||
"directory": directory,
|
"root": if path.is_empty() { "/" } else { path },
|
||||||
"entries": entries.iter().map(|e| serde_json::json!({
|
"depth": depth,
|
||||||
"path": e.path,
|
"tree": tree,
|
||||||
"name": e.name(),
|
|
||||||
"is_directory": e.is_directory,
|
|
||||||
"updated_at": e.updated_at.map(|t| t.to_rfc3339()),
|
|
||||||
"preview": e.content_preview,
|
|
||||||
})).collect::<Vec<_>>(),
|
|
||||||
"count": entries.len(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(ToolOutput::success(output, start.elapsed()))
|
Ok(ToolOutput::success(output, start.elapsed()))
|
||||||
@@ -457,13 +505,15 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_memory_list_schema() {
|
fn test_memory_tree_schema() {
|
||||||
let workspace = make_test_workspace();
|
let workspace = make_test_workspace();
|
||||||
let tool = MemoryListTool::new(workspace);
|
let tool = MemoryTreeTool::new(workspace);
|
||||||
|
|
||||||
assert_eq!(tool.name(), "memory_list");
|
assert_eq!(tool.name(), "memory_tree");
|
||||||
|
|
||||||
let schema = tool.parameters_schema();
|
let schema = tool.parameters_schema();
|
||||||
assert!(schema["properties"]["directory"].is_object());
|
assert!(schema["properties"]["path"].is_object());
|
||||||
|
assert!(schema["properties"]["depth"].is_object());
|
||||||
|
assert_eq!(schema["properties"]["depth"]["default"], 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user