Changeset 0.7.2 (#40)
This commit is contained in:
92
server/tools/registry.go
Normal file
92
server/tools/registry.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// ── Registry ────────────────────────────────
|
||||
|
||||
var registry = map[string]Tool{}
|
||||
|
||||
// Register adds a tool to the global registry. Called at init time.
|
||||
func Register(t Tool) {
|
||||
def := t.Definition()
|
||||
if _, exists := registry[def.Name]; exists {
|
||||
panic("tools.Register: duplicate tool name: " + def.Name)
|
||||
}
|
||||
registry[def.Name] = t
|
||||
log.Printf("🔧 Registered tool: %s", def.Name)
|
||||
}
|
||||
|
||||
// Get returns a tool by name, or nil if not found.
|
||||
func Get(name string) Tool {
|
||||
return registry[name]
|
||||
}
|
||||
|
||||
// AllDefinitions returns tool definitions for all registered tools.
|
||||
// Used to populate the `tools` field in LLM requests.
|
||||
func AllDefinitions() []ToolDef {
|
||||
defs := make([]ToolDef, 0, len(registry))
|
||||
for _, t := range registry {
|
||||
defs = append(defs, t.Definition())
|
||||
}
|
||||
return defs
|
||||
}
|
||||
|
||||
// ── Execution ───────────────────────────────
|
||||
|
||||
// ExecuteCall runs a single tool call and returns a ToolResult.
|
||||
// Never returns an error — failures are encoded in the result content
|
||||
// so the LLM can see what went wrong and adjust.
|
||||
func ExecuteCall(ctx context.Context, execCtx ExecutionContext, call ToolCall) ToolResult {
|
||||
tool := Get(call.Name)
|
||||
if tool == nil {
|
||||
return ToolResult{
|
||||
ToolCallID: call.ID,
|
||||
Name: call.Name,
|
||||
Content: jsonError(fmt.Sprintf("unknown tool: %s", call.Name)),
|
||||
IsError: true,
|
||||
}
|
||||
}
|
||||
|
||||
result, err := tool.Execute(ctx, execCtx, call.Arguments)
|
||||
if err != nil {
|
||||
log.Printf("Tool %s error: %v", call.Name, err)
|
||||
return ToolResult{
|
||||
ToolCallID: call.ID,
|
||||
Name: call.Name,
|
||||
Content: jsonError(err.Error()),
|
||||
IsError: true,
|
||||
}
|
||||
}
|
||||
|
||||
return ToolResult{
|
||||
ToolCallID: call.ID,
|
||||
Name: call.Name,
|
||||
Content: result,
|
||||
}
|
||||
}
|
||||
|
||||
// ExecuteAll runs multiple tool calls and returns all results.
|
||||
func ExecuteAll(ctx context.Context, execCtx ExecutionContext, calls []ToolCall) []ToolResult {
|
||||
results := make([]ToolResult, len(calls))
|
||||
for i, call := range calls {
|
||||
results[i] = ExecuteCall(ctx, execCtx, call)
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// HasTools returns true if any tools are registered.
|
||||
func HasTools() bool {
|
||||
return len(registry) > 0
|
||||
}
|
||||
|
||||
// ── Helpers ─────────────────────────────────
|
||||
|
||||
func jsonError(msg string) string {
|
||||
b, _ := json.Marshal(map[string]string{"error": msg})
|
||||
return string(b)
|
||||
}
|
||||
Reference in New Issue
Block a user