wire/answer/endpoints.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! What the settings page reads back about attached endpoints.
7
8use kernel::{Ceiling, DialectKind, ModelTag, ServerLabel};
9use serde::{Deserialize, Serialize};
10
11use super::ModelFactsSummary;
12
13/// What the settings page reads back: what is attached, and what each
14/// tag currently points at.
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
17pub struct EndpointsAnswer {
18 pub endpoints: Vec<EndpointSummary>,
19 pub chosen: Vec<ChosenSummary>,
20}
21
22/// One attached endpoint, as a reader may see it. No credential appears
23/// here in any form; `has_credential` answers the only question a page
24/// needs, which is whether one was enrolled at all.
25#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
27pub struct EndpointSummary {
28 pub name: String,
29 /// What to call it on screen. The id it was filed under when the
30 /// person gave it no other name, so a page never has to decide what
31 /// to show when a label is missing.
32 pub label: String,
33 pub base_url: String,
34 pub dialect: DialectKind,
35 /// How this endpoint is connected, as one flat word:
36 /// `openai_compat`, `responses` or `anthropic_native`.
37 ///
38 /// Resolved once when the endpoint was attached and read back
39 /// here. `dialect` beside it answers a narrower question - which
40 /// request writer runs - and two connections can share a writer
41 /// while being different registrations, so a page given only the
42 /// writer cannot say which one a person set up. The word's one
43 /// authority is `gateway::provider::registry::ConnectionKind`.
44 pub connection_kind: String,
45 /// The models this endpoint serves, with what it said about each.
46 pub models: Vec<ModelFactsSummary>,
47 /// Whether calls to it stay on this machine, which is the only thing
48 /// a confidential building may use.
49 pub local: bool,
50 pub has_credential: bool,
51 /// What the person attached this endpoint with, read back in the
52 /// shape `AttachEndpoint` carries it: a page that changes the account
53 /// list sends this back whole with only `accounts` replaced, so the
54 /// figures, headers and overrides nobody touched stay as they were
55 /// (`crates/wire/spec/Answer/Endpoints.lean` §8-85, wire D49).
56 pub tuning: crate::EndpointTuning,
57 /// Whether each listed account's key is there, one row per id in the
58 /// order of `tuning.accounts`; empty for an endpoint registered
59 /// without an account list.
60 pub account_status: Vec<AccountStatus>,
61}
62
63/// Whether one account's key is there, by the account's id. Says nothing
64/// of the key's value.
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
67pub struct AccountStatus {
68 pub id: ServerLabel,
69 pub key: KeyState,
70}
71
72/// Where one account's key stands, decided by the city so a page draws a
73/// word rather than reading two flags.
74#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
75#[serde(rename_all = "snake_case")]
76#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
77pub enum KeyState {
78 /// The account names no reference: its requests carry no key.
79 Anonymous,
80 /// The vault holds a key under the account's reference.
81 Stored,
82 /// Neither the vault nor an environment variable has one, and the
83 /// page may store one.
84 Missing,
85 /// An environment variable supplies it; the page cannot change it.
86 Environment,
87 /// An environment variable is set for it and does not read as text:
88 /// it shades the vault, so the key cannot be used either way.
89 EnvironmentUnusable,
90 /// This city has no vault open, so nothing was looked up.
91 Unread,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
95#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
96pub struct ChosenSummary {
97 pub tag: ModelTag,
98 pub endpoint: String,
99 pub model: String,
100 /// Absent when no row states this model's ceiling — which the
101 /// settings page shows as a field to fill rather than as a number.
102 pub max_output_tokens: Option<Ceiling>,
103}