bots-garden/mini-mepublic Fork 0
main
Commits
Clone
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

provider.go · 97 lines · 3.8 KBGo Blame HistoryRaw
💾 Saved. d722711 k33g 4h ago1package engine
2
3import (
4 "context"
5 "fmt"
6 "sort"
7 "strings"
8
9 "mm/internal/config"
10
11 "github.com/firebase/genkit/go/genkit"
12)
13
14// Provider is what changes from one LLM server to the next. There is ONE
15// implementation per wire protocol, not one per vendor: Docker Model Runner and
16// llama-server both speak the OpenAI chat-completions format, and differ only
17// in a base URL, a key policy and the words of their error messages. Adding a
18// server that speaks the same protocol is a registry entry (see openai_compat.go);
19// adding a protocol (Anthropic's Messages API, Ollama's /api/chat) is a new type.
20type Provider interface {
21 // Name is the registry key AND the Genkit plugin name, hence the prefix of
22 // the model reference Generate uses ("dmr/<id>").
23 Name() string
24
25 // Resolve turns the loaded config into a concrete Backend: the URL after
26 // environment overrides and the fallback probe, the key read from the
27 // environment, the model in the provider's own naming.
28 Resolve(cfg config.Config) (Backend, error)
29
30 // Open initialises Genkit with this provider's plugin, declares the model
31 // (stating that it knows how to call tools) and returns the full model
32 // reference. One Genkit per Engine for now; several backends in one Genkit
33 // is the seam for a `/model` command later.
34 Open(ctx context.Context, b Backend) (*genkit.Genkit, string, error)
35
36 // Probe learns what it can about the server before the first question.
37 // Best effort, never fatal: a server started AFTER the agent is a normal
38 // demo situation, not an error.
39 Probe(ctx context.Context, b Backend) Info
40
41 // Explain rewrites a transport error as ONE actionable line, in the words of
42 // this server: "start llama-server with --jinja" means nothing to a DMR
43 // user, and "docker model pull" nothing to a llama.cpp user.
44 Explain(err error, b Backend) string
45}
46
47// Backend is a resolved target: everything Open and Explain need, and nothing
48// that still depends on the environment.
49type Backend struct {
50 Provider string
51 BaseURL string
52 Model string // in the provider's naming, no Genkit prefix
53 APIKey string // the resolved value; a placeholder when the server ignores it
54 // APIKeyEnv is the variable the key was read from — the yaml's `apiKeyEnv`,
55 // else the provider's default — or "" when neither names one. Explain cites
56 // it on a 401: the first version named a variable nothing read, and a
57 // message that sends the user to `export` the wrong name is worse than none.
58 APIKeyEnv string
59 // ContextWindow is the hint from the config, 0 when absent. The probe may
60 // fill it from the server (llama-server tells its n_ctx); the config wins,
61 // because the operator knows what they started the server with.
62 ContextWindow int
63}
64
65// Info is what Probe found out. Warnings are printed one per line at start-up,
66// dimmed like the config line; they are advice, not failures.
67type Info struct {
68 Reachable bool
69 ContextWindow int // 0 = unknown
70 ContextSource string // "config", "/props", … — a number without an origin never gets corrected
71 Warnings []string
72}
73
74// registry: the providers this build knows. Keys are the values `provider:`
75// accepts in agent.yaml.
76var registry = map[string]Provider{}
77
78func register(p Provider) { registry[p.Name()] = p }
79
80// Lookup finds a provider by its config name. The error lists the known names:
81// the user typed one, the fix is to pick another.
82func Lookup(name string) (Provider, error) {
83 if p, ok := registry[name]; ok {
84 return p, nil
85 }
86 return nil, fmt.Errorf("unknown provider %q (known: %s)", name, strings.Join(Names(), ", "))
87}
88
89// Names lists the registered providers, sorted for stable messages.
90func Names() []string {
91 names := make([]string, 0, len(registry))
92 for n := range registry {
93 names = append(names, n)
94 }
95 sort.Strings(names)
96 return names
97}