- Project infrastructure: go.mod, Makefile, .gitignore, README - Configuration system with YAML parsing and env overrides - Structured logging with slog - AI provider interface with Ollama, OpenAI, Anthropic implementations - Provider manager with runtime switching - Agent orchestrator with ReAct loop (reason-act-observe) - Tool registry with JSON Schema descriptions - Terminal tool: shell command execution with safety controls - Filesystem tools: read, write, list with path access control - Conversation memory with session management - Web UI server with WebSocket streaming - Modern dark theme UI with glassmorphism, animations - Frontend: WebSocket client, markdown rendering, tool call display
86 lines
2 KiB
Go
86 lines
2 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"sync"
|
|
|
|
"git.bebrik.xyz/Dan4ick/ZovOS_AI/internal/ai"
|
|
)
|
|
|
|
// ToolHandler is the function signature for tool implementations.
|
|
type ToolHandler func(ctx context.Context, args json.RawMessage) (string, error)
|
|
|
|
// ToolDef defines a tool with its metadata and handler.
|
|
type ToolDef struct {
|
|
ai.Tool
|
|
Handler ToolHandler
|
|
}
|
|
|
|
// Registry manages all available tools.
|
|
type Registry struct {
|
|
mu sync.RWMutex
|
|
tools map[string]ToolDef
|
|
log *slog.Logger
|
|
}
|
|
|
|
// NewRegistry creates a new tool registry.
|
|
func NewRegistry(log *slog.Logger) *Registry {
|
|
return &Registry{
|
|
tools: make(map[string]ToolDef),
|
|
log: log,
|
|
}
|
|
}
|
|
|
|
// Register adds a tool to the registry.
|
|
func (r *Registry) Register(def ToolDef) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.tools[def.Name] = def
|
|
r.log.Info("registered tool", "name", def.Name)
|
|
}
|
|
|
|
// Execute runs a tool by name with the given arguments.
|
|
func (r *Registry) Execute(ctx context.Context, name string, argsJSON string) (string, error) {
|
|
r.mu.RLock()
|
|
td, ok := r.tools[name]
|
|
r.mu.RUnlock()
|
|
if !ok {
|
|
return "", fmt.Errorf("unknown tool: %s", name)
|
|
}
|
|
|
|
r.log.Info("executing tool", "name", name, "args", argsJSON)
|
|
|
|
result, err := td.Handler(ctx, json.RawMessage(argsJSON))
|
|
if err != nil {
|
|
r.log.Error("tool execution failed", "name", name, "error", err)
|
|
return fmt.Sprintf("Error: %v", err), nil // return error as result, not as Go error
|
|
}
|
|
|
|
r.log.Debug("tool result", "name", name, "result_len", len(result))
|
|
return result, nil
|
|
}
|
|
|
|
// List returns AI tool definitions for all registered tools.
|
|
func (r *Registry) List() []ai.Tool {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
result := make([]ai.Tool, 0, len(r.tools))
|
|
for _, td := range r.tools {
|
|
result = append(result, td.Tool)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Names returns names of all registered tools.
|
|
func (r *Registry) Names() []string {
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
names := make([]string, 0, len(r.tools))
|
|
for name := range r.tools {
|
|
names = append(names, name)
|
|
}
|
|
return names
|
|
}
|