···11let src = Logs.Src.create "claude.client" ~doc:"Claude client"
22module Log = (val Logs.src_log src : Logs.LOG)
3344-(** Control response builders using jsont *)
44+(** Control response builders using Sdk_control codecs *)
55module Control_response = struct
66 let success ~request_id ~response =
77- Jsont.Json.object' [
88- Jsont.Json.mem (Jsont.Json.name "type") (Jsont.Json.string "control_response");
99- Jsont.Json.mem (Jsont.Json.name "response") (Jsont.Json.object' [
1010- Jsont.Json.mem (Jsont.Json.name "subtype") (Jsont.Json.string "success");
1111- Jsont.Json.mem (Jsont.Json.name "request_id") (Jsont.Json.string request_id);
1212- Jsont.Json.mem (Jsont.Json.name "response") response;
1313- ]);
1414- ]
77+ let resp = Sdk_control.Response.success ~request_id ?response () in
88+ let ctrl = Sdk_control.create_response ~response:resp () in
99+ match Jsont.Json.encode Sdk_control.jsont ctrl with
1010+ | Ok json -> json
1111+ | Error msg -> failwith ("Control_response.success: " ^ msg)
15121613 let error ~request_id ~message =
1717- Jsont.Json.object' [
1818- Jsont.Json.mem (Jsont.Json.name "type") (Jsont.Json.string "control_response");
1919- Jsont.Json.mem (Jsont.Json.name "response") (Jsont.Json.object' [
2020- Jsont.Json.mem (Jsont.Json.name "subtype") (Jsont.Json.string "error");
2121- Jsont.Json.mem (Jsont.Json.name "request_id") (Jsont.Json.string request_id);
2222- Jsont.Json.mem (Jsont.Json.name "error") (Jsont.Json.string message);
2323- ]);
2424- ]
1414+ let resp = Sdk_control.Response.error ~request_id ~error:message () in
1515+ let ctrl = Sdk_control.create_response ~response:resp () in
1616+ match Jsont.Json.encode Sdk_control.jsont ctrl with
1717+ | Ok json -> json
1818+ | Error msg -> failwith ("Control_response.error: " ^ msg)
2519end
26202721(* Helper functions for JSON manipulation using jsont *)
···3024 | Ok s -> s
3125 | Error err -> failwith (Jsont.Error.to_string err)
32263333-(* JSON construction helpers using jsont *)
3434-let json_string s = Jsont.Json.string s
3535-let json_null () = Jsont.Json.null ()
2727+(** Wire-level codec for permission responses to CLI.
2828+ Uses camelCase field names as expected by the CLI protocol. *)
2929+module Permission_wire = struct
3030+ type allow = { allow_behavior : string; allow_updated_input : Jsont.json }
3131+ type deny = { deny_behavior : string; deny_message : string }
36323737-let json_object pairs =
3838- Jsont.Json.object' (List.map (fun (k, v) -> Jsont.Json.mem (Jsont.Json.name k) v) pairs)
3333+ let allow_jsont : allow Jsont.t =
3434+ let make allow_behavior allow_updated_input = { allow_behavior; allow_updated_input } in
3535+ Jsont.Object.map ~kind:"AllowWire" make
3636+ |> Jsont.Object.mem "behavior" Jsont.string ~enc:(fun r -> r.allow_behavior)
3737+ |> Jsont.Object.mem "updatedInput" Jsont.json ~enc:(fun r -> r.allow_updated_input)
3838+ |> Jsont.Object.finish
3939+4040+ let deny_jsont : deny Jsont.t =
4141+ let make deny_behavior deny_message = { deny_behavior; deny_message } in
4242+ Jsont.Object.map ~kind:"DenyWire" make
4343+ |> Jsont.Object.mem "behavior" Jsont.string ~enc:(fun r -> r.deny_behavior)
4444+ |> Jsont.Object.mem "message" Jsont.string ~enc:(fun r -> r.deny_message)
4545+ |> Jsont.Object.finish
4646+4747+ let encode_allow ~updated_input =
4848+ match Jsont.Json.encode allow_jsont { allow_behavior = "allow"; allow_updated_input = updated_input } with
4949+ | Ok json -> json
5050+ | Error msg -> failwith ("Permission_wire.encode_allow: " ^ msg)
5151+5252+ let encode_deny ~message =
5353+ match Jsont.Json.encode deny_jsont { deny_behavior = "deny"; deny_message = message } with
5454+ | Ok json -> json
5555+ | Error msg -> failwith ("Permission_wire.encode_deny: " ^ msg)
5656+end
5757+5858+(** Wire-level codec for hook matcher configuration sent to CLI. *)
5959+module Hook_matcher_wire = struct
6060+ type t = {
6161+ matcher : string option;
6262+ hook_callback_ids : string list;
6363+ }
6464+6565+ let jsont : t Jsont.t =
6666+ let make matcher hook_callback_ids = { matcher; hook_callback_ids } in
6767+ Jsont.Object.map ~kind:"HookMatcherWire" make
6868+ |> Jsont.Object.opt_mem "matcher" Jsont.string ~enc:(fun r -> r.matcher)
6969+ |> Jsont.Object.mem "hookCallbackIds" (Jsont.list Jsont.string) ~enc:(fun r -> r.hook_callback_ids)
7070+ |> Jsont.Object.finish
7171+7272+ let encode matchers =
7373+ Jsont.Json.list (List.map (fun m ->
7474+ match Jsont.Json.encode jsont m with
7575+ | Ok json -> json
7676+ | Error msg -> failwith ("Hook_matcher_wire.encode: " ^ msg)
7777+ ) matchers)
7878+end
39794080type t = {
4181 transport : Transport.t;
4282 permission_callback : Permissions.callback option;
4383 permission_log : Permissions.Rule.t list ref option;
4484 hook_callbacks : (string, Hooks.callback) Hashtbl.t;
4545- mutable next_callback_id : int;
4685 mutable session_id : string option;
4786 control_responses : (string, Jsont.json) Hashtbl.t;
4887 control_mutex : Eio.Mutex.t;
4988 control_condition : Eio.Condition.t;
5089}
9090+9191+let session_id t = t.session_id
51925293let handle_control_request t (ctrl_req : Incoming.Control_request.t) =
5394 let request_id = Incoming.Control_request.request_id ctrl_req in
···76117 | Permissions.Result.Allow _ -> "ALLOW"
77118 | Permissions.Result.Deny _ -> "DENY"));
781197979- (* Convert permission result to CLI format *)
120120+ (* Convert permission result to CLI format using wire codec *)
80121 let response_data = match result with
81122 | Permissions.Result.Allow { updated_input; updated_permissions = _; unknown = _ } ->
82123 let updated_input = Option.value updated_input ~default:input in
8383- json_object [
8484- ("behavior", json_string "allow");
8585- ("updatedInput", updated_input);
8686- ]
124124+ Permission_wire.encode_allow ~updated_input
87125 | Permissions.Result.Deny { message; interrupt = _; unknown = _ } ->
8888- json_object [
8989- ("behavior", json_string "deny");
9090- ("message", json_string message);
9191- ]
126126+ Permission_wire.encode_deny ~message
92127 in
9393- let response = Control_response.success ~request_id ~response:response_data in
128128+ let response = Control_response.success ~request_id ~response:(Some response_data) in
94129 Log.info (fun m -> m "Sending control response: %s" (json_to_string response));
95130 Transport.send t.transport response
96131···109144 | Ok j -> j
110145 | Error msg -> failwith ("Failed to encode hook result: " ^ msg)
111146 in
112112- let response = Control_response.success ~request_id ~response:result_json in
147147+ let response = Control_response.success ~request_id ~response:(Some result_json) in
113148 Log.info (fun m -> m "Hook callback succeeded, sending response");
114149 Transport.send t.transport response
115150 with
···208243 permission_callback = Options.permission_callback options;
209244 permission_log = None;
210245 hook_callbacks;
211211- next_callback_id = 0;
212246 session_id = None;
213247 control_responses = Hashtbl.create 16;
214248 control_mutex = Eio.Mutex.create ();
···220254 | Some hooks_config ->
221255 Log.info (fun m -> m "Registering hooks...");
222256223223- (* Build hooks configuration with callback IDs *)
224224- let hooks_json = List.fold_left (fun acc (event, matchers) ->
257257+ (* Build hooks configuration with callback IDs as (string * Jsont.json) list *)
258258+ let hooks_list = List.map (fun (event, matchers) ->
225259 let event_name = Hooks.event_to_string event in
226226- let matchers_json = List.map (fun matcher ->
260260+ let matcher_wires = List.map (fun matcher ->
227261 let callback_ids = List.map (fun callback ->
228262 let callback_id = Printf.sprintf "hook_%d" !next_callback_id in
229263 incr next_callback_id;
···231265 Log.debug (fun m -> m "Registered callback: %s for event: %s" callback_id event_name);
232266 callback_id
233267 ) matcher.Hooks.callbacks in
234234- json_object [
235235- "matcher", (match matcher.Hooks.matcher with
236236- | Some p -> json_string p
237237- | None -> json_null ());
238238- "hookCallbackIds", Jsont.Json.list (List.map (fun id -> json_string id) callback_ids);
239239- ]
268268+ Hook_matcher_wire.{ matcher = matcher.Hooks.matcher; hook_callback_ids = callback_ids }
240269 ) matchers in
241241- (event_name, Jsont.Json.list matchers_json) :: acc
242242- ) [] hooks_config in
270270+ (event_name, Hook_matcher_wire.encode matcher_wires)
271271+ ) hooks_config in
243272244244- (* Send initialize control request *)
245245- let initialize_msg = json_object [
246246- "type", json_string "control_request";
247247- "request_id", json_string "init_hooks";
248248- "request", json_object [
249249- "subtype", json_string "initialize";
250250- "hooks", json_object hooks_json;
251251- ]
252252- ] in
273273+ (* Create initialize request using Sdk_control codec *)
274274+ let request = Sdk_control.Request.initialize ~hooks:hooks_list () in
275275+ let ctrl_req = Sdk_control.create_request ~request_id:"init_hooks" ~request () in
276276+ let initialize_msg = match Jsont.Json.encode Sdk_control.jsont ctrl_req with
277277+ | Ok json -> json
278278+ | Error msg -> failwith ("Failed to encode initialize request: " ^ msg)
279279+ in
253280 Log.info (fun m -> m "Sending hooks initialize request");
254254- Transport.send t.transport initialize_msg;
255255- t.next_callback_id <- !next_callback_id
281281+ Transport.send t.transport initialize_msg
256282 | None -> ());
257283258284 t
+5
lib/client.mli
···4747type t
4848(** The type of Claude clients. *)
49495050+val session_id : t -> string option
5151+(** [session_id t] returns the session ID if one has been received from Claude.
5252+ The session ID is provided in system init messages and uniquely identifies
5353+ the current conversation session. *)
5454+5055val create :
5156 ?options:Options.t ->
5257 sw:Eio.Switch.t ->
-52
lib/content_block.ml
···2020 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
2121 |> Jsont.Object.finish
22222323- let to_json t =
2424- match Jsont.Json.encode jsont t with
2525- | Ok json -> json
2626- | Error msg -> failwith ("Text.to_json: " ^ msg)
2727-2828- let of_json json =
2929- match Jsont.Json.decode jsont json with
3030- | Ok v -> v
3131- | Error msg -> raise (Invalid_argument ("Text.of_json: " ^ msg))
3232-3323 let pp fmt t =
3424 if String.length t.text > 60 then
3525 let truncated = String.sub t.text 0 57 in
···7464 | Jsont.Object (members, _) -> List.map (fun ((name, _), _) -> name) members
7565 | _ -> []
76667777- let to_json t = t
7878- let of_json json = json
7967 end
80688169 type t = {
···10189 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
10290 |> Jsont.Object.finish
10391104104- let to_json t =
105105- match Jsont.Json.encode jsont t with
106106- | Ok json -> json
107107- | Error msg -> failwith ("Tool_use.to_json: " ^ msg)
108108-109109- let of_json json =
110110- match Jsont.Json.decode jsont json with
111111- | Ok v -> v
112112- | Error msg -> raise (Invalid_argument ("Tool_use.of_json: " ^ msg))
113113-11492 let pp fmt t =
11593 let keys = Input.keys t.input in
11694 let key_info = match keys with
···147125 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
148126 |> Jsont.Object.finish
149127150150- let to_json t =
151151- match Jsont.Json.encode jsont t with
152152- | Ok json -> json
153153- | Error msg -> failwith ("Tool_result.to_json: " ^ msg)
154154-155155- let of_json json =
156156- match Jsont.Json.decode jsont json with
157157- | Ok v -> v
158158- | Error msg -> raise (Invalid_argument ("Tool_result.of_json: " ^ msg))
159159-160128 let pp fmt t =
161129 match t.is_error, t.content with
162130 | Some true, Some c ->
···195163 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
196164 |> Jsont.Object.finish
197165198198- let to_json t =
199199- match Jsont.Json.encode jsont t with
200200- | Ok json -> json
201201- | Error msg -> failwith ("Thinking.to_json: " ^ msg)
202202-203203- let of_json json =
204204- match Jsont.Json.decode jsont json with
205205- | Ok v -> v
206206- | Error msg -> raise (Invalid_argument ("Thinking.of_json: " ^ msg))
207207-208166 let pp fmt t =
209167 if String.length t.thinking > 50 then
210168 let truncated = String.sub t.thinking 0 47 in
···252210 |> Jsont.Object.case_mem "type" Jsont.string ~enc:Fun.id ~enc_case cases
253211 ~tag_to_string:Fun.id ~tag_compare:String.compare
254212 |> Jsont.Object.finish
255255-256256-let to_json t =
257257- match Jsont.Json.encode jsont t with
258258- | Ok json -> json
259259- | Error msg -> failwith ("Content_block.to_json: " ^ msg)
260260-261261-let of_json json =
262262- match Jsont.Json.decode jsont json with
263263- | Ok v -> v
264264- | Error msg -> raise (Invalid_argument ("Content_block.of_json: " ^ msg))
265213266214let pp fmt = function
267215 | Text t -> Text.pp fmt t
+10-45
lib/content_block.mli
···2424 (** [unknown t] returns any unknown fields from JSON parsing. *)
25252626 val jsont : t Jsont.t
2727- (** [jsont] is the Jsont codec for text blocks. *)
2828-2929- val to_json : t -> Jsont.json
3030- (** [to_json t] converts the text block to its JSON representation. *)
3131-3232- val of_json : Jsont.json -> t
3333- (** [of_json json] parses a text block from JSON.
3434- @raise Invalid_argument if the JSON is not a valid text block. *)
2727+ (** [jsont] is the Jsont codec for text blocks.
2828+ Use [Jsont.Json.encode jsont] and [Jsont.Json.decode jsont] for serialization. *)
35293630 val pp : Format.formatter -> t -> unit
3731 (** [pp fmt t] pretty-prints the text block. *)
···7266 val keys : t -> string list
7367 (** [keys t] returns all keys in the input. *)
74687575- val to_json : t -> Jsont.json
7676- (** [to_json t] converts to JSON representation. Internal use only. *)
7777-7878- val of_json : Jsont.json -> t
7979- (** [of_json json] parses from JSON. Internal use only. *)
8069 end
81708271 type t
···10190 (** [unknown t] returns any unknown fields from JSON parsing. *)
1029110392 val jsont : t Jsont.t
104104- (** [jsont] is the Jsont codec for tool use blocks. *)
105105-106106- val to_json : t -> Jsont.json
107107- (** [to_json t] converts the tool use block to its JSON representation. *)
108108-109109- val of_json : Jsont.json -> t
110110- (** [of_json json] parses a tool use block from JSON.
111111- @raise Invalid_argument if the JSON is not a valid tool use block. *)
9393+ (** [jsont] is the Jsont codec for tool use blocks.
9494+ Use [Jsont.Json.encode jsont] and [Jsont.Json.decode jsont] for serialization. *)
1129511396 val pp : Format.formatter -> t -> unit
11497 (** [pp fmt t] pretty-prints the tool use block. *)
···141124 (** [unknown t] returns any unknown fields from JSON parsing. *)
142125143126 val jsont : t Jsont.t
144144- (** [jsont] is the Jsont codec for tool result blocks. *)
145145-146146- val to_json : t -> Jsont.json
147147- (** [to_json t] converts the tool result block to its JSON representation. *)
148148-149149- val of_json : Jsont.json -> t
150150- (** [of_json json] parses a tool result block from JSON.
151151- @raise Invalid_argument if the JSON is not a valid tool result block. *)
127127+ (** [jsont] is the Jsont codec for tool result blocks.
128128+ Use [Jsont.Json.encode jsont] and [Jsont.Json.decode jsont] for serialization. *)
152129153130 val pp : Format.formatter -> t -> unit
154131 (** [pp fmt t] pretty-prints the tool result block. *)
···177154 (** [unknown t] returns any unknown fields from JSON parsing. *)
178155179156 val jsont : t Jsont.t
180180- (** [jsont] is the Jsont codec for thinking blocks. *)
181181-182182- val to_json : t -> Jsont.json
183183- (** [to_json t] converts the thinking block to its JSON representation. *)
184184-185185- val of_json : Jsont.json -> t
186186- (** [of_json json] parses a thinking block from JSON.
187187- @raise Invalid_argument if the JSON is not a valid thinking block. *)
157157+ (** [jsont] is the Jsont codec for thinking blocks.
158158+ Use [Jsont.Json.encode jsont] and [Jsont.Json.decode jsont] for serialization. *)
188159189160 val pp : Format.formatter -> t -> unit
190161 (** [pp fmt t] pretty-prints the thinking block. *)
···212183(** [thinking ~thinking ~signature] creates a thinking content block. *)
213184214185val jsont : t Jsont.t
215215-(** [jsont] is the Jsont codec for content blocks. *)
216216-217217-val to_json : t -> Jsont.json
218218-(** [to_json t] converts any content block to its JSON representation. *)
219219-220220-val of_json : Jsont.json -> t
221221-(** [of_json json] parses a content block from JSON.
222222- @raise Invalid_argument if the JSON is not a valid content block. *)
186186+(** [jsont] is the Jsont codec for content blocks.
187187+ Use [Jsont.Json.encode jsont] and [Jsont.Json.decode jsont] for serialization. *)
223188224189val pp : Format.formatter -> t -> unit
225190(** [pp fmt t] pretty-prints any content block. *)
+18-7
lib/hooks.ml
···435435 | Ok json -> json
436436 | Error msg -> failwith ("result_to_json: " ^ msg)
437437438438+(** Wire codec for hook matcher in protocol format *)
439439+module Protocol_matcher_wire = struct
440440+ type t = { matcher : string option; callbacks : Jsont.json list }
441441+442442+ let jsont : t Jsont.t =
443443+ let make matcher callbacks = { matcher; callbacks } in
444444+ Jsont.Object.map ~kind:"ProtocolMatcher" make
445445+ |> Jsont.Object.opt_mem "matcher" Jsont.string ~enc:(fun r -> r.matcher)
446446+ |> Jsont.Object.mem "callbacks" (Jsont.list Jsont.json) ~enc:(fun r -> r.callbacks)
447447+ |> Jsont.Object.finish
448448+449449+ let encode m =
450450+ match Jsont.Json.encode jsont m with
451451+ | Ok json -> json
452452+ | Error msg -> failwith ("Protocol_matcher_wire.encode: " ^ msg)
453453+end
454454+438455let config_to_protocol_format config =
439456 let hooks_dict = List.map (fun (event, matchers) ->
440457 let event_name = event_to_string event in
441458 let matchers_json = List.map (fun m ->
442459 (* matcher and hookCallbackIds will be filled in by client *)
443443- let mems = [
444444- Jsont.Json.mem (Jsont.Json.name "matcher") (match m.matcher with
445445- | Some p -> Jsont.Json.string p
446446- | None -> Jsont.Json.null ());
447447- Jsont.Json.mem (Jsont.Json.name "callbacks") (Jsont.Json.list []); (* Placeholder, filled by client *)
448448- ] in
449449- Jsont.Json.object' mems
460460+ Protocol_matcher_wire.encode { matcher = m.matcher; callbacks = [] }
450461 ) matchers in
451462 Jsont.Json.mem (Jsont.Json.name event_name) (Jsont.Json.list matchers_json)
452463 ) config in
+138-60
lib/message.ml
···5959 (* Encode content to json value *)
6060 let encode_content = function
6161 | String s -> Jsont.String (s, Jsont.Meta.none)
6262- | Blocks blocks -> Jsont.Array (List.map Content_block.to_json blocks, Jsont.Meta.none)
6262+ | Blocks blocks ->
6363+ let jsons = List.map (fun b ->
6464+ match Jsont.Json.encode Content_block.jsont b with
6565+ | Ok j -> j
6666+ | Error msg -> failwith ("encode_content: " ^ msg)
6767+ ) blocks in
6868+ Jsont.Array (jsons, Jsont.Meta.none)
63696470 let jsont : t Jsont.t =
6571 Jsont.Object.map ~kind:"User" (fun json_content unknown ->
···7076 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
7177 |> Jsont.Object.finish
72787979+ (** Wire-format codec for outgoing user messages.
8080+ Format: {"type": "user", "message": {"role": "user", "content": ...}} *)
8181+ module Wire = struct
8282+ type inner = { role : string; content : Jsont.json }
8383+ type outer = { type_ : string; message : inner }
8484+8585+ let inner_jsont : inner Jsont.t =
8686+ let make role content = { role; content } in
8787+ Jsont.Object.map ~kind:"UserMessageInner" make
8888+ |> Jsont.Object.mem "role" Jsont.string ~enc:(fun r -> r.role)
8989+ |> Jsont.Object.mem "content" Jsont.json ~enc:(fun r -> r.content)
9090+ |> Jsont.Object.finish
9191+9292+ let outer_jsont : outer Jsont.t =
9393+ let make type_ message = { type_; message } in
9494+ Jsont.Object.map ~kind:"UserMessageOuter" make
9595+ |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.type_)
9696+ |> Jsont.Object.mem "message" inner_jsont ~enc:(fun r -> r.message)
9797+ |> Jsont.Object.finish
9898+ end
9999+73100 let to_json t =
7474- let content_json = match t.content with
7575- | String s -> Jsont.String (s, Jsont.Meta.none)
7676- | Blocks blocks ->
7777- Jsont.Array (List.map Content_block.to_json blocks, Jsont.Meta.none)
7878- in
7979- Jsont.Object ([
8080- (Jsont.Json.name "type", Jsont.String ("user", Jsont.Meta.none));
8181- (Jsont.Json.name "message", Jsont.Object ([
8282- (Jsont.Json.name "role", Jsont.String ("user", Jsont.Meta.none));
8383- (Jsont.Json.name "content", content_json);
8484- ], Jsont.Meta.none));
8585- ], Jsont.Meta.none)
101101+ let content_json = encode_content t.content in
102102+ let wire = Wire.{
103103+ type_ = "user";
104104+ message = { role = "user"; content = content_json }
105105+ } in
106106+ match Jsont.Json.encode Wire.outer_jsont wire with
107107+ | Ok json -> json
108108+ | Error msg -> failwith ("User.to_json: " ^ msg)
8610987110 (* Jsont codec for parsing incoming user messages from CLI *)
88111 let incoming_jsont : t Jsont.t =
···215238 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
216239 |> Jsont.Object.finish
217240241241+ let encode_content_blocks blocks =
242242+ let jsons = List.map (fun b ->
243243+ match Jsont.Json.encode Content_block.jsont b with
244244+ | Ok j -> j
245245+ | Error msg -> failwith ("encode_content_blocks: " ^ msg)
246246+ ) blocks in
247247+ Jsont.Array (jsons, Jsont.Meta.none)
248248+249249+ (** Wire-format codec for outgoing assistant messages. *)
250250+ module Wire = struct
251251+ type inner = {
252252+ wire_content : Jsont.json;
253253+ wire_model : string;
254254+ wire_error : string option;
255255+ }
256256+ type outer = { wire_type : string; wire_message : inner }
257257+258258+ let inner_jsont : inner Jsont.t =
259259+ let make wire_content wire_model wire_error = { wire_content; wire_model; wire_error } in
260260+ Jsont.Object.map ~kind:"AssistantMessageInner" make
261261+ |> Jsont.Object.mem "content" Jsont.json ~enc:(fun r -> r.wire_content)
262262+ |> Jsont.Object.mem "model" Jsont.string ~enc:(fun r -> r.wire_model)
263263+ |> Jsont.Object.opt_mem "error" Jsont.string ~enc:(fun r -> r.wire_error)
264264+ |> Jsont.Object.finish
265265+266266+ let outer_jsont : outer Jsont.t =
267267+ let make wire_type wire_message = { wire_type; wire_message } in
268268+ Jsont.Object.map ~kind:"AssistantMessageOuter" make
269269+ |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.wire_type)
270270+ |> Jsont.Object.mem "message" inner_jsont ~enc:(fun r -> r.wire_message)
271271+ |> Jsont.Object.finish
272272+ end
273273+218274 let to_json t =
219219- let msg_fields = [
220220- (Jsont.Json.name "content", Jsont.Array (List.map Content_block.to_json t.content, Jsont.Meta.none));
221221- (Jsont.Json.name "model", Jsont.String (t.model, Jsont.Meta.none));
222222- ] in
223223- let msg_fields = match t.error with
224224- | Some err -> (Jsont.Json.name "error", Jsont.String (error_to_string err, Jsont.Meta.none)) :: msg_fields
225225- | None -> msg_fields
226226- in
227227- Jsont.Object ([
228228- (Jsont.Json.name "type", Jsont.String ("assistant", Jsont.Meta.none));
229229- (Jsont.Json.name "message", Jsont.Object (msg_fields, Jsont.Meta.none));
230230- ], Jsont.Meta.none)
275275+ let wire = Wire.{
276276+ wire_type = "assistant";
277277+ wire_message = {
278278+ wire_content = encode_content_blocks t.content;
279279+ wire_model = t.model;
280280+ wire_error = Option.map error_to_string t.error;
281281+ }
282282+ } in
283283+ match Jsont.Json.encode Wire.outer_jsont wire with
284284+ | Ok json -> json
285285+ | Error msg -> failwith ("Assistant.to_json: " ^ msg)
231286232287 (* Jsont codec for parsing incoming assistant messages from CLI *)
233288 let incoming_jsont : t Jsont.t =
···448503 Fmt.(option int) t.cache_creation_input_tokens
449504 Fmt.(option int) t.cache_read_input_tokens
450505451451- let to_json t =
452452- match Jsont.Json.encode jsont t with
453453- | Ok json -> json
454454- | Error msg -> failwith ("Usage.to_json: " ^ msg)
455455-456456- let of_json json =
457457- match Jsont.Json.decode jsont json with
458458- | Ok v -> v
459459- | Error msg -> raise (Invalid_argument ("Usage.of_json: " ^ msg))
460506 end
461507462508 type t = {
···510556 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
511557 |> Jsont.Object.finish
512558559559+ (** Wire-format codec for outgoing result messages (adds "type" field). *)
560560+ module Wire = struct
561561+ type wire = {
562562+ type_ : string;
563563+ subtype : string;
564564+ duration_ms : int;
565565+ duration_api_ms : int;
566566+ is_error : bool;
567567+ num_turns : int;
568568+ session_id : string;
569569+ total_cost_usd : float option;
570570+ usage : Jsont.json option;
571571+ result : string option;
572572+ structured_output : Jsont.json option;
573573+ }
574574+575575+ let jsont : wire Jsont.t =
576576+ let make type_ subtype duration_ms duration_api_ms is_error num_turns
577577+ session_id total_cost_usd usage result structured_output =
578578+ { type_; subtype; duration_ms; duration_api_ms; is_error; num_turns;
579579+ session_id; total_cost_usd; usage; result; structured_output }
580580+ in
581581+ Jsont.Object.map ~kind:"ResultWire" make
582582+ |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.type_)
583583+ |> Jsont.Object.mem "subtype" Jsont.string ~enc:(fun r -> r.subtype)
584584+ |> Jsont.Object.mem "duration_ms" Jsont.int ~enc:(fun r -> r.duration_ms)
585585+ |> Jsont.Object.mem "duration_api_ms" Jsont.int ~enc:(fun r -> r.duration_api_ms)
586586+ |> Jsont.Object.mem "is_error" Jsont.bool ~enc:(fun r -> r.is_error)
587587+ |> Jsont.Object.mem "num_turns" Jsont.int ~enc:(fun r -> r.num_turns)
588588+ |> Jsont.Object.mem "session_id" Jsont.string ~enc:(fun r -> r.session_id)
589589+ |> Jsont.Object.opt_mem "total_cost_usd" Jsont.number ~enc:(fun r -> r.total_cost_usd)
590590+ |> Jsont.Object.opt_mem "usage" Jsont.json ~enc:(fun r -> r.usage)
591591+ |> Jsont.Object.opt_mem "result" Jsont.string ~enc:(fun r -> r.result)
592592+ |> Jsont.Object.opt_mem "structured_output" Jsont.json ~enc:(fun r -> r.structured_output)
593593+ |> Jsont.Object.finish
594594+ end
595595+513596 let to_json t =
514514- let fields = [
515515- (Jsont.Json.name "type", Jsont.String ("result", Jsont.Meta.none));
516516- (Jsont.Json.name "subtype", Jsont.String (t.subtype, Jsont.Meta.none));
517517- (Jsont.Json.name "duration_ms", Jsont.Number (float_of_int t.duration_ms, Jsont.Meta.none));
518518- (Jsont.Json.name "duration_api_ms", Jsont.Number (float_of_int t.duration_api_ms, Jsont.Meta.none));
519519- (Jsont.Json.name "is_error", Jsont.Bool (t.is_error, Jsont.Meta.none));
520520- (Jsont.Json.name "num_turns", Jsont.Number (float_of_int t.num_turns, Jsont.Meta.none));
521521- (Jsont.Json.name "session_id", Jsont.String (t.session_id, Jsont.Meta.none));
522522- ] in
523523- let fields = match t.total_cost_usd with
524524- | Some cost -> (Jsont.Json.name "total_cost_usd", Jsont.Number (cost, Jsont.Meta.none)) :: fields
525525- | None -> fields
526526- in
527527- let fields = match t.usage with
528528- | Some usage -> (Jsont.Json.name "usage", Usage.to_json usage) :: fields
529529- | None -> fields
530530- in
531531- let fields = match t.result with
532532- | Some result -> (Jsont.Json.name "result", Jsont.String (result, Jsont.Meta.none)) :: fields
533533- | None -> fields
534534- in
535535- let fields = match t.structured_output with
536536- | Some output -> (Jsont.Json.name "structured_output", output) :: fields
537537- | None -> fields
538538- in
539539- Jsont.Object (fields, Jsont.Meta.none)
597597+ let usage_json = Option.map (fun u ->
598598+ match Jsont.Json.encode Usage.jsont u with
599599+ | Ok j -> j
600600+ | Error msg -> failwith ("Result.to_json: usage: " ^ msg)
601601+ ) t.usage in
602602+ let wire = Wire.{
603603+ type_ = "result";
604604+ subtype = t.subtype;
605605+ duration_ms = t.duration_ms;
606606+ duration_api_ms = t.duration_api_ms;
607607+ is_error = t.is_error;
608608+ num_turns = t.num_turns;
609609+ session_id = t.session_id;
610610+ total_cost_usd = t.total_cost_usd;
611611+ usage = usage_json;
612612+ result = t.result;
613613+ structured_output = t.structured_output;
614614+ } in
615615+ match Jsont.Json.encode Wire.jsont wire with
616616+ | Ok json -> json
617617+ | Error msg -> failwith ("Result.to_json: " ^ msg)
540618541619 let of_json json =
542620 match Jsont.Json.decode jsont json with
-6
lib/message.mli
···269269270270 val pp : Format.formatter -> t -> unit
271271 (** [pp fmt t] pretty-prints the usage statistics. *)
272272-273273- val to_json : t -> Jsont.json
274274- (** [to_json t] converts to JSON representation. Internal use only. *)
275275-276276- val of_json : Jsont.json -> t
277277- (** [of_json json] parses from JSON. Internal use only. *)
278272 end
279273280274 type t
+3-1
lib/options.ml
···218218 |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown
219219 |> Jsont.Object.finish
220220221221+(*
221222let to_json t =
222223 match Jsont.Json.encode jsont t with
223224 | Ok json -> json
···227228 match Jsont.Json.decode jsont json with
228229 | Ok t -> t
229230 | Error msg -> raise (Invalid_argument ("Options.of_json: " ^ msg))
231231+*)
230232231233let pp fmt t =
232234 Fmt.pf fmt "@[<v>Options {@ \
···249251 Fmt.(list (pair string string)) t.env
250252251253let log_options t =
252252- Log.debug (fun m -> m "Claude options: %a" pp t)254254+ Log.debug (fun m -> m "Claude options: %a" pp t)
+1-8
lib/options.mli
···356356val jsont : t Jsont.t
357357(** [jsont] is the Jsont codec for Options.t *)
358358359359-val to_json : t -> Jsont.json
360360-(** [to_json t] converts options to JSON representation. *)
361361-362362-val of_json : Jsont.json -> t
363363-(** [of_json json] parses options from JSON.
364364- @raise Invalid_argument if the JSON is not valid options. *)
365365-366359val pp : Format.formatter -> t -> unit
367360(** [pp fmt t] pretty-prints the options. *)
368361369362(** {1 Logging} *)
370363371364val log_options : t -> unit
372372-(** [log_options t] logs the current options configuration. *)365365+(** [log_options t] logs the current options configuration. *)
+28-11
lib/transport.ml
···1414 stdin : Eio.Flow.sink_ty r;
1515 stdin_close : [`Close | `Flow] r;
1616 stdout : Eio.Buf_read.t;
1717- sw : Switch.t;
1817}
19182019let setting_source_to_string = function
···162161 in
163162 let stdout = Eio.Buf_read.of_flow ~max_size (stdout_r :> Eio.Flow.source_ty r) in
164163165165- { process = P process; stdin; stdin_close; stdout; sw }
164164+ { process = P process; stdin; stdin_close; stdout }
166165167166let send t json =
168167 let data = match Jsont_bytesrw.encode_string' Jsont.json json with
···191190 Log.err (fun m -> m "Failed to receive message: %s" (Printexc.to_string exn));
192191 raise (Connection_error (Printf.sprintf "Failed to receive message: %s" (Printexc.to_string exn)))
193192193193+(** Wire codec for interrupt response messages. *)
194194+module Interrupt_wire = struct
195195+ type inner = { subtype : string; request_id : string }
196196+ type t = { type_ : string; response : inner }
197197+198198+ let inner_jsont : inner Jsont.t =
199199+ let make subtype request_id = { subtype; request_id } in
200200+ Jsont.Object.map ~kind:"InterruptInner" make
201201+ |> Jsont.Object.mem "subtype" Jsont.string ~enc:(fun r -> r.subtype)
202202+ |> Jsont.Object.mem "request_id" Jsont.string ~enc:(fun r -> r.request_id)
203203+ |> Jsont.Object.finish
204204+205205+ let jsont : t Jsont.t =
206206+ let make type_ response = { type_; response } in
207207+ Jsont.Object.map ~kind:"InterruptOuter" make
208208+ |> Jsont.Object.mem "type" Jsont.string ~enc:(fun r -> r.type_)
209209+ |> Jsont.Object.mem "response" inner_jsont ~enc:(fun r -> r.response)
210210+ |> Jsont.Object.finish
211211+212212+ let encode () =
213213+ let wire = { type_ = "control_response"; response = { subtype = "interrupt"; request_id = "" } } in
214214+ match Jsont.Json.encode jsont wire with
215215+ | Ok json -> json
216216+ | Error msg -> failwith ("Interrupt_wire.encode: " ^ msg)
217217+end
218218+194219let interrupt t =
195220 Log.info (fun m -> m "Sending interrupt signal");
196196- let interrupt_msg =
197197- Jsont.Json.object' [
198198- Jsont.Json.mem (Jsont.Json.name "type") (Jsont.Json.string "control_response");
199199- Jsont.Json.mem (Jsont.Json.name "response") (Jsont.Json.object' [
200200- Jsont.Json.mem (Jsont.Json.name "subtype") (Jsont.Json.string "interrupt");
201201- Jsont.Json.mem (Jsont.Json.name "request_id") (Jsont.Json.string "");
202202- ])
203203- ]
204204- in
221221+ let interrupt_msg = Interrupt_wire.encode () in
205222 send t interrupt_msg
206223207224let close t =