bots-garden/mini-mepublic Fork 0
d72271127802973540c648bfb372176cdaaa8e4f
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.

💾 Saved. d722711 · on d72271127802973540c648bfb372176cdaaa8e4f · k33g · 6h ago
provider.go · 97 lines · 3.8 KBGo Blame HistoryRaw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package engine

import (
	"context"
	"fmt"
	"sort"
	"strings"

	"mm/internal/config"

	"github.com/firebase/genkit/go/genkit"
)

// Provider is what changes from one LLM server to the next. There is ONE
// implementation per wire protocol, not one per vendor: Docker Model Runner and
// llama-server both speak the OpenAI chat-completions format, and differ only
// in a base URL, a key policy and the words of their error messages. Adding a
// server that speaks the same protocol is a registry entry (see openai_compat.go);
// adding a protocol (Anthropic's Messages API, Ollama's /api/chat) is a new type.
type Provider interface {
	// Name is the registry key AND the Genkit plugin name, hence the prefix of
	// the model reference Generate uses ("dmr/<id>").
	Name() string

	// Resolve turns the loaded config into a concrete Backend: the URL after
	// environment overrides and the fallback probe, the key read from the
	// environment, the model in the provider's own naming.
	Resolve(cfg config.Config) (Backend, error)

	// Open initialises Genkit with this provider's plugin, declares the model
	// (stating that it knows how to call tools) and returns the full model
	// reference. One Genkit per Engine for now; several backends in one Genkit
	// is the seam for a `/model` command later.
	Open(ctx context.Context, b Backend) (*genkit.Genkit, string, error)

	// Probe learns what it can about the server before the first question.
	// Best effort, never fatal: a server started AFTER the agent is a normal
	// demo situation, not an error.
	Probe(ctx context.Context, b Backend) Info

	// Explain rewrites a transport error as ONE actionable line, in the words of
	// this server: "start llama-server with --jinja" means nothing to a DMR
	// user, and "docker model pull" nothing to a llama.cpp user.
	Explain(err error, b Backend) string
}

// Backend is a resolved target: everything Open and Explain need, and nothing
// that still depends on the environment.
type Backend struct {
	Provider string
	BaseURL  string
	Model    string // in the provider's naming, no Genkit prefix
	APIKey   string // the resolved value; a placeholder when the server ignores it
	// APIKeyEnv is the variable the key was read from — the yaml's `apiKeyEnv`,
	// else the provider's default — or "" when neither names one. Explain cites
	// it on a 401: the first version named a variable nothing read, and a
	// message that sends the user to `export` the wrong name is worse than none.
	APIKeyEnv string
	// ContextWindow is the hint from the config, 0 when absent. The probe may
	// fill it from the server (llama-server tells its n_ctx); the config wins,
	// because the operator knows what they started the server with.
	ContextWindow int
}

// Info is what Probe found out. Warnings are printed one per line at start-up,
// dimmed like the config line; they are advice, not failures.
type Info struct {
	Reachable     bool
	ContextWindow int    // 0 = unknown
	ContextSource string // "config", "/props", … — a number without an origin never gets corrected
	Warnings      []string
}

// registry: the providers this build knows. Keys are the values `provider:`
// accepts in agent.yaml.
var registry = map[string]Provider{}

func register(p Provider) { registry[p.Name()] = p }

// Lookup finds a provider by its config name. The error lists the known names:
// the user typed one, the fix is to pick another.
func Lookup(name string) (Provider, error) {
	if p, ok := registry[name]; ok {
		return p, nil
	}
	return nil, fmt.Errorf("unknown provider %q (known: %s)", name, strings.Join(Names(), ", "))
}

// Names lists the registered providers, sorted for stable messages.
func Names() []string {
	names := make([]string, 0, len(registry))
	for n := range registry {
		names = append(names, n)
	}
	sort.Strings(names)
	return names
}