1use std::{borrow::Cow, collections::BTreeMap, fmt};
2
3use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6
7use crate::*;
8
9pub const SESSION_TREE_USAGE_MISSING_SESSION_CODE: i32 = -32030;
10pub const SESSION_TREE_USAGE_CORRUPT_DELEGATION_CODE: i32 = -32031;
11pub const SESSION_GOAL_GET_METHOD: &str = "session.goal.get";
12pub const SESSION_GOAL_SET_METHOD: &str = "session.goal.set";
13pub const SESSION_GOAL_LIFECYCLE_METHOD: &str = "session.goal.lifecycle";
14pub const SESSION_PRODUCERS_METHOD: &str = "session.producers";
15
16#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
17pub struct JsonRpcVersion(());
18impl JsonRpcVersion {
19 #[must_use]
20 pub const fn current() -> Self {
21 Self(())
22 }
23}
24impl Serialize for JsonRpcVersion {
25 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
26 where
27 S: serde::Serializer,
28 {
29 s.serialize_str("2.0")
30 }
31}
32impl<'de> Deserialize<'de> for JsonRpcVersion {
33 fn deserialize<D>(d: D) -> Result<Self, D::Error>
34 where
35 D: serde::Deserializer<'de>,
36 {
37 let value = String::deserialize(d)?;
38 if value == "2.0" {
39 Ok(Self::current())
40 } else {
41 Err(serde::de::Error::custom(
42 "JSON-RPC version must be exactly 2.0",
43 ))
44 }
45 }
46}
47impl JsonSchema for JsonRpcVersion {
48 fn inline_schema() -> bool {
49 true
50 }
51 fn schema_name() -> Cow<'static, str> {
52 Cow::Borrowed("JsonRpcVersion")
53 }
54 fn json_schema(_: &mut SchemaGenerator) -> Schema {
55 json_schema!({"type":"string","const":"2.0"})
56 }
57}
58
59#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
60#[serde(untagged)]
61pub enum JsonRpcId {
62 Null,
63 Number(i64),
64 String(String),
65}
66#[derive(Clone, Deserialize, JsonSchema, PartialEq, Serialize)]
67#[serde(deny_unknown_fields)]
68pub struct Request {
69 pub jsonrpc: JsonRpcVersion,
70 pub id: JsonRpcId,
71 pub method: String,
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub params: Option<Value>,
74}
75impl Request {
76 #[must_use]
77 pub fn new(id: JsonRpcId, method: impl Into<String>, params: Option<Value>) -> Self {
78 Self {
79 jsonrpc: JsonRpcVersion::current(),
80 id,
81 method: method.into(),
82 params,
83 }
84 }
85}
86impl fmt::Debug for Request {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 f.debug_struct("Request")
89 .field("jsonrpc", &self.jsonrpc)
90 .field("id", &self.id)
91 .field("method", &self.method)
92 .field("params", &self.params.as_ref().map(|_| "<redacted>"))
93 .finish()
94 }
95}
96#[derive(Clone, Deserialize, JsonSchema, PartialEq, Serialize)]
97#[serde(deny_unknown_fields)]
98pub struct SuccessResponse {
99 pub jsonrpc: JsonRpcVersion,
100 pub id: JsonRpcId,
101 pub result: Value,
102}
103impl fmt::Debug for SuccessResponse {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_struct("SuccessResponse")
106 .field("jsonrpc", &self.jsonrpc)
107 .field("id", &self.id)
108 .field("result", &"<redacted>")
109 .finish()
110 }
111}
112#[derive(Clone, Deserialize, JsonSchema, PartialEq, Serialize)]
113#[serde(deny_unknown_fields)]
114pub struct JsonRpcError {
115 pub code: i32,
116 pub message: String,
117 #[serde(skip_serializing_if = "Option::is_none")]
118 pub data: Option<Value>,
119}
120impl fmt::Debug for JsonRpcError {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 f.debug_struct("JsonRpcError")
123 .field("code", &self.code)
124 .field("message", &self.message)
125 .field("data", &self.data.as_ref().map(|_| "<redacted>"))
126 .finish()
127 }
128}
129#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
130#[serde(deny_unknown_fields)]
131pub struct ErrorResponse {
132 pub jsonrpc: JsonRpcVersion,
133 pub id: JsonRpcId,
134 pub error: JsonRpcError,
135}
136#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
137#[serde(untagged)]
138pub enum Response {
139 Success(SuccessResponse),
140 Error(ErrorResponse),
141}
142#[derive(Clone, Deserialize, JsonSchema, PartialEq, Serialize)]
143#[serde(deny_unknown_fields)]
144pub struct Notification {
145 pub jsonrpc: JsonRpcVersion,
146 pub method: String,
147 #[serde(skip_serializing_if = "Option::is_none")]
148 pub params: Option<Value>,
149}
150impl Notification {
151 #[must_use]
152 pub fn new(method: impl Into<String>, params: Option<Value>) -> Self {
153 Self {
154 jsonrpc: JsonRpcVersion::current(),
155 method: method.into(),
156 params,
157 }
158 }
159}
160impl fmt::Debug for Notification {
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 f.debug_struct("Notification")
163 .field("jsonrpc", &self.jsonrpc)
164 .field("method", &self.method)
165 .field("params", &self.params.as_ref().map(|_| "<redacted>"))
166 .finish()
167 }
168}
169
170#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
171#[serde(deny_unknown_fields)]
172pub struct ClientHello {
173 pub protocol_version: ProtocolVersion,
174}
175#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
176#[serde(deny_unknown_fields)]
177pub struct ServerHello {
178 pub protocol_version: ProtocolVersion,
179}
180
181#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
182#[serde(deny_unknown_fields)]
183pub struct SessionCreateParams {
184 pub selection: RunSelection,
185}
186#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
187#[serde(deny_unknown_fields)]
188pub struct SessionCreateResult {
189 pub session: SessionMeta,
190}
191#[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
192#[serde(deny_unknown_fields)]
193pub struct SessionListParams {
194 #[serde(skip_serializing_if = "Option::is_none")]
195 pub cwd_identity: Option<CwdIdentity>,
196}
197#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
198#[serde(deny_unknown_fields)]
199pub struct SessionListResult {
200 pub sessions: Vec<SessionMeta>,
201}
202#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
203#[serde(deny_unknown_fields)]
204pub struct SessionGetParams {
205 pub session_id: SessionId,
206}
207#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
208#[serde(deny_unknown_fields)]
209pub struct SessionGetResult {
210 pub session: SessionMeta,
211}
212
213#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
214#[serde(deny_unknown_fields)]
215pub struct SessionGoalGetParams {
216 pub session_id: SessionId,
217}
218
219#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
220#[serde(deny_unknown_fields)]
221pub struct SessionGoalGetResult {
222 #[serde(deserialize_with = "crate::deserialize_required_option")]
223 #[schemars(with = "crate::NullableSchema<GoalState>", required)]
224 pub goal: Option<GoalState>,
225}
226
227#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
228#[serde(deny_unknown_fields)]
229pub struct SessionGoalSetParams {
230 pub session_id: SessionId,
231 pub objective: String,
232 #[serde(default, skip_serializing_if = "Option::is_none")]
233 pub selection: Option<RunSelection>,
234}
235
236#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
237#[serde(deny_unknown_fields)]
238pub struct SessionGoalSetResult {
239 pub goal: GoalState,
240}
241
242#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
243#[serde(deny_unknown_fields)]
244pub struct SessionGoalLifecycleParams {
245 pub session_id: SessionId,
246 pub goal_id: GoalId,
247 pub expected_revision: u64,
248 pub action: GoalLifecycleAction,
249 #[serde(default, skip_serializing_if = "Option::is_none")]
250 pub selection: Option<RunSelection>,
251}
252
253#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
254#[serde(deny_unknown_fields)]
255pub struct SessionGoalLifecycleResult {
256 pub goal: GoalState,
257}
258
259#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
260#[serde(deny_unknown_fields)]
261pub struct SessionProducersParams {
262 pub session_id: SessionId,
263}
264
265#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
266#[serde(deny_unknown_fields)]
267pub struct SessionProducersResult {
268 pub producers: Vec<ProducerRegistration>,
269 pub plugin_recovery: Vec<PluginRecoveryState>,
270}
271
272#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Serialize)]
273#[serde(deny_unknown_fields)]
274pub struct UsageRollup {
275 pub input_tokens: u64,
276 pub output_tokens: u64,
277 pub reasoning_tokens: u64,
278 pub cache_read_tokens: u64,
279 pub cache_write_tokens: u64,
280 pub request_count: u64,
281 #[serde(deserialize_with = "deserialize_required_option")]
282 #[schemars(with = "crate::NullableSchema<f64>", required)]
283 pub cache_hit_rate: Option<f64>,
284 #[serde(deserialize_with = "deserialize_required_option")]
285 #[schemars(with = "crate::NullableSchema<f64>", required)]
286 pub estimated_cost_usd: Option<f64>,
287 pub by_model: BTreeMap<ModelKey, ModelUsageRollup>,
288 #[serde(skip)]
289 #[schemars(skip)]
290 pub arithmetic_overflow: bool,
291}
292
293#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Serialize)]
294#[serde(deny_unknown_fields)]
295pub struct ModelUsageRollup {
296 pub input_tokens: u64,
297 pub output_tokens: u64,
298 pub reasoning_tokens: u64,
299 pub cache_read_tokens: u64,
300 pub cache_write_tokens: u64,
301 pub request_count: u64,
302 #[serde(deserialize_with = "deserialize_required_option")]
303 #[schemars(with = "crate::NullableSchema<f64>", required)]
304 pub cache_hit_rate: Option<f64>,
305 #[serde(deserialize_with = "deserialize_required_option")]
306 #[schemars(with = "crate::NullableSchema<f64>", required)]
307 pub estimated_cost_usd: Option<f64>,
308 #[serde(skip)]
309 #[schemars(skip)]
310 pub observations: Vec<Usage>,
311 #[serde(skip)]
312 #[schemars(skip)]
313 pub cost_provenance: Vec<UsageCostProvenance>,
314 #[serde(skip)]
315 #[schemars(skip)]
316 pub arithmetic_overflow: bool,
317}
318
319#[doc(hidden)]
320#[derive(Clone, Copy, Debug, Eq, PartialEq)]
321pub enum UsageCostProvenance {
322 Stamped(Option<u64>),
323}
324
325#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
326#[serde(deny_unknown_fields)]
327pub struct SessionUsageParams {
328 pub session_id: SessionId,
329}
330
331#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
332#[serde(deny_unknown_fields)]
333pub struct SessionUsageResult {
334 pub session_id: SessionId,
335 pub usage: UsageRollup,
336}
337
338#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
339#[serde(deny_unknown_fields)]
340pub struct SessionTreeUsageResult {
341 pub session_id: SessionId,
342 pub usage: UsageRollup,
343 pub session_count: u64,
344}
345
346#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
347#[serde(deny_unknown_fields)]
348pub struct AgentUsageParams {
349 pub agent_id: AgentId,
350}
351
352#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
353#[serde(deny_unknown_fields)]
354pub struct AgentUsageResult {
355 pub agent_id: AgentId,
356 pub usage: UsageRollup,
357}
358
359#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
360#[serde(deny_unknown_fields)]
361pub struct GlobalUsageParams {}
362
363#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
364#[serde(deny_unknown_fields)]
365pub struct GlobalUsageResult {
366 pub usage: UsageRollup,
367}
368
369#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
370#[serde(deny_unknown_fields)]
371pub struct ChildSummary {
372 pub session_id: SessionId,
373 pub agent: AgentId,
374 #[serde(deserialize_with = "deserialize_nullable_title")]
375 #[schemars(with = "crate::NullableSchema<SessionTitle>", required)]
376 pub title: Option<SessionTitle>,
377 pub title_updated_seq: u64,
378 pub status: SessionStatus,
379 #[serde(deserialize_with = "deserialize_nullable_usage")]
380 #[schemars(with = "crate::NullableSchema<Usage>", required)]
381 pub usage: Option<Usage>,
382}
383fn deserialize_nullable_title<'de, D>(d: D) -> Result<Option<SessionTitle>, D::Error>
384where
385 D: serde::Deserializer<'de>,
386{
387 Option::deserialize(d)
388}
389fn deserialize_nullable_usage<'de, D>(d: D) -> Result<Option<Usage>, D::Error>
390where
391 D: serde::Deserializer<'de>,
392{
393 Option::deserialize(d)
394}
395#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
396#[serde(deny_unknown_fields)]
397pub struct SessionTree {
398 pub session: SessionMeta,
399 pub children: Vec<SessionTree>,
400}
401#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
402#[serde(deny_unknown_fields)]
403pub struct SessionChildrenParams {
404 pub session_id: SessionId,
405}
406#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
407#[serde(deny_unknown_fields)]
408pub struct SessionChildrenResult {
409 pub children: Vec<ChildSummary>,
410}
411#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
412#[serde(deny_unknown_fields)]
413pub struct SessionTreeParams {
414 pub session_id: SessionId,
415}
416#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
417#[serde(deny_unknown_fields)]
418pub struct SessionTreeResult {
419 pub tree: SessionTree,
420}
421#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
422#[serde(deny_unknown_fields)]
423pub struct SessionResumeParams {
424 pub session_id: SessionId,
425}
426#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
427#[serde(deny_unknown_fields)]
428pub struct SessionResumeResult {
429 pub session: SessionMeta,
430}
431
432#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
433#[serde(deny_unknown_fields)]
434pub struct SessionSetPermissionModeParams {
435 pub session_id: SessionId,
436 pub mode: PermissionMode,
437}
438#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
439#[serde(deny_unknown_fields)]
440pub struct SessionSetPermissionModeResult {}
441
442#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
443#[serde(rename_all = "snake_case")]
444pub enum PermissionRuleSource {
445 SessionOverlay,
446 AgentDocument,
447 Default,
448}
449
450#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
451#[serde(deny_unknown_fields)]
452pub struct EffectivePermissionRule {
453 pub resource: WildcardPattern,
454 pub effect: PermissionEffect,
455 pub source: PermissionRuleSource,
456}
457
458#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
459#[serde(deny_unknown_fields)]
460pub struct EffectivePermissionAction {
461 pub action: PermissionAction,
462 pub effect: PermissionEffect,
463 pub source: PermissionRuleSource,
464 pub patterns: Vec<EffectivePermissionRule>,
465}
466
467#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
468#[serde(deny_unknown_fields)]
469pub struct SessionPermissionGetParams {
470 pub session_id: SessionId,
471}
472
473#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
474#[serde(deny_unknown_fields)]
475pub struct SessionPermissionGetResult {
476 pub permissions: Vec<EffectivePermissionAction>,
477 #[serde(default, skip_serializing_if = "Option::is_none")]
478 pub current_mode: Option<PermissionMode>,
479}
480
481#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
482#[serde(deny_unknown_fields)]
483pub struct SessionPermissionSetParams {
484 pub session_id: SessionId,
485 pub action: PermissionAction,
486 pub resource: WildcardPattern,
487 pub effect: PermissionEffect,
488}
489
490#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
491#[serde(deny_unknown_fields)]
492pub struct SessionPermissionClearParams {
493 pub session_id: SessionId,
494 pub action: PermissionAction,
495 pub resource: WildcardPattern,
496}
497
498#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
499#[serde(deny_unknown_fields)]
500pub struct SessionPermissionMutationResult {
501 pub permissions: Vec<EffectivePermissionAction>,
502}
503
504#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
505#[serde(rename_all = "snake_case")]
506pub enum SkillSource {
507 User,
508 Project,
509}
510
511#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
512#[serde(deny_unknown_fields)]
513pub struct SkillDescriptor {
514 pub name: String,
515 pub description: String,
516 #[serde(deserialize_with = "crate::deserialize_required_option")]
517 #[schemars(with = "crate::NullableSchema<String>", required)]
518 pub when_to_use: Option<String>,
519 pub location: String,
520 pub source: SkillSource,
521 pub precedence_winner: bool,
522 pub permission_effect: PermissionEffect,
523 pub visible: bool,
524 pub user_invocable: bool,
525 #[serde(deserialize_with = "crate::deserialize_required_option")]
526 #[schemars(with = "crate::NullableSchema<String>", required)]
527 pub argument_hint: Option<String>,
528}
529
530#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
531#[serde(deny_unknown_fields)]
532pub struct SkillsListParams {
533 pub session_id: SessionId,
534}
535
536#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
537#[serde(deny_unknown_fields)]
538pub struct SkillsListResult {
539 pub skills: Vec<SkillDescriptor>,
540}
541
542#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
543#[serde(deny_unknown_fields)]
544pub struct SkillsGetParams {
545 pub session_id: SessionId,
546 pub name: String,
547 #[serde(default)]
548 pub args: String,
549}
550
551#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
552#[serde(deny_unknown_fields)]
553pub struct SkillsGetResult {
554 pub skill: SkillDescriptor,
555 pub rendered: String,
556}
557
558const SKILL_SUBMISSION_PREFIX: &str = "\u{0}cookie-skill:";
559
560#[must_use]
561pub fn encode_skill_submission(name: &str, args: &str) -> String {
562 encode_skill_submission_with_prompt(name, args, None)
563}
564
565#[must_use]
566pub fn encode_skill_submission_with_prompt(name: &str, args: &str, prompt: Option<&str>) -> String {
567 format!(
568 "{SKILL_SUBMISSION_PREFIX}{}",
569 serde_json::json!({"name": name, "args": args, "prompt": prompt})
570 )
571}
572
573#[must_use]
574pub fn decode_skill_submission(input: &str) -> Option<(String, String, Option<String>)> {
575 #[derive(Deserialize)]
576 #[serde(deny_unknown_fields)]
577 struct Submission {
578 name: String,
579 args: String,
580 prompt: Option<String>,
581 }
582 let submission: Submission =
583 serde_json::from_str(input.strip_prefix(SKILL_SUBMISSION_PREFIX)?).ok()?;
584 Some((submission.name, submission.args, submission.prompt))
585}
586
587#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
588#[serde(deny_unknown_fields)]
589pub struct SessionCompactParams {
590 pub session_id: SessionId,
591 #[serde(deserialize_with = "crate::deserialize_required_option")]
592 #[schemars(with = "crate::NullableSchema<SafeDisplayText>", required)]
593 pub focus: Option<SafeDisplayText>,
594}
595#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
596#[serde(deny_unknown_fields)]
597pub struct SessionCompactResult {
598 pub compacted: bool,
599 #[serde(default, skip_serializing_if = "Option::is_none")]
600 pub cancellation_reason: Option<String>,
601}
602
603#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
604#[serde(deny_unknown_fields)]
605pub struct SessionRevertParams {
606 pub session_id: SessionId,
607 #[schemars(range(min = 1))]
608 pub through_seq: u64,
609}
610#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
611#[serde(deny_unknown_fields)]
612pub struct SessionRevertResult {
613 pub session: SessionMeta,
614 #[serde(default, skip_serializing_if = "Option::is_none")]
615 pub instructions_override: Option<String>,
616}
617
618#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
619#[serde(deny_unknown_fields)]
620pub struct SessionForkParams {
621 pub session_id: SessionId,
622 #[schemars(range(min = 1))]
623 pub through_seq: u64,
624}
625#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
626#[serde(deny_unknown_fields)]
627pub struct SessionForkResult {
628 pub session_id: SessionId,
629}
630
631#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
632#[serde(tag = "type", rename_all = "snake_case", deny_unknown_fields)]
633pub enum SessionRenameChange {
634 Set { title: SessionTitle },
635 Clear,
636 Reset,
637}
638#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
639#[serde(deny_unknown_fields)]
640pub struct SessionRenameParams {
641 pub session_id: SessionId,
642 pub client_rename_id: ClientRenameId,
643 pub change: SessionRenameChange,
644}
645#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
646#[serde(deny_unknown_fields)]
647pub struct SessionRenameResult {
648 pub client_rename_id: ClientRenameId,
649 pub session: SessionMeta,
650}
651#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
652#[serde(deny_unknown_fields)]
653pub struct SessionRenameRecord {
654 pub client_rename_id: ClientRenameId,
655 pub change: SessionRenameChange,
656}
657impl SessionRenameRecord {
658 #[must_use]
659 pub fn conflicts_with(&self, request: &SessionRenameParams) -> bool {
660 self.client_rename_id == request.client_rename_id && self.change != request.change
661 }
662 #[must_use]
663 pub fn matches(&self, request: &SessionRenameParams) -> bool {
664 self.client_rename_id == request.client_rename_id && self.change == request.change
665 }
666}
667#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
668#[serde(rename_all = "snake_case")]
669pub enum SessionRenameErrorCode {
670 SessionNotFound,
671 InvalidTitle,
672 IdempotencyConflict,
673}
674#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
675#[serde(deny_unknown_fields)]
676pub struct SessionRenameError {
677 pub code: SessionRenameErrorCode,
678 pub session_id: SessionId,
679 pub client_rename_id: ClientRenameId,
680}
681
682#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
683#[serde(deny_unknown_fields)]
684pub struct RunStartParams {
685 pub session_id: SessionId,
686 pub client_run_id: ClientRunId,
687 pub selection: RunSelection,
688 pub input: String,
689 #[serde(default, skip_serializing_if = "is_false")]
691 pub reset_fallback: bool,
692}
693
694fn is_false(value: &bool) -> bool {
695 !value
696}
697#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
698#[serde(rename_all = "snake_case")]
699pub enum RunStartConflictCode {
700 IdempotencyConflict,
701}
702#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
703#[serde(deny_unknown_fields)]
704pub struct RunStartConflict {
705 pub code: RunStartConflictCode,
706 pub session_id: SessionId,
707 pub client_run_id: ClientRunId,
708}
709#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
710#[serde(deny_unknown_fields)]
711pub struct RunStartResult {
712 pub run_id: RunId,
713}
714#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
715#[serde(deny_unknown_fields)]
716pub struct RunSteerParams {
717 pub run_id: RunId,
718 pub input: String,
719}
720#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
721#[serde(deny_unknown_fields)]
722pub struct RunSteerResult {
723 pub accepted: bool,
724 #[serde(default, skip_serializing_if = "Option::is_none")]
725 pub handled_reason: Option<String>,
726}
727#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
728#[serde(deny_unknown_fields)]
729pub struct RunRecallSteerParams {
730 pub run_id: RunId,
731}
732#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
733#[serde(deny_unknown_fields)]
734pub struct RunRecallSteerResult {
735 #[serde(deserialize_with = "deserialize_required_option")]
736 #[schemars(with = "crate::NullableSchema<String>", required)]
737 pub recalled: Option<String>,
738}
739#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
740#[serde(deny_unknown_fields)]
741pub struct RunCancelParams {
742 pub run_id: RunId,
743}
744#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
745#[serde(deny_unknown_fields)]
746pub struct RunCancelResult {
747 pub cancelled: bool,
748}
749#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
750#[serde(deny_unknown_fields)]
751pub struct RunToolStdinParams {
752 pub run_id: RunId,
753 pub call_id: ToolCallId,
754 #[serde(skip_serializing_if = "Option::is_none")]
755 pub data: Option<String>,
756 pub eof: bool,
757}
758#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
759#[serde(deny_unknown_fields)]
760pub struct RunToolStdinResult {
761 pub accepted: bool,
762}
763
764#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
765#[serde(deny_unknown_fields)]
766pub struct EventsSubscribeParams {
767 pub session_id: SessionId,
768 #[serde(skip_serializing_if = "Option::is_none")]
769 pub cursor: Option<u64>,
770}
771#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
772#[serde(deny_unknown_fields)]
773pub struct EventsSubscribeResult {
774 pub events: Vec<StoredEvent>,
775}
776
777#[derive(Clone, Debug, Eq, JsonSchema, PartialEq, Serialize)]
778#[serde(deny_unknown_fields)]
779pub struct ApprovalRespondParams {
780 pub session_id: SessionId,
781 pub approval_id: ApprovalId,
782 #[schemars(range(min = 1))]
783 pub request_revision: u64,
784 pub operation_fingerprint: OperationFingerprint,
785 pub client_response_id: ClientResponseId,
786 pub decision: ApprovalUserDecision,
787 #[serde(skip_serializing_if = "Option::is_none")]
788 pub feedback: Option<ApprovalFeedback>,
789}
790impl ApprovalRespondParams {
791 pub fn validate(&self) -> Result<(), &'static str> {
792 if self.request_revision == 0 {
793 return Err("approval request revision must be positive");
794 }
795 if self.feedback.is_some() && self.decision != ApprovalUserDecision::Reject {
796 return Err("approval feedback is allowed only with reject");
797 }
798 Ok(())
799 }
800}
801impl<'de> Deserialize<'de> for ApprovalRespondParams {
802 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
803 where
804 D: serde::Deserializer<'de>,
805 {
806 #[derive(Deserialize)]
807 #[serde(deny_unknown_fields)]
808 struct Wire {
809 session_id: SessionId,
810 approval_id: ApprovalId,
811 request_revision: u64,
812 operation_fingerprint: OperationFingerprint,
813 client_response_id: ClientResponseId,
814 decision: ApprovalUserDecision,
815 feedback: Option<ApprovalFeedback>,
816 }
817 let wire = Wire::deserialize(deserializer)?;
818 let value = Self {
819 session_id: wire.session_id,
820 approval_id: wire.approval_id,
821 request_revision: wire.request_revision,
822 operation_fingerprint: wire.operation_fingerprint,
823 client_response_id: wire.client_response_id,
824 decision: wire.decision,
825 feedback: wire.feedback,
826 };
827 value.validate().map_err(serde::de::Error::custom)?;
828 Ok(value)
829 }
830}
831#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
832#[serde(deny_unknown_fields)]
833pub struct ApprovalRespondResult {
834 pub client_response_id: ClientResponseId,
835 pub approval: ApprovalRecord,
836}
837#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
838#[serde(rename_all = "snake_case")]
839pub enum ApprovalRespondErrorCode {
840 ApprovalNotFound,
841 ApprovalNotPending,
842 ApprovalRevisionConflict,
843 DecisionNotAllowed,
844 OperationFingerprintMismatch,
845 OperationChanged,
846 IdempotencyConflict,
847}
848#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
849#[serde(deny_unknown_fields)]
850pub struct ApprovalRespondError {
851 pub code: ApprovalRespondErrorCode,
852 pub session_id: SessionId,
853 pub approval_id: ApprovalId,
854 pub client_response_id: ClientResponseId,
855 #[serde(skip_serializing_if = "Option::is_none")]
856 pub expected_revision: Option<u64>,
857 #[serde(skip_serializing_if = "Option::is_none")]
858 pub found_revision: Option<u64>,
859}
860#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
861#[serde(deny_unknown_fields)]
862pub struct ApprovalListParams {
863 pub root_session_id: SessionId,
864 #[serde(skip_serializing_if = "Option::is_none")]
865 pub status: Option<ApprovalStatus>,
866}
867#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
868#[serde(deny_unknown_fields)]
869pub struct ApprovalListResult {
870 pub approvals: Vec<ApprovalRecord>,
871 pub tree_grants: Vec<TreeApprovalGrant>,
872}
873
874#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
875#[serde(rename_all = "snake_case")]
876pub enum McpConfigSource {
877 UserFile,
878 WorkspaceFile,
879 Runtime,
880}
881
882#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
883#[serde(rename_all = "snake_case")]
884pub enum McpConfigTarget {
885 UserFile,
886 WorkspaceFile,
887}
888
889#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
890#[serde(rename_all = "snake_case")]
891pub enum McpServerState {
892 Connected,
893 Connecting,
894 Failed,
895 NeedsAuth,
896 Disabled,
897 LazyNotConnected,
898 Disconnected,
899}
900
901#[derive(Clone, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
902#[serde(deny_unknown_fields)]
903pub struct McpOAuthSettingsDefinition {
904 #[serde(default, skip_serializing_if = "Option::is_none")]
905 pub client_id: Option<String>,
906 #[serde(default, skip_serializing_if = "Option::is_none")]
907 pub client_secret: Option<String>,
908 #[serde(default, skip_serializing_if = "Option::is_none")]
909 pub client_metadata_url: Option<String>,
910 #[serde(default, skip_serializing_if = "Option::is_none")]
911 pub scopes: Option<Vec<String>>,
912}
913
914impl std::fmt::Debug for McpOAuthSettingsDefinition {
915 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
916 formatter
917 .debug_struct("McpOAuthSettingsDefinition")
918 .field("client_id", &self.client_id)
919 .field(
920 "client_secret",
921 &self.client_secret.as_ref().map(|_| "[REDACTED]"),
922 )
923 .field("client_metadata_url", &self.client_metadata_url)
924 .field("scopes", &self.scopes)
925 .finish()
926 }
927}
928
929#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
930#[serde(untagged)]
931pub enum McpOAuthDefinition {
932 Bool(bool),
933 Settings(McpOAuthSettingsDefinition),
934}
935
936#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
937#[serde(deny_unknown_fields)]
938pub struct McpServerDefinition {
939 #[serde(deserialize_with = "deserialize_required_option")]
940 #[schemars(with = "crate::NullableSchema<String>", required)]
941 pub command: Option<String>,
942 pub args: Vec<String>,
943 pub env: BTreeMap<String, String>,
944 #[serde(deserialize_with = "deserialize_required_option")]
945 #[schemars(with = "crate::NullableSchema<String>", required)]
946 pub cwd: Option<String>,
947 #[serde(deserialize_with = "deserialize_required_option")]
948 #[schemars(with = "crate::NullableSchema<String>", required)]
949 pub url: Option<String>,
950 pub headers: BTreeMap<String, String>,
951 #[serde(default, skip_serializing_if = "Option::is_none")]
952 pub oauth: Option<McpOAuthDefinition>,
953 pub enabled: bool,
954 pub lazy: bool,
955 #[serde(deserialize_with = "deserialize_required_option")]
956 #[schemars(with = "crate::NullableSchema<u64>", required)]
957 pub timeout_ms: Option<u64>,
958}
959
960#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
961#[serde(deny_unknown_fields)]
962pub struct McpServerInfo {
963 pub name: String,
964 pub source: McpConfigSource,
965 pub definition: McpServerDefinition,
966 pub state: McpServerState,
967 pub tool_count: u32,
968 #[serde(deserialize_with = "deserialize_required_option")]
969 #[schemars(with = "crate::NullableSchema<String>", required)]
970 pub message: Option<String>,
971 #[serde(default, skip_serializing_if = "Option::is_none")]
972 pub auth_in_progress: Option<bool>,
973}
974
975#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
976#[serde(deny_unknown_fields)]
977pub struct McpServerListParams {}
978
979#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
980#[serde(deny_unknown_fields)]
981pub struct McpServerListResult {
982 pub servers: Vec<McpServerInfo>,
983}
984
985#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
986#[serde(deny_unknown_fields)]
987pub struct McpServerAddParams {
988 pub name: String,
989 pub definition: McpServerDefinition,
990}
991
992#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
993#[serde(deny_unknown_fields)]
994pub struct McpServerEditParams {
995 pub name: String,
996 pub definition: McpServerDefinition,
997}
998
999#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1000#[serde(deny_unknown_fields)]
1001pub struct McpServerNameParams {
1002 pub name: String,
1003}
1004
1005#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1006#[serde(deny_unknown_fields)]
1007pub struct McpServerSetEnabledParams {
1008 pub name: String,
1009 pub enabled: bool,
1010}
1011
1012#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1013#[serde(deny_unknown_fields)]
1014pub struct McpServerPersistParams {
1015 pub name: String,
1016 pub target: McpConfigTarget,
1017}
1018
1019#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1020#[serde(deny_unknown_fields)]
1021pub struct McpServerMutationResult {
1022 #[serde(deserialize_with = "deserialize_required_option")]
1023 #[schemars(with = "crate::NullableSchema<McpServerInfo>", required)]
1024 pub server: Option<McpServerInfo>,
1025}
1026
1027#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1028#[serde(deny_unknown_fields)]
1029pub struct McpAuthBeginParams {
1030 pub server: String,
1031}
1032
1033#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1034#[serde(deny_unknown_fields)]
1035pub struct McpAuthBeginResult {
1036 pub server: String,
1037 pub authorization_url: String,
1038}
1039
1040#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1041#[serde(deny_unknown_fields)]
1042pub struct McpAuthCancelParams {
1043 pub server: String,
1044}
1045
1046#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
1047#[serde(deny_unknown_fields)]
1048pub struct McpAuthCancelResult {
1049 pub server: String,
1050}