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
//! Per-tenant LLM model selection — which backend the in-tab agent uses.
//!
//! The choice is a single model ID persisted to `.lh_model` in this
//! origin's OPFS root (same pattern as [`super::key_store`] /
//! `.lh_system_prompt.txt`), read on session start by
//! [`super::chat::start_session`]. A `gemini-*` id routes to the Gemini
//! backend; a `claude-*` id routes to the Anthropic backend. Both reach
//! the model through the credit proxy in credits mode (the proxy is
//! multi-provider) and BYOK still works for Gemini.
//!
//! Unlike the encrypted `.lh_api_key`, the model id is not a secret, so
//! it's stored as plaintext UTF-8.
const MODEL_FILE: &str = ".lh_model";
/// Default model id when none is persisted — the platform's Gemini default.
/// Aliases the crate-canonical [`crate::types::DEFAULT_MODEL`] so a model-id
/// flip in ONE place propagates here (no re-typed literal to drift).
pub const DEFAULT_MODEL: &str = crateDEFAULT_MODEL;
/// The selectable models, as `(id, label)` pairs. Drives the admin
/// selector template AND is the allowlist [`save`] validates against, so a
/// stale/garbage `.lh_model` can never route to an unknown model.
///
/// The ids REFERENCE the canonical backend constants rather than re-typing
/// literals — a rename in `types`/`anthropic::wire` auto-propagates here, so
/// the selector can never advertise a dead id (the model-id-flip drift trap;
/// browser-app always pulls the `anthropic` feature, so the consts resolve).
/// `gemma-3-270m` stays a literal (the `local` feature/backend isn't always
/// present to const-reference); `gpt-*` is intentionally absent until the
/// OpenAI selector path is wired (proxy `OPENAI_API_KEY`).
pub const MODELS: & = &;
/// True for a Claude/Anthropic model id (`claude-*`). Everything else is
/// treated as a Gemini id by [`super::chat::start_session`].
pub
/// True for the in-browser local model id (`gemma-*`). Routes to the local
/// (Burn-wgpu) backend rather than the credit proxy / a network API.
pub
/// Read the persisted model id, validated against [`MODELS`]. A missing,
/// empty, or unrecognised file falls back to [`DEFAULT_MODEL`] — the
/// selector is never left pointing at a model the bundle can't route.
pub async
/// Persist `model` as the new selection. Rejects an id not in [`MODELS`]
/// so the file can only ever hold a routable model. Best-effort write.
pub async