feat: implement tool registry and add various tools for HTTP, file operations, SSH, and Matrix messaging
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
coretypes "github.com/enmanuel/agents/pkg/llm"
|
||||
)
|
||||
|
||||
// Registry holds available tools keyed by name.
|
||||
type Registry struct {
|
||||
tools map[string]Tool
|
||||
}
|
||||
|
||||
// NewRegistry creates an empty registry.
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{tools: make(map[string]Tool)}
|
||||
}
|
||||
|
||||
// Register adds a tool to the registry.
|
||||
func (r *Registry) Register(t Tool) {
|
||||
r.tools[t.Def.Name] = t
|
||||
}
|
||||
|
||||
// Get looks up a tool by name.
|
||||
func (r *Registry) Get(name string) (Tool, bool) {
|
||||
t, ok := r.tools[name]
|
||||
return t, ok
|
||||
}
|
||||
|
||||
// Names returns all registered tool names in sorted order.
|
||||
func (r *Registry) Names() []string {
|
||||
names := make([]string, 0, len(r.tools))
|
||||
for k := range r.tools {
|
||||
names = append(names, k)
|
||||
}
|
||||
sort.Strings(names)
|
||||
return names
|
||||
}
|
||||
|
||||
// Len returns the number of registered tools.
|
||||
func (r *Registry) Len() int {
|
||||
return len(r.tools)
|
||||
}
|
||||
|
||||
// Execute looks up a tool by name and runs it. Returns an error result if not found.
|
||||
func (r *Registry) Execute(ctx context.Context, name string, argsJSON string) Result {
|
||||
t, ok := r.tools[name]
|
||||
if !ok {
|
||||
return Result{Err: fmt.Errorf("tool %q not found", name)}
|
||||
}
|
||||
|
||||
var args map[string]any
|
||||
if argsJSON != "" {
|
||||
if err := json.Unmarshal([]byte(argsJSON), &args); err != nil {
|
||||
return Result{Err: fmt.Errorf("parse args for %q: %w", name, err)}
|
||||
}
|
||||
}
|
||||
|
||||
return t.Exec(ctx, args)
|
||||
}
|
||||
|
||||
// ToLLMSpecs converts all registered tools to the LLM-compatible ToolSpec format.
|
||||
// This is a pure transformation — no side effects.
|
||||
func (r *Registry) ToLLMSpecs() []coretypes.ToolSpec {
|
||||
specs := make([]coretypes.ToolSpec, 0, len(r.tools))
|
||||
for _, name := range r.Names() {
|
||||
t := r.tools[name]
|
||||
specs = append(specs, defToLLMSpec(t.Def))
|
||||
}
|
||||
return specs
|
||||
}
|
||||
|
||||
// defToLLMSpec converts a pure Def to an LLM ToolSpec with JSON Schema.
|
||||
func defToLLMSpec(d Def) coretypes.ToolSpec {
|
||||
properties := make(map[string]any, len(d.Parameters))
|
||||
required := make([]string, 0)
|
||||
|
||||
for _, p := range d.Parameters {
|
||||
properties[p.Name] = map[string]any{
|
||||
"type": p.Type,
|
||||
"description": p.Description,
|
||||
}
|
||||
if p.Required {
|
||||
required = append(required, p.Name)
|
||||
}
|
||||
}
|
||||
|
||||
schema := map[string]any{
|
||||
"type": "object",
|
||||
"properties": properties,
|
||||
}
|
||||
if len(required) > 0 {
|
||||
schema["required"] = required
|
||||
}
|
||||
|
||||
return coretypes.ToolSpec{
|
||||
Name: d.Name,
|
||||
Description: d.Description,
|
||||
InputSchema: schema,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user