modelsync.go RawHistoryFolder
1package agent
2
3import (
4 "context"
5 "path/filepath"
6 "time"
7
8 "github.com/patriceckhart/zot/internal/provider"
9)
10
11// ModelCachePath returns the on-disk location of the merged model cache.
12func ModelCachePath() string {
13 return filepath.Join(ZotHome(), "models-cache.json")
14}
15
16// UserModelsPath returns the path to the user's models.json override.
17func UserModelsPath() string {
18 return filepath.Join(ZotHome(), "models.json")
19}
20
21// LoadCachedModels loads the cache file and applies it to the provider
22// package so FindModel / ModelsForProvider see live ids immediately.
23// Safe to call before any credentials are known.
24func LoadCachedModels() {
25 c, err := provider.LoadCache(ModelCachePath())
26 if err != nil {
27 return
28 }
29 if len(c.Models) > 0 {
30 provider.SetLiveModels(c.Models)
31 }
32}
33
34// LoadUserModels reads $ZOT_HOME/models.json and merges any user-defined
35// models into the active catalog. User models take highest precedence.
36func LoadUserModels() {
37 models := provider.LoadUserModels(UserModelsPath())
38 provider.SetUserModels(models)
39}
40
41// RefreshModelsAsync kicks a background discovery for every provider
42// we have credentials for. Refreshed results are merged into the
43// active catalog and persisted to the on-disk cache.
44//
45// Silent on error: discovery is a nice-to-have. Callers can still use
46// the baked-in catalog if this fails.
47func RefreshModelsAsync() {
48 go refreshModels()
49}
50
51func refreshModels() {
52 cached, _ := provider.LoadCache(ModelCachePath())
53 if cached.IsFresh() {
54 return
55 }
56
57 ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
58 defer cancel()
59
60 var all []provider.Model
61
62 if cred, method, err := ResolveCredential("anthropic", ""); err == nil && method == "apikey" {
63 // /v1/models on Anthropic is API-key only; OAuth tokens can
64 // also list models via the bearer header, but we skip OAuth
65 // here to avoid surprise rate-limit hits on subscription keys.
66 if live, err := provider.DiscoverAnthropic(ctx, cred, ""); err == nil {
67 all = append(all, live...)
68 }
69 }
70 if cred, method, err := ResolveCredential("openai", ""); err == nil && method == "apikey" {
71 if live, err := provider.DiscoverOpenAI(ctx, cred, ""); err == nil {
72 all = append(all, live...)
73 }
74 }
75
76 if len(all) == 0 {
77 return
78 }
79 provider.SetLiveModels(all)
80 _ = provider.SaveCache(ModelCachePath(), provider.ModelCache{
81 FetchedAt: time.Now().UTC(),
82 Models: all,
83 })
84}