OCaml Claude SDK using Eio and Jsont
1(*---------------------------------------------------------------------------
2 Copyright (c) 2025 Anil Madhavapeddy <anil@recoil.org>. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6(** Control protocol wire format for SDK communication.
7
8 This module defines the wire format for the SDK control protocol used for
9 bidirectional communication between the SDK and the Claude CLI. It handles
10 JSON serialization and deserialization of control messages.
11
12 The control protocol enables:
13 - Permission requests for tool usage authorization
14 - Hook callbacks for intercepting and modifying tool execution
15 - Dynamic control for changing settings mid-conversation
16 - Server introspection for querying capabilities *)
17
18(** {1 Request Types} *)
19
20module Request : sig
21 (** SDK control request types. *)
22
23 type permission_r = private {
24 tool_name : string;
25 input : Jsont.json;
26 permission_suggestions : Permissions.Update.t list option;
27 blocked_path : string option;
28 unknown : Unknown.t;
29 }
30
31 type initialize_r = private {
32 hooks : (string * Jsont.json) list option;
33 unknown : Unknown.t;
34 }
35
36 type set_permission_mode_r = private {
37 mode : Permissions.Mode.t;
38 unknown : Unknown.t;
39 }
40
41 type hook_callback_r = private {
42 callback_id : string;
43 input : Jsont.json;
44 tool_use_id : string option;
45 unknown : Unknown.t;
46 }
47
48 type mcp_message_r = private {
49 server_name : string;
50 message : Jsont.json;
51 unknown : Unknown.t;
52 }
53
54 type set_model_r = private { model : string; unknown : Unknown.t }
55
56 type t =
57 | Interrupt
58 | Permission of permission_r
59 | Initialize of initialize_r
60 | Set_permission_mode of set_permission_mode_r
61 | Hook_callback of hook_callback_r
62 | Mcp_message of mcp_message_r
63 | Set_model of set_model_r
64 | Get_server_info
65 (** The type of SDK control requests. Wire format uses "subtype" field:
66 "interrupt", "canUseTool", "initialize", "setPermissionMode",
67 "hookCallback", "mcpMessage", "setModel", "getServerInfo". *)
68
69 val jsont : t Jsont.t
70 (** [jsont] is the Jsont codec for requests. *)
71
72 val interrupt : unit -> t
73 (** [interrupt ()] creates an interrupt request. *)
74
75 val permission :
76 tool_name:string ->
77 input:Jsont.json ->
78 ?permission_suggestions:Permissions.Update.t list ->
79 ?blocked_path:string ->
80 unit ->
81 t
82 (** [permission ~tool_name ~input ?permission_suggestions ?blocked_path ()]
83 creates a permission request. *)
84
85 val initialize : ?hooks:(string * Jsont.json) list -> unit -> t
86 (** [initialize ?hooks ()] creates an initialize request. *)
87
88 val set_permission_mode : mode:Permissions.Mode.t -> unit -> t
89 (** [set_permission_mode ~mode ()] creates a permission mode change request.
90 *)
91
92 val hook_callback :
93 callback_id:string -> input:Jsont.json -> ?tool_use_id:string -> unit -> t
94 (** [hook_callback ~callback_id ~input ?tool_use_id ()] creates a hook
95 callback request. *)
96
97 val mcp_message : server_name:string -> message:Jsont.json -> unit -> t
98 (** [mcp_message ~server_name ~message ()] creates an MCP message request. *)
99
100 val set_model : model:string -> unit -> t
101 (** [set_model ~model ()] creates a model change request. *)
102
103 val get_server_info : unit -> t
104 (** [get_server_info ()] creates a server info request. *)
105end
106
107(** {1 Response Types} *)
108
109module Response : sig
110 (** SDK control response types. *)
111
112 (** Standard JSON-RPC 2.0 error codes.
113
114 These codes follow the JSON-RPC 2.0 specification for structured error
115 responses. Using the typed codes instead of raw integers improves code
116 clarity and prevents typos. Polymorphic variants allow for easy extension.
117 *)
118 module Error_code : sig
119 type t =
120 [ `Parse_error (** -32700: Invalid JSON received *)
121 | `Invalid_request (** -32600: The request object is invalid *)
122 | `Method_not_found (** -32601: The requested method does not exist *)
123 | `Invalid_params (** -32602: Invalid method parameters *)
124 | `Internal_error (** -32603: Internal server error *)
125 | `Custom of int (** Application-specific error codes *) ]
126
127 val to_int : [< t ] -> int
128 (** [to_int t] converts an error code to its integer representation. *)
129
130 val of_int : int -> t
131 (** [of_int n] converts an integer to an error code. Standard codes are
132 mapped to their variants, others become [`Custom n]. *)
133 end
134
135 type error_detail = {
136 code : int; (** Error code for programmatic handling *)
137 message : string; (** Human-readable error message *)
138 data : Jsont.json option; (** Optional additional error data *)
139 }
140 (** Structured error detail similar to JSON-RPC. *)
141
142 val error_detail :
143 code:[< Error_code.t ] ->
144 message:string ->
145 ?data:Jsont.json ->
146 unit ->
147 error_detail
148 (** [error_detail ~code ~message ?data ()] creates a structured error detail
149 using typed error codes.
150
151 Example:
152 {[
153 error_detail ~code:`Method_not_found ~message:"Hook callback not found"
154 ()
155 ]} *)
156
157 val error_detail_jsont : error_detail Jsont.t
158 (** [error_detail_jsont] is the Jsont codec for error details. *)
159
160 type success_r = private {
161 request_id : string;
162 response : Jsont.json option;
163 unknown : Unknown.t;
164 }
165
166 type error_r = private {
167 request_id : string;
168 error : error_detail;
169 unknown : Unknown.t;
170 }
171
172 type t =
173 | Success of success_r
174 | Error of error_r
175 (** The type of SDK control responses. Wire format uses "subtype" field:
176 "success", "error". *)
177
178 val jsont : t Jsont.t
179 (** [jsont] is the Jsont codec for responses. *)
180
181 val success : request_id:string -> ?response:Jsont.json -> unit -> t
182 (** [success ~request_id ?response ()] creates a success response. *)
183
184 val error : request_id:string -> error:error_detail -> unit -> t
185 (** [error ~request_id ~error ()] creates an error response with structured
186 error detail. *)
187end
188
189(** {1 Control Envelopes} *)
190
191type request_envelope = {
192 request_id : string;
193 request : Request.t;
194 unknown : Unknown.t;
195}
196(** Control request envelope. Wire format has "type": "control_request". *)
197
198type response_envelope = { response : Response.t; unknown : Unknown.t }
199(** Control response envelope. Wire format has "type": "control_response". *)
200
201val request_envelope_jsont : request_envelope Jsont.t
202(** [request_envelope_jsont] is the Jsont codec for request envelopes. *)
203
204val response_envelope_jsont : response_envelope Jsont.t
205(** [response_envelope_jsont] is the Jsont codec for response envelopes. *)
206
207val create_request :
208 request_id:string -> request:Request.t -> unit -> request_envelope
209(** [create_request ~request_id ~request ()] creates a control request envelope.
210*)
211
212val create_response : response:Response.t -> unit -> response_envelope
213(** [create_response ~response ()] creates a control response envelope. *)
214
215(** {1 Server Information} *)
216
217module Server_info : sig
218 (** Server information and capabilities. *)
219
220 type t
221 (** Server metadata and capabilities. *)
222
223 val jsont : t Jsont.t
224 (** [jsont] is the Jsont codec for server info. *)
225
226 val create :
227 version:string ->
228 capabilities:string list ->
229 commands:string list ->
230 output_styles:string list ->
231 unit ->
232 t
233 (** [create ~version ~capabilities ~commands ~output_styles ()] creates server
234 info. *)
235
236 val version : t -> string
237 (** [version t] returns the server version. *)
238
239 val capabilities : t -> string list
240 (** [capabilities t] returns the server capabilities. *)
241
242 val commands : t -> string list
243 (** [commands t] returns available commands. *)
244
245 val output_styles : t -> string list
246 (** [output_styles t] returns available output styles. *)
247
248 val unknown : t -> Unknown.t
249 (** [unknown t] returns the unknown fields. *)
250end