mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-04-27 18:14:25 +08:00
add memory_get tool and docker-based make test target
This commit is contained in:
6
Makefile
6
Makefile
@@ -161,6 +161,12 @@ deps:
|
||||
run: build
|
||||
@$(BUILD_DIR)/$(BINARY_NAME) $(ARGS)
|
||||
|
||||
## test: Build and compile-check in Docker (Dockerfile.test)
|
||||
test:
|
||||
@echo "Running Docker compile test..."
|
||||
docker build -f Dockerfile.test -t clawgo:test .
|
||||
@echo "Docker compile test passed"
|
||||
|
||||
## help: Show this help message
|
||||
help:
|
||||
@echo "clawgo Makefile"
|
||||
|
||||
@@ -80,6 +80,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
|
||||
// Register memory tools
|
||||
memorySearchTool := tools.NewMemorySearchTool(workspace)
|
||||
toolsRegistry.Register(memorySearchTool)
|
||||
toolsRegistry.Register(tools.NewMemoryGetTool(workspace))
|
||||
toolsRegistry.Register(tools.NewMemoryWriteTool(workspace))
|
||||
|
||||
// Register parallel execution tool (leveraging Go's concurrency)
|
||||
|
||||
123
pkg/tools/memory_get.go
Normal file
123
pkg/tools/memory_get.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type MemoryGetTool struct {
|
||||
workspace string
|
||||
}
|
||||
|
||||
func NewMemoryGetTool(workspace string) *MemoryGetTool {
|
||||
return &MemoryGetTool{workspace: workspace}
|
||||
}
|
||||
|
||||
func (t *MemoryGetTool) Name() string {
|
||||
return "memory_get"
|
||||
}
|
||||
|
||||
func (t *MemoryGetTool) Description() string {
|
||||
return "Read safe snippets from MEMORY.md or memory/*.md using optional line range."
|
||||
}
|
||||
|
||||
func (t *MemoryGetTool) Parameters() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"path": map[string]interface{}{
|
||||
"type": "string",
|
||||
"description": "Relative path to MEMORY.md or memory/*.md",
|
||||
},
|
||||
"from": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"description": "Start line (1-indexed)",
|
||||
"default": 1,
|
||||
},
|
||||
"lines": map[string]interface{}{
|
||||
"type": "integer",
|
||||
"description": "Number of lines to read",
|
||||
"default": 80,
|
||||
},
|
||||
},
|
||||
"required": []string{"path"},
|
||||
}
|
||||
}
|
||||
|
||||
func (t *MemoryGetTool) Execute(ctx context.Context, args map[string]interface{}) (string, error) {
|
||||
rawPath, _ := args["path"].(string)
|
||||
rawPath = strings.TrimSpace(rawPath)
|
||||
if rawPath == "" {
|
||||
return "", fmt.Errorf("path is required")
|
||||
}
|
||||
|
||||
from := 1
|
||||
if v, ok := args["from"].(float64); ok && int(v) > 0 {
|
||||
from = int(v)
|
||||
}
|
||||
lines := 80
|
||||
if v, ok := args["lines"].(float64); ok && int(v) > 0 {
|
||||
lines = int(v)
|
||||
}
|
||||
if lines > 500 {
|
||||
lines = 500
|
||||
}
|
||||
|
||||
fullPath := filepath.Clean(filepath.Join(t.workspace, rawPath))
|
||||
if !t.isAllowedMemoryPath(fullPath) {
|
||||
return "", fmt.Errorf("path not allowed: %s", rawPath)
|
||||
}
|
||||
|
||||
f, err := os.Open(fullPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
lineNo := 0
|
||||
end := from + lines - 1
|
||||
var out strings.Builder
|
||||
for scanner.Scan() {
|
||||
lineNo++
|
||||
if lineNo < from {
|
||||
continue
|
||||
}
|
||||
if lineNo > end {
|
||||
break
|
||||
}
|
||||
out.WriteString(fmt.Sprintf("%d: %s\n", lineNo, scanner.Text()))
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
content := strings.TrimSpace(out.String())
|
||||
if content == "" {
|
||||
return fmt.Sprintf("No content in range for %s (from=%d, lines=%d)", rawPath, from, lines), nil
|
||||
}
|
||||
|
||||
rel, _ := filepath.Rel(t.workspace, fullPath)
|
||||
return fmt.Sprintf("Source: %s#L%d-L%d\n%s", rel, from, end, content), nil
|
||||
}
|
||||
|
||||
func (t *MemoryGetTool) isAllowedMemoryPath(fullPath string) bool {
|
||||
workspaceMemory := filepath.Join(t.workspace, "MEMORY.md")
|
||||
if fullPath == workspaceMemory {
|
||||
return true
|
||||
}
|
||||
|
||||
memoryDir := filepath.Join(t.workspace, "memory")
|
||||
rel, err := filepath.Rel(memoryDir, fullPath)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(rel, "..") {
|
||||
return false
|
||||
}
|
||||
return strings.HasSuffix(strings.ToLower(fullPath), ".md")
|
||||
}
|
||||
Reference in New Issue
Block a user