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
type meta = {
id : Provider.id;
name : string;
signatures : string list;
env_key : string;
legacy_env_key : string option;
base_url : string option;
}
let all =
[
{
id = Provider.Openai;
name = "OpenAI";
signatures = [ "gpt"; "o1"; "o3"; "o4"; "chatgpt" ];
env_key = "OPENAI_API_KEY";
legacy_env_key = Some "API_KEY_OPENAI";
base_url = Some "https://api.openai.com/v1";
};
{
id = Provider.Anthropic;
name = "Anthropic";
signatures = [ "claude" ];
env_key = "ANTHROPIC_API_KEY";
legacy_env_key = Some "API_KEY_ANTHROPIC";
base_url = Some "https://api.anthropic.com/v1";
};
{
id = Provider.Xai;
name = "xAI";
signatures = [ "grok" ];
env_key = "XAI_API_KEY";
legacy_env_key = Some "API_KEY_XAI";
base_url = Some "https://api.x.ai/v1";
};
{
id = Provider.Local;
name = "Local";
signatures = [];
env_key = "LOCAL_API_KEY";
legacy_env_key = None;
base_url = None;
};
{
id = Provider.Openrouter;
name = "OpenRouter";
signatures = [];
env_key = "OPENROUTER_API_KEY";
legacy_env_key = Some "API_KEY_OPENROUTER";
base_url = Some "https://openrouter.ai/api/v1";
};
]
let find id =
match List.find_opt (fun meta -> meta.id = id) all with
| Some meta -> meta
| None -> invalid_arg "unknown provider id"
let lowercase_ascii value = String.lowercase_ascii value
let contains haystack needle =
let haystack = lowercase_ascii haystack in
let needle = lowercase_ascii needle in
let needle_len = String.length needle in
let haystack_len = String.length haystack in
let rec loop index =
if needle_len = 0 then true
else if index + needle_len > haystack_len then false
else if String.sub haystack index needle_len = needle then true
else loop (index + 1)
in
loop 0
let detect_by_model model =
if contains model "/" then Some Provider.Openrouter
else
all
|> List.find_opt (fun meta ->
meta.signatures
|> List.exists (fun signature -> contains model signature))
|> Option.map (fun meta -> meta.id)
let resolve_by_model ~local_active model =
match detect_by_model model with
| Some _ as provider -> provider
| None -> if local_active then Some Provider.Local else None
let env_keys id =
let meta = find id in
(meta.env_key, meta.legacy_env_key)
let base_url id = (find id).base_url