Skip to main content

scv_tools/
config.rs

1//! What a session's built-in tools are configured with: limits, the
2//! delegation context, and each delegated agent's adapter settings.
3
4use std::{collections::HashMap, ffi::OsString, path::PathBuf, sync::Arc, time::Duration};
5
6use crate::{
7    builtin::{chat_attach, chat_history},
8    delegate::{
9        adapters::{OutputFormat, Resume, Transport},
10        background,
11        conversation::ConversationLimits,
12        records::DelegationRegistry,
13    },
14};
15
16/// Limits and shared state for one session's tools.
17#[derive(Debug, Clone)]
18pub struct ToolsConfig {
19    /// Default `bash` timeout when a call does not choose one.
20    pub command_timeout: Duration,
21    /// Default native-agent timeout when a call does not choose one.
22    pub agent_timeout: Duration,
23    /// The longest timeout any single call may request.
24    pub max_timeout: Duration,
25    pub output_limit_bytes: usize,
26    pub max_read_bytes: usize,
27    pub max_write_bytes: usize,
28    /// The `agent` tool is offered only below this delegation depth.
29    pub max_delegation_depth: u32,
30    /// Agents the user prefers, in order (`[agent] prefer`); the first one
31    /// offered runs an `agent` call that names none.
32    pub prefer: Vec<String>,
33    /// How many delegated conversations a session remembers, and for how long.
34    pub conversations: ConversationLimits,
35    /// Records delegated runs for listing and cleanup; `None` runs them untracked.
36    pub delegation: Option<DelegationContext>,
37    /// Background jobs `agent` calls may run at once (`background: true`);
38    /// 0 turns background calls and `agent_wait` / `agent_status` /
39    /// `agent_cancel` off.
40    pub max_background: usize,
41    /// The session's background job store, when the server reports finished
42    /// jobs; otherwise the registry makes its own.
43    pub background: Option<Arc<background::BackgroundJobs>>,
44    /// Offers `chat_attach` when the session answers on a chat channel.
45    pub chat_attach: Option<chat_attach::ChatAttachConfig>,
46    /// Offers `chat_history` and `chat_keep` when the session answers a
47    /// conversation that has a chat log.
48    pub chat_history: Option<chat_history::ChatHistoryConfig>,
49    /// Refuse a model an ACP agent's saved list lacks before the call starts.
50    /// `scv agents check` turns it off so the agent's own list decides.
51    pub precheck_agent_models: bool,
52}
53
54impl Default for ToolsConfig {
55    fn default() -> Self {
56        Self {
57            command_timeout: Duration::from_secs(600),
58            agent_timeout: Duration::from_secs(3600),
59            max_timeout: Duration::from_secs(14400),
60            output_limit_bytes: 64 * 1024,
61            max_read_bytes: 256 * 1024,
62            max_write_bytes: 1024 * 1024,
63            max_delegation_depth: 2,
64            prefer: Vec::new(),
65            conversations: ConversationLimits {
66                max: 8,
67                idle: Duration::from_secs(86400),
68            },
69            delegation: None,
70            max_background: 2,
71            background: None,
72            chat_attach: None,
73            chat_history: None,
74            precheck_agent_models: true,
75        }
76    }
77}
78
79/// The registry and parent session that delegated runs are recorded under.
80#[derive(Debug, Clone)]
81pub struct DelegationContext {
82    pub registry: Arc<DelegationRegistry>,
83    pub session: String,
84    /// Delegation depth the session's client declared (0 for a direct
85    /// client). Runs count from the larger of this and the process's own.
86    pub depth: u32,
87}
88
89impl DelegationContext {
90    /// The depth delegated runs of this session start from.
91    pub(crate) fn owner_depth(&self) -> u32 {
92        self.registry.depth().max(self.depth)
93    }
94}
95
96#[derive(Debug, Clone)]
97pub struct AgentAdapterConfig {
98    pub command: String,
99    pub args: Vec<String>,
100    /// Arguments placed immediately before the prompt, for CLIs that take the
101    /// prompt as a flag value.
102    pub prompt_args: Vec<String>,
103    /// The CLI's own full-autonomy arguments, placed after `args`, when the
104    /// user configured `permissions = "full"`; the approval summary says so.
105    pub full_permission_args: Option<Vec<String>>,
106    /// Arguments appended for a per-call model; `{model}` is substituted.
107    /// Empty means the adapter does not offer model selection.
108    pub model_args: Vec<String>,
109    /// Arguments appended for a per-call effort; `{effort}` is substituted.
110    /// Empty means the adapter does not offer effort selection.
111    pub effort_args: Vec<String>,
112    /// Describes the `model` argument for the calling model.
113    pub model_hint: String,
114    /// Environment for the nested process. SCV supplies an instance-private home.
115    pub environment: Vec<(OsString, OsString)>,
116    /// Per-user install directories searched when `command` is not on `PATH`.
117    pub search_dirs: Vec<PathBuf>,
118    /// What the CLI prints, and so how its reply is read.
119    pub output: OutputFormat,
120    /// How a conversation with the CLI is continued, if it can be.
121    pub resume: Resume,
122    /// SCV's private home for this agent, for files SCV hands the CLI.
123    pub home: Option<PathBuf>,
124    /// How SCV talks to the agent.
125    pub transport: Transport,
126    /// The agent's ACP server, when `[agents.<name>] transport` allows it and
127    /// the adapter table has one.
128    pub acp: Option<AcpAgentLaunch>,
129    /// The user's note on when to choose this agent (`[agents.<name>]
130    /// use_for`), added to its line in the `agent` tool's description.
131    pub use_for: Option<String>,
132    /// Default model to pass when the work matches `use_for` (or on every
133    /// call to this agent, when `use_for` is unset).
134    pub model: Option<String>,
135    /// Default effort to pass the same way as `model`.
136    pub effort: Option<String>,
137    /// Where SCV keeps the model and effort values this agent's ACP server
138    /// offers (`state/agent-options/<name>.json`); `None` keeps none.
139    pub options_file: Option<PathBuf>,
140}
141
142/// An agent's Agent Client Protocol server, resolved from its adapter-table
143/// entry and `[agents.<name>] transport`.
144#[derive(Debug, Clone)]
145pub struct AcpAgentLaunch {
146    pub command: String,
147    /// Arguments with the `permissions = "full"` switches already applied.
148    pub args: Vec<String>,
149    /// The ACP session mode that grants full permissions, selected in every
150    /// new session when `permissions = "full"`.
151    pub full_mode: Option<String>,
152    /// Extra environment for the ACP server, such as permission settings the
153    /// server reads only from its environment.
154    pub environment: Vec<(OsString, OsString)>,
155    /// `transport = "acp"`: never fall back to one CLI process per turn, so
156    /// the agent is not offered while its ACP server is missing.
157    pub required: bool,
158}
159
160/// Where a skill's text comes from.
161#[derive(Debug, Clone, PartialEq, Eq)]
162pub enum Skill {
163    /// A `SKILL.md` file, read when loaded and only from inside one of the
164    /// configured skill roots.
165    File(PathBuf),
166    /// Built into SCV.
167    Builtin(&'static str),
168}
169
170/// A session's skills by name.
171pub type SkillMap = HashMap<String, Skill>;