Skip to main content

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}