Skip to main content

wire/answer/
agents.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//! The ACP page: the agent catalog, one pasted spec read as an agent
7//! entry, and the agents this city added
8//! (`crates/wire/spec/Answer/Agents.lean` ยง8-90).
9
10use kernel::{Address, B3Hash};
11use serde::{Deserialize, Serialize};
12
13/// Everything the ACP page draws from one question.
14#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
15#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
16pub struct AgentCatalogAnswer {
17    /// Agents found on this machine without running anything; each one is
18    /// a consent card of its own.
19    pub detected: Vec<AgentOffer>,
20    /// The catalog snapshot shipped with this build, the built-in entries
21    /// among them.
22    pub catalog: Vec<AgentOffer>,
23    /// The agents this city added.
24    pub added: Vec<AgentLine>,
25    pub snapshot: CatalogSnapshot,
26}
27
28/// When the shipped catalog was read from the registry.
29#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
30#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
31pub struct CatalogSnapshot {
32    /// The registry's `Date` header.
33    pub date: String,
34    /// The registry's `ETag` header.
35    pub etag: String,
36}
37
38/// One agent the person may consent to, as the consent card shows it.
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
41pub struct AgentOffer {
42    pub id: String,
43    pub name: String,
44    pub source: AgentSource,
45    /// The exact command line, shown as it is.
46    pub launch_preview: String,
47    pub version: Option<String>,
48    pub pinned: PinState,
49    pub licence: Option<String>,
50    /// The names of the environment variables the entry sets; never their
51    /// values.
52    pub env_names: Vec<String>,
53    pub login: Vec<LoginKind>,
54    /// The digest of this launch spec; `AddAgent` carries it back as the
55    /// consent.
56    pub spec_digest: B3Hash,
57}
58
59/// Where an agent entry came from.
60#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
61#[serde(rename_all = "snake_case")]
62#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
63pub enum AgentSource {
64    /// The ACP registry's catalog, as the build shipped it.
65    Registry,
66    /// Found on this machine.
67    Detected,
68    /// Pasted by the person.
69    Pasted,
70}
71
72/// How exactly the launch spec names the agent's version.
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
74#[serde(rename_all = "snake_case")]
75#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
76pub enum PinState {
77    /// One exact version (`pkg@1.2.3`).
78    Exact,
79    /// Whatever the launcher resolves (`@latest`, or no version).
80    Floating,
81    /// A program found on this machine; the city ran nothing, so it does
82    /// not know which version.
83    Unknown,
84}
85
86/// The two auth method types of ACP's stable schema.
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
88#[serde(rename_all = "snake_case")]
89#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
90pub enum LoginKind {
91    /// The agent signs in through `authenticate`.
92    Agent,
93    /// The agent signs in on a terminal of its own.
94    Terminal,
95}
96
97/// One agent this city added.
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
100pub struct AgentLine {
101    pub id: String,
102    pub name: String,
103    pub source: AgentSource,
104    pub version: Option<String>,
105    pub pinned: PinState,
106    pub login_state: LoginState,
107    /// The methods the agent declared in `initialize`, without the one
108    /// login this city never starts on a person's behalf.
109    pub auth_methods: Vec<AuthMethod>,
110    /// The rooms whose `[resident] harness` names this agent.
111    pub seated_in: Vec<Address>,
112}
113
114/// Where an added agent stands on signing in.
115#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
116#[serde(rename_all = "snake_case")]
117#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
118pub enum LoginState {
119    /// The city has not opened a session with it yet.
120    Unasked,
121    /// It took a session without asking for a login.
122    Ready,
123    /// It answered `-32000` (`E_AUTH_REQUIRED`).
124    Required,
125}
126
127/// One auth method an agent declared.
128#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
129#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
130pub struct AuthMethod {
131    pub id: String,
132    pub name: String,
133    pub kind: LoginKind,
134}