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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! The canonical model list (§3, §4): one available model and the one pure, TOTAL
//! resolver that places a seed against the provider's ORDERED cached list. No IO;
//! the list is the single source for "which model" — order is authoritative, there
//! is no separate rank field. The one generic `decode_models`, fed each protocol's
//! `Protocol::models_shape` (§3.1), projects the dialect's list body onto `Vec<Model>`;
//! `select_model` reads it.
use ;
use crate;
/// One available model, the canonical projection of a provider list entry (§3).
/// Ordered position in the returned `Vec` IS the provider's suggested order — the
/// single source the heuristics read, so there is no rank field. `default` is
/// CARRIED, not invented: a dialect that flags one sets it; today none does, so it
/// is `false` and §4's first-in-list rule governs — the seam stays so a provider
/// that DOES flag one needs no code change.
///
/// The three metadata fields are the provider-reported facts a harness would else
/// hand-mirror (model-discovery §3): `context_window` (input token limit),
/// `max_output_tokens` (output limit), `display_name` (human label). Each is
/// OPTION-SHAPED and CARRIED, never fabricated — absent stays `None` (the Usage
/// zero-vs-unknown principle, AGENTS.md): Google serves all three on its list GET,
/// Anthropic only `display_name`, and OpenAI/Ollama none (so those rows stay `None`;
/// the empty-set rule — a harness hand-configures only what no provider serves). The
/// fields are ADDITIVE with `serde(default)` + `skip_serializing_if`: an older cache
/// (id + default only) reads clean to `None`, and a metadata-less model serializes
/// byte-identically to the pre-metadata `{id,default}` shape — the v=1 grows-only
/// discipline, so `--json`/the on-disk cache both extend without a version break.
/// What produced the wire id — the provenance the §5.3 404 hint reads (CARRIED, not
/// reconstructed downstream: AGENTS.md). `Cached` is an entry resolved from the list
/// (an exact id, a partial match, or the default); `Verbatim` is the seed passed
/// through because the cache could not place it.
/// Resolve a `seed` against the provider's cached model list (§4) — ONE TOTAL
/// operation for default-selection, partial-matching, and "the cache can't help, try
/// it literally," distinguished only by the seed and whether a match is found (the
/// empty-input dissolve of a special case, AGENTS.md):
/// - `seed == ""` → the default: the first model flagged `default`, else
/// `models[0]` (`Cached`). An EMPTY list here is the lone error — `Config` (78):
/// nothing to send and no list to default from. `provider` names it in that
/// message (carried, not reconstructed — the caller already knows it: AGENTS.md).
/// - `seed != ""` → an exact `id` if present (`Cached`); else the FIRST id (in list
/// order) whose `id` contains the seed case-insensitively (`Cached`, "opus" →
/// "claude-opus-4-…"); else the SEED ITSELF (`Verbatim`) — attempted literally,
/// since the cache cannot place it. A cold cache (empty list) therefore yields
/// `Verbatim` for any non-empty seed: cache-absent ≡ cache-present-but-empty.
///
/// List order is authoritative — the first match is "the suggested version," never an
/// ambiguity error. Exact-before-contains so a full id present in the list resolves to
/// itself rather than a longer id that merely contains it. Verbatim-on-no-match (not an
/// error) self-heals a stale cache: a brand-new full id no list yet carries is tried
/// verbatim and succeeds; a partial typo is tried verbatim, 404s, and the caller runs
/// `bz --list-models` (§5.3).
/// The lone `select_model` failure (§4): `seed == "" && models.is_empty()` — no model
/// given and no cache to default from → `Config` (exit 78), the same family as
/// `NoProvider`/`AmbiguousModel` (config §7). The caller's next move is in the message,
/// which names `provider` so a multi-provider user knows which cache is cold.