Files
gnoma/internal/tool/registry.go
vikingowl f0633d8ac6 feat: complete M1 — core engine with Mistral provider
Mistral provider adapter with streaming, tool calls (single-chunk
pattern), stop reason inference, model listing, capabilities, and
JSON output support.

Tool system: bash (7 security checks, shell alias harvesting for
bash/zsh/fish), file ops (read, write, edit, glob, grep, ls).
Alias harvesting collects 300+ aliases from user's shell config.

Engine agentic loop: stream → tool execution → re-query → until
done. Tool gating on model capabilities. Max turns safety limit.

CLI pipe mode: echo "prompt" | gnoma streams response to stdout.
Flags: --provider, --model, --system, --api-key, --max-turns,
--verbose, --version.

Provider interface expanded: Models(), DefaultModel(), Capabilities
(ToolUse, JSONOutput, Vision, Thinking, ContextWindow, MaxOutput),
ResponseFormat with JSON schema support.

Live verified: text streaming + tool calling with devstral-small.
117 tests across 8 packages, 10MB binary.
2026-04-03 12:01:55 +02:00

78 lines
1.6 KiB
Go

package tool
import (
"encoding/json"
"fmt"
"sync"
)
// Definition is the provider-agnostic tool schema sent to the LLM.
type Definition struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters json.RawMessage `json:"parameters"`
}
// Registry holds all available tools.
type Registry struct {
mu sync.RWMutex
tools map[string]Tool
}
func NewRegistry() *Registry {
return &Registry{
tools: make(map[string]Tool),
}
}
// Register adds a tool. Overwrites if name already exists.
func (r *Registry) Register(t Tool) {
r.mu.Lock()
defer r.mu.Unlock()
r.tools[t.Name()] = t
}
// Get returns a tool by name.
func (r *Registry) Get(name string) (Tool, bool) {
r.mu.RLock()
defer r.mu.RUnlock()
t, ok := r.tools[name]
return t, ok
}
// All returns all registered tools.
func (r *Registry) All() []Tool {
r.mu.RLock()
defer r.mu.RUnlock()
all := make([]Tool, 0, len(r.tools))
for _, t := range r.tools {
all = append(all, t)
}
return all
}
// Definitions returns tool definitions for all registered tools,
// suitable for sending to the LLM.
func (r *Registry) Definitions() []Definition {
r.mu.RLock()
defer r.mu.RUnlock()
defs := make([]Definition, 0, len(r.tools))
for _, t := range r.tools {
defs = append(defs, Definition{
Name: t.Name(),
Description: t.Description(),
Parameters: t.Parameters(),
})
}
return defs
}
// MustGet returns a tool by name or panics. For use in tests.
func (r *Registry) MustGet(name string) Tool {
t, ok := r.Get(name)
if !ok {
panic(fmt.Sprintf("tool not found: %q", name))
}
return t
}