agentic_coding_protocol/
schema.rs

1use std::{fmt::Display, ops::Deref, path::PathBuf};
2
3use derive_more::{Deref, Display, FromStr};
4use schemars::JsonSchema;
5use semver::Version;
6use serde::{Deserialize, Serialize};
7use serde_json::value::RawValue;
8
9#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
10pub struct Error {
11    pub code: i32,
12    pub message: String,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub data: Option<serde_json::Value>,
15}
16
17impl Error {
18    pub fn new(code: impl Into<(i32, String)>) -> Self {
19        let (code, message) = code.into();
20        Error {
21            code,
22            message,
23            data: None,
24        }
25    }
26
27    pub fn with_data(mut self, data: impl Into<serde_json::Value>) -> Self {
28        self.data = Some(data.into());
29        self
30    }
31
32    /// Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.
33    pub fn parse_error() -> Self {
34        Error::new(ErrorCode::PARSE_ERROR)
35    }
36
37    /// The JSON sent is not a valid Request object.
38    pub fn invalid_request() -> Self {
39        Error::new(ErrorCode::INVALID_REQUEST)
40    }
41
42    /// The method does not exist / is not available.
43    pub fn method_not_found() -> Self {
44        Error::new(ErrorCode::METHOD_NOT_FOUND)
45    }
46
47    /// Invalid method parameter(s).
48    pub fn invalid_params() -> Self {
49        Error::new(ErrorCode::INVALID_PARAMS)
50    }
51
52    /// Internal JSON-RPC error.
53    pub fn internal_error() -> Self {
54        Error::new(ErrorCode::INTERNAL_ERROR)
55    }
56
57    pub fn into_internal_error(err: impl std::error::Error) -> Self {
58        Error::internal_error().with_data(err.to_string())
59    }
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
63pub struct ErrorCode {
64    code: i32,
65    message: &'static str,
66}
67
68impl ErrorCode {
69    pub const PARSE_ERROR: ErrorCode = ErrorCode {
70        code: -32700,
71        message: "Parse error",
72    };
73
74    pub const INVALID_REQUEST: ErrorCode = ErrorCode {
75        code: -32600,
76        message: "Invalid Request",
77    };
78
79    pub const METHOD_NOT_FOUND: ErrorCode = ErrorCode {
80        code: -32601,
81        message: "Method not found",
82    };
83
84    pub const INVALID_PARAMS: ErrorCode = ErrorCode {
85        code: -32602,
86        message: "Invalid params",
87    };
88
89    pub const INTERNAL_ERROR: ErrorCode = ErrorCode {
90        code: -32603,
91        message: "Internal error",
92    };
93}
94
95impl From<ErrorCode> for (i32, String) {
96    fn from(error_code: ErrorCode) -> Self {
97        (error_code.code, error_code.message.to_string())
98    }
99}
100
101impl From<ErrorCode> for Error {
102    fn from(error_code: ErrorCode) -> Self {
103        Error::new(error_code)
104    }
105}
106
107impl std::error::Error for Error {}
108
109impl Display for Error {
110    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111        if self.message.is_empty() {
112            write!(f, "{}", self.code)?;
113        } else {
114            write!(f, "{}", self.message)?;
115        }
116
117        if let Some(data) = &self.data {
118            write!(f, ": {data}")?;
119        }
120
121        Ok(())
122    }
123}
124
125impl From<anyhow::Error> for Error {
126    fn from(error: anyhow::Error) -> Self {
127        Error::into_internal_error(error.deref())
128    }
129}
130
131#[derive(Serialize, JsonSchema)]
132#[serde(rename_all = "camelCase")]
133pub struct Method {
134    pub name: &'static str,
135    pub request_type: &'static str,
136    pub param_payload: bool,
137    pub response_type: &'static str,
138    pub response_payload: bool,
139}
140
141pub trait AnyRequest: Serialize + Sized + std::fmt::Debug + 'static {
142    type Response: Serialize + 'static;
143    fn from_method_and_params(method: &str, params: &RawValue) -> Result<Self, Error>;
144    fn response_from_method_and_result(
145        method: &str,
146        params: &RawValue,
147    ) -> Result<Self::Response, Error>;
148}
149
150macro_rules! acp_peer {
151    (
152        $handler_trait_name:ident,
153        $request_trait_name:ident,
154        $request_enum_name:ident,
155        $response_enum_name:ident,
156        $method_map_name:ident,
157        $(($request_method:ident, $request_method_string:expr, $request_name:ident, $param_payload: tt, $response_name:ident, $response_payload: tt)),*
158        $(,)?
159    ) => {
160        macro_rules! handler_trait_call_req {
161            ($self: ident, $method: ident, false, $resp_name: ident, false, $params: ident) => {
162                {
163                    $self.$method().await?;
164                    Ok($response_enum_name::$resp_name($resp_name))
165                }
166            };
167            ($self: ident, $method: ident, false, $resp_name: ident, true, $params: ident) => {
168                {
169                    let resp = $self.$method().await?;
170                    Ok($response_enum_name::$resp_name(resp))
171                }
172            };
173            ($self: ident, $method: ident, true, $resp_name: ident, false, $params: ident) => {
174                {
175                    $self.$method($params).await?;
176                    Ok($response_enum_name::$resp_name($resp_name))
177                }
178            };
179            ($self: ident, $method: ident, true, $resp_name: ident, true, $params: ident) => {
180                {
181                    let resp = $self.$method($params).await?;
182                    Ok($response_enum_name::$resp_name(resp))
183                }
184            }
185        }
186
187        macro_rules! handler_trait_req_method {
188            ($method: ident, $req: ident, false, $resp: tt, false) => {
189                fn $method(&self) -> impl Future<Output = Result<(), Error>>;
190            };
191            ($method: ident, $req: ident, false, $resp: tt, true) => {
192                fn $method(&self) -> impl Future<Output = Result<$resp, Error>>;
193            };
194            ($method: ident, $req: ident, true, $resp: tt, false) => {
195                fn $method(&self, request: $req) -> impl Future<Output = Result<(), Error>>;
196            };
197            ($method: ident, $req: ident, true, $resp: tt, true) => {
198                fn $method(&self, request: $req) -> impl Future<Output = Result<$resp, Error>>;
199            }
200        }
201
202        pub trait $handler_trait_name {
203            fn call(&self, params: $request_enum_name) -> impl Future<Output = Result<$response_enum_name, Error>> {
204                async move {
205                    match params {
206                        $(#[allow(unused_variables)]
207                        $request_enum_name::$request_name(params) => {
208                            handler_trait_call_req!(self, $request_method, $param_payload, $response_name, $response_payload, params)
209                        }),*
210                    }
211                }
212            }
213
214            $(
215                handler_trait_req_method!($request_method, $request_name, $param_payload, $response_name, $response_payload);
216            )*
217        }
218
219        pub trait $request_trait_name {
220            type Response;
221            fn into_any(self) -> $request_enum_name;
222            fn response_from_any(any: $response_enum_name) -> Result<Self::Response, Error>;
223        }
224
225        #[derive(Serialize, JsonSchema, Debug)]
226        #[serde(untagged)]
227        pub enum $request_enum_name {
228            $(
229                $request_name($request_name),
230            )*
231        }
232
233        #[derive(Serialize, Deserialize, JsonSchema)]
234        #[serde(untagged)]
235        pub enum $response_enum_name {
236            $(
237                $response_name($response_name),
238            )*
239        }
240
241        macro_rules! request_from_method_and_params {
242            ($req_name: ident, false, $params: tt) => {
243                Ok($request_enum_name::$req_name($req_name))
244            };
245            ($req_name: ident, true, $params: tt) => {
246                match serde_json::from_str($params.get()) {
247                    Ok(params) => Ok($request_enum_name::$req_name(params)),
248                    Err(e) => Err(Error::parse_error().with_data(e.to_string())),
249                }
250            };
251        }
252
253        macro_rules! response_from_method_and_result {
254            ($resp_name: ident, false, $result: tt) => {
255                Ok($response_enum_name::$resp_name($resp_name))
256            };
257            ($resp_name: ident, true, $result: tt) => {
258                match serde_json::from_str($result.get()) {
259                    Ok(result) => Ok($response_enum_name::$resp_name(result)),
260                    Err(e) => Err(Error::parse_error().with_data(e.to_string())),
261                }
262            };
263        }
264
265        impl AnyRequest for $request_enum_name {
266            type Response = $response_enum_name;
267
268            fn from_method_and_params(method: &str, params: &RawValue) -> Result<Self, Error> {
269                match method {
270                    $(
271                        $request_method_string => {
272                            request_from_method_and_params!($request_name, $param_payload, params)
273                        }
274                    )*
275                    _ => Err(Error::method_not_found()),
276                }
277            }
278
279            fn response_from_method_and_result(method: &str, params: &RawValue) -> Result<Self::Response, Error> {
280                match method {
281                    $(
282                        $request_method_string => {
283                            response_from_method_and_result!($response_name, $response_payload, params)
284                        }
285                    )*
286                    _ => Err(Error::method_not_found()),
287                }
288            }
289        }
290
291        impl $request_enum_name {
292            pub fn method_name(&self) -> &'static str {
293                match self {
294                    $(
295                        $request_enum_name::$request_name(_) => $request_method_string,
296                    )*
297                }
298            }
299        }
300
301
302
303        pub static $method_map_name: &[Method] = &[
304            $(
305                Method {
306                    name: $request_method_string,
307                    request_type: stringify!($request_name),
308                    param_payload: $param_payload,
309                    response_type: stringify!($response_name),
310                    response_payload: $response_payload,
311                },
312            )*
313        ];
314
315        macro_rules! req_into_any {
316            ($self: ident, $req_name: ident, false) => {
317                $request_enum_name::$req_name($req_name)
318            };
319            ($self: ident, $req_name: ident, true) => {
320                $request_enum_name::$req_name($self)
321            };
322        }
323
324        macro_rules! resp_type {
325            ($resp_name: ident, false) => {
326                ()
327            };
328            ($resp_name: ident, true) => {
329                $resp_name
330            };
331        }
332
333        macro_rules! resp_from_any {
334            ($any: ident, $resp_name: ident, false) => {
335                match $any {
336                    $response_enum_name::$resp_name(_) => Ok(()),
337                    _ => Err(Error::internal_error().with_data("Unexpected Response"))
338                }
339            };
340            ($any: ident, $resp_name: ident, true) => {
341                match $any {
342                    $response_enum_name::$resp_name(this) => Ok(this),
343                    _ => Err(Error::internal_error().with_data("Unexpected Response"))
344                }
345            };
346        }
347
348        $(
349            impl $request_trait_name for $request_name {
350                type Response = resp_type!($response_name, $response_payload);
351
352                fn into_any(self) -> $request_enum_name {
353                    req_into_any!(self, $request_name, $param_payload)
354                }
355
356                fn response_from_any(any: $response_enum_name) -> Result<Self::Response, Error> {
357                    resp_from_any!(any, $response_name, $response_payload)
358                }
359            }
360        )*
361    };
362}
363
364// requests sent from the client (the IDE) to the agent
365acp_peer!(
366    Client,
367    ClientRequest,
368    AnyClientRequest,
369    AnyClientResult,
370    CLIENT_METHODS,
371    (
372        stream_assistant_message_chunk,
373        "streamAssistantMessageChunk",
374        StreamAssistantMessageChunkParams,
375        true,
376        StreamAssistantMessageChunkResponse,
377        false
378    ),
379    (
380        request_tool_call_confirmation,
381        "requestToolCallConfirmation",
382        RequestToolCallConfirmationParams,
383        true,
384        RequestToolCallConfirmationResponse,
385        true
386    ),
387    (
388        push_tool_call,
389        "pushToolCall",
390        PushToolCallParams,
391        true,
392        PushToolCallResponse,
393        true
394    ),
395    (
396        update_tool_call,
397        "updateToolCall",
398        UpdateToolCallParams,
399        true,
400        UpdateToolCallResponse,
401        false
402    ),
403    (
404        update_plan,
405        "updatePlan",
406        UpdatePlanParams,
407        true,
408        UpdatePlanResponse,
409        false
410    ),
411    (
412        write_text_file,
413        "writeTextFile",
414        WriteTextFileParams,
415        true,
416        WriteTextFileResponse,
417        false
418    ),
419    (
420        read_text_file,
421        "readTextFile",
422        ReadTextFileParams,
423        true,
424        ReadTextFileResponse,
425        true
426    ),
427);
428
429// requests sent from the agent to the client (the IDE)
430acp_peer!(
431    Agent,
432    AgentRequest,
433    AnyAgentRequest,
434    AnyAgentResult,
435    AGENT_METHODS,
436    (
437        initialize,
438        "initialize",
439        InitializeParams,
440        true,
441        InitializeResponse,
442        true
443    ),
444    (
445        authenticate,
446        "authenticate",
447        AuthenticateParams,
448        false,
449        AuthenticateResponse,
450        false
451    ),
452    (
453        send_user_message,
454        "sendUserMessage",
455        SendUserMessageParams,
456        true,
457        SendUserMessageResponse,
458        false
459    ),
460    (
461        cancel_send_message,
462        "cancelSendMessage",
463        CancelSendMessageParams,
464        false,
465        CancelSendMessageResponse,
466        false
467    )
468);
469
470// --- Messages sent from the client to the agent --- \\
471
472/// Initialize sets up the agent's state. It should be called before any other method,
473/// and no other methods should be called until it has completed.
474///
475/// If the agent is not authenticated, then the client should prompt the user to authenticate,
476/// and then call the `authenticate` method.
477/// Otherwise the client can send other messages to the agent.
478#[derive(Debug, Serialize, Deserialize, JsonSchema)]
479#[serde(rename_all = "camelCase")]
480pub struct InitializeParams {
481    /// The version of the protocol that the client supports.
482    /// This should be the latest version supported by the client.
483    pub protocol_version: ProtocolVersion,
484}
485
486#[derive(Clone, Debug, Deref, Display, FromStr, Serialize, Deserialize, JsonSchema)]
487#[serde(transparent)]
488pub struct ProtocolVersion(Version);
489
490impl ProtocolVersion {
491    pub fn latest() -> Self {
492        Self(env!("CARGO_PKG_VERSION").parse().expect("Invalid version"))
493    }
494}
495
496#[derive(Debug, Serialize, Deserialize, JsonSchema)]
497#[serde(rename_all = "camelCase")]
498pub struct InitializeResponse {
499    /// The version of the protocol that the agent supports.
500    /// If the agent supports the requested version, it should respond with the same version.
501    /// Otherwise, the agent should respond with the latest version it supports.
502    pub protocol_version: ProtocolVersion,
503    /// Indicates whether the agent is authenticated and
504    /// ready to handle requests.
505    pub is_authenticated: bool,
506}
507
508/// Triggers authentication on the agent side.
509///
510/// This method should only be called if the initialize response indicates the user isn't already authenticated.
511/// If this succceeds then the client can send other messasges to the agent,
512/// If it fails then the error message should be shown and the user prompted to authenticate.
513///
514/// The implementation of authentication is left up to the agent, typically an oauth
515/// flow is run by opening a browser window in the background.
516#[derive(Debug, Serialize, Deserialize, JsonSchema)]
517#[serde(rename_all = "camelCase")]
518pub struct AuthenticateParams;
519
520#[derive(Debug, Serialize, Deserialize, JsonSchema)]
521#[serde(rename_all = "camelCase")]
522pub struct AuthenticateResponse;
523
524/// sendUserMessage allows the user to send a message to the agent.
525/// This method should complete after the agent is finished, during
526/// which time the agent may update the client by calling
527/// streamAssistantMessageChunk and other methods.
528#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
529#[serde(rename_all = "camelCase")]
530pub struct SendUserMessageParams {
531    pub chunks: Vec<UserMessageChunk>,
532}
533
534#[derive(Debug, Serialize, Deserialize, JsonSchema)]
535#[serde(rename_all = "camelCase")]
536pub struct SendUserMessageResponse;
537
538/// A part in a user message
539#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
540#[serde(untagged, rename_all = "camelCase")]
541pub enum UserMessageChunk {
542    /// A chunk of text in user message
543    Text { text: String },
544    /// A file path mention in a user message
545    Path { path: PathBuf },
546}
547
548/// cancelSendMessage allows the client to request that the agent
549/// stop running. The agent should resolve or reject the current sendUserMessage call.
550#[derive(Debug, Serialize, Deserialize, JsonSchema)]
551#[serde(rename_all = "camelCase")]
552pub struct CancelSendMessageParams;
553
554#[derive(Debug, Serialize, Deserialize, JsonSchema)]
555#[serde(rename_all = "camelCase")]
556pub struct CancelSendMessageResponse;
557
558// --- Messages sent from the agent to the client --- \\
559
560/// Streams part of an assistant response to the client
561#[derive(Debug, Serialize, Deserialize, JsonSchema)]
562#[serde(rename_all = "camelCase")]
563pub struct StreamAssistantMessageChunkParams {
564    pub chunk: AssistantMessageChunk,
565}
566
567#[derive(Debug, Serialize, Deserialize, JsonSchema)]
568#[serde(rename_all = "camelCase")]
569pub struct StreamAssistantMessageChunkResponse;
570
571#[derive(Debug, Serialize, Deserialize, JsonSchema)]
572#[serde(untagged, rename_all = "camelCase")]
573pub enum AssistantMessageChunk {
574    Text { text: String },
575    Thought { thought: String },
576}
577
578/// Request confirmation before running a tool
579///
580/// When allowed, the client returns a [`ToolCallId`] which can be used
581/// to update the tool call's `status` and `content` as it runs.
582#[derive(Debug, Serialize, Deserialize, JsonSchema)]
583#[serde(rename_all = "camelCase")]
584pub struct RequestToolCallConfirmationParams {
585    #[serde(flatten)]
586    pub tool_call: PushToolCallParams,
587    pub confirmation: ToolCallConfirmation,
588}
589
590#[derive(Debug, Serialize, Deserialize, JsonSchema)]
591#[serde(rename_all = "camelCase")]
592// todo? make this `pub enum ToolKind { Edit, Search, Read, Fetch, ...}?`
593// avoids being to UI centric.
594pub enum Icon {
595    FileSearch,
596    Folder,
597    Globe,
598    Hammer,
599    LightBulb,
600    Pencil,
601    Regex,
602    Terminal,
603}
604
605#[derive(Debug, Serialize, Deserialize, JsonSchema)]
606#[serde(tag = "type", rename_all = "camelCase")]
607pub enum ToolCallConfirmation {
608    #[serde(rename_all = "camelCase")]
609    Edit {
610        #[serde(skip_serializing_if = "Option::is_none")]
611        description: Option<String>,
612    },
613    #[serde(rename_all = "camelCase")]
614    Execute {
615        command: String,
616        root_command: String,
617        #[serde(skip_serializing_if = "Option::is_none")]
618        description: Option<String>,
619    },
620    #[serde(rename_all = "camelCase")]
621    Mcp {
622        server_name: String,
623        tool_name: String,
624        tool_display_name: String,
625        #[serde(skip_serializing_if = "Option::is_none")]
626        description: Option<String>,
627    },
628    #[serde(rename_all = "camelCase")]
629    Fetch {
630        urls: Vec<String>,
631        #[serde(skip_serializing_if = "Option::is_none")]
632        description: Option<String>,
633    },
634    #[serde(rename_all = "camelCase")]
635    Other { description: String },
636}
637
638#[derive(Debug, Serialize, Deserialize, JsonSchema)]
639#[serde(tag = "type", rename_all = "camelCase")]
640pub struct RequestToolCallConfirmationResponse {
641    pub id: ToolCallId,
642    pub outcome: ToolCallConfirmationOutcome,
643}
644
645#[derive(Debug, Clone, Copy, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
646#[serde(rename_all = "camelCase")]
647pub enum ToolCallConfirmationOutcome {
648    /// Allow this one call
649    Allow,
650    /// Always allow this kind of operation
651    AlwaysAllow,
652    /// Always allow any tool from this MCP server
653    AlwaysAllowMcpServer,
654    /// Always allow this tool from this MCP server
655    AlwaysAllowTool,
656    /// Reject this tool call
657    Reject,
658    /// The generation was canceled before a confirming
659    Cancel,
660}
661
662/// pushToolCall allows the agent to start a tool call
663/// when it does not need to request permission to do so.
664///
665/// The returned id can be used to update the UI for the tool
666/// call as needed.
667#[derive(Debug, Serialize, Deserialize, JsonSchema)]
668#[serde(rename_all = "camelCase")]
669pub struct PushToolCallParams {
670    pub label: String,
671    pub icon: Icon,
672    #[serde(skip_serializing_if = "Option::is_none")]
673    pub content: Option<ToolCallContent>,
674    #[serde(default, skip_serializing_if = "Vec::is_empty")]
675    pub locations: Vec<ToolCallLocation>,
676}
677
678#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
679#[serde(tag = "type", rename_all = "camelCase")]
680pub struct ToolCallLocation {
681    pub path: PathBuf,
682    #[serde(skip_serializing_if = "Option::is_none")]
683    pub line: Option<u32>,
684}
685
686#[derive(Debug, Serialize, Deserialize, JsonSchema)]
687#[serde(tag = "type", rename_all = "camelCase")]
688pub struct PushToolCallResponse {
689    pub id: ToolCallId,
690}
691
692#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Eq, PartialEq, Hash)]
693#[serde(rename_all = "camelCase")]
694pub struct ToolCallId(pub u64);
695
696/// updateToolCall allows the agent to update the content and status of the tool call.
697///
698/// The new content replaces what is currently displayed in the UI.
699///
700/// The [`ToolCallId`] is included in the response of
701/// `pushToolCall` or `requestToolCallConfirmation` respectively.
702#[derive(Debug, Serialize, Deserialize, JsonSchema)]
703#[serde(rename_all = "camelCase")]
704pub struct UpdateToolCallParams {
705    pub tool_call_id: ToolCallId,
706    pub status: ToolCallStatus,
707    pub content: Option<ToolCallContent>,
708}
709
710#[derive(Debug, Serialize, Deserialize, JsonSchema)]
711pub struct UpdateToolCallResponse;
712
713/// Parameters for updating the current execution plan.
714///
715/// This allows the assistant to communicate its high-level plan
716/// for completing the user's request.
717#[derive(Debug, Serialize, Deserialize, JsonSchema)]
718#[serde(rename_all = "camelCase")]
719pub struct UpdatePlanParams {
720    /// The list of plan entries representing the current execution plan.
721    pub entries: Vec<PlanEntry>,
722}
723
724#[derive(Debug, Serialize, Deserialize, JsonSchema)]
725pub struct UpdatePlanResponse;
726
727/// A single entry in the execution plan.
728///
729/// Represents a task or goal that the assistant intends to accomplish
730/// as part of fulfilling the user's request.
731#[derive(Debug, Serialize, Deserialize, JsonSchema)]
732#[serde(rename_all = "camelCase")]
733pub struct PlanEntry {
734    /// Description of what this task aims to accomplish
735    pub content: String,
736    /// Relative importance of this task
737    pub priority: PlanEntryPriority,
738    /// Current progress of this task
739    pub status: PlanEntryStatus,
740}
741
742/// Priority levels for plan entries.
743///
744/// Used to indicate the relative importance or urgency of different
745/// tasks in the execution plan.
746#[derive(Deserialize, Serialize, JsonSchema, Debug)]
747#[serde(rename_all = "snake_case")]
748pub enum PlanEntryPriority {
749    High,
750    Medium,
751    Low,
752}
753
754/// Status of a plan entry in the execution flow.
755///
756/// Tracks the lifecycle of each task from planning through completion.
757#[derive(Deserialize, Serialize, JsonSchema, Debug)]
758#[serde(rename_all = "snake_case")]
759pub enum PlanEntryStatus {
760    Pending,
761    InProgress,
762    Completed,
763}
764
765#[derive(Debug, Serialize, Deserialize, JsonSchema)]
766#[serde(rename_all = "camelCase")]
767pub enum ToolCallStatus {
768    /// The tool call is currently running
769    Running,
770    /// The tool call completed successfully
771    Finished,
772    /// The tool call failed
773    Error,
774}
775
776#[derive(Debug, Serialize, Deserialize, JsonSchema)]
777#[serde(tag = "type", rename_all = "camelCase")]
778pub enum ToolCallContent {
779    #[serde(rename_all = "camelCase")]
780    Markdown { markdown: String },
781    #[serde(rename_all = "camelCase")]
782    Diff {
783        #[serde(flatten)]
784        diff: Diff,
785    },
786}
787
788#[derive(Debug, Serialize, Deserialize, JsonSchema)]
789#[serde(rename_all = "camelCase")]
790pub struct Diff {
791    pub path: PathBuf,
792    pub old_text: Option<String>,
793    pub new_text: String,
794}
795
796#[derive(Debug, Serialize, Deserialize, JsonSchema)]
797#[serde(rename_all = "camelCase")]
798pub struct WriteTextFileParams {
799    pub path: PathBuf,
800    pub content: String,
801}
802
803#[derive(Debug, Serialize, Deserialize, JsonSchema)]
804pub struct WriteTextFileResponse;
805
806#[derive(Debug, Serialize, Deserialize, JsonSchema)]
807#[serde(rename_all = "camelCase")]
808pub struct ReadTextFileParams {
809    pub path: PathBuf,
810    #[serde(skip_serializing_if = "Option::is_none")]
811    pub line: Option<u32>,
812    #[serde(skip_serializing_if = "Option::is_none")]
813    pub limit: Option<u32>,
814}
815
816#[derive(Debug, Serialize, Deserialize, JsonSchema)]
817pub struct ReadTextFileResponse {
818    pub content: String,
819}