Ryanhub - file viewer
filename: tools/registry.go
branch: main
back to repo
package tools

import (
	"context"
	"encoding/json"
	"fmt"
	"sort"

	"assistant/config"
	"assistant/llm"
	"assistant/memory"
)

// Tool is a registry entry: schema + runner.
type Tool struct {
	Name        string
	Description string
	Parameters  json.RawMessage
	Run         func(ctx context.Context, args json.RawMessage) (string, error)
}

// Registry maps tool name to definition.
type Registry map[string]Tool

// ToChatTools builds Ollama /api/chat tool definitions for enabled tools.
func (r Registry) ToChatTools() []llm.ChatTool {
	names := make([]string, 0, len(r))
	for n := range r {
		names = append(names, n)
	}
	sort.Strings(names)
	out := make([]llm.ChatTool, 0, len(r))
	for _, n := range names {
		t := r[n]
		out = append(out, llm.ChatTool{
			Type: "function",
			Function: llm.ToolFunction{
				Name:        t.Name,
				Description: t.Description,
				Parameters:  t.Parameters,
			},
		})
	}
	return out
}

// BuildRegistry constructs tools from config. store may be nil when db-backed tools are disabled.
func BuildRegistry(cfg *config.Config, store *memory.Store) (Registry, error) {
	reg := Registry{}
	if cfg.Tools.Weather.Enabled {
		w := newWeatherTool(cfg.Tools.Weather)
		reg[w.Name] = w
	}
	if cfg.Tools.News.Enabled {
		for _, t := range newNewsTools(cfg.Tools.News) {
			reg[t.Name] = t
		}
	}
	if cfg.Tools.Tasks.Enabled {
		if store == nil {
			return nil, fmt.Errorf("tasks tool enabled but memory store is nil")
		}
		for _, t := range taskTools(store) {
			reg[t.Name] = t
		}
	}
	if cfg.Tools.Memory.Enabled {
		if store == nil {
			return nil, fmt.Errorf("memory tool enabled but memory store is nil")
		}
		for _, t := range memoryTools(store) {
			reg[t.Name] = t
		}
	}
	if cfg.Tools.Code.Enabled {
		codeTools, err := newCodeTool(cfg.Tools.Code)
		if err != nil {
			return nil, err
		}
		for i := range codeTools {
			t := codeTools[i]
			reg[t.Name] = t
		}
	}
	return reg, nil
}