···91919292let session_id t = t.session_id
93939494-let handle_control_request t (ctrl_req : Incoming.Control_request.t) =
9595- let request_id = Incoming.Control_request.request_id ctrl_req in
9696- Log.info (fun m ->
9797- m "Handling control request: %s"
9898- (Incoming.Control_request.subtype ctrl_req));
9494+let handle_control_request t (ctrl_req : Sdk_control.control_request) =
9595+ let request_id = ctrl_req.request_id in
9696+ Log.info (fun m -> m "Handling control request: %s" request_id);
9997100100- match Incoming.Control_request.request ctrl_req with
101101- | Incoming.Control_request.Can_use_tool req ->
102102- let tool_name = Incoming.Control_request.Can_use_tool.tool_name req in
103103- let input = Incoming.Control_request.Can_use_tool.input req in
9898+ match ctrl_req.request with
9999+ | Sdk_control.Request.Permission req ->
100100+ let tool_name = req.tool_name in
101101+ let input = req.input in
104102 Log.info (fun m ->
105103 m "Permission request for tool '%s' with input: %s" tool_name
106104 (json_to_string input));
107107- (* TODO: Parse permission_suggestions properly *)
108108- let context = Permissions.Context.create ~suggestions:[] () in
105105+ (* Convert permission_suggestions to Context *)
106106+ let suggestions = Option.value req.permission_suggestions ~default:[] in
107107+ let context = Permissions.Context.create ~suggestions () in
109108110109 Log.info (fun m ->
111110 m "Invoking permission callback for tool: %s" tool_name);
···136135 Log.info (fun m ->
137136 m "Sending control response: %s" (json_to_string response));
138137 Transport.send t.transport response
139139- | Incoming.Control_request.Hook_callback req -> (
140140- let callback_id =
141141- Incoming.Control_request.Hook_callback.callback_id req
142142- in
143143- let input = Incoming.Control_request.Hook_callback.input req in
144144- let tool_use_id =
145145- Incoming.Control_request.Hook_callback.tool_use_id req
146146- in
138138+ | Sdk_control.Request.Hook_callback req -> (
139139+ let callback_id = req.callback_id in
140140+ let input = req.input in
141141+ let tool_use_id = req.tool_use_id in
147142 Log.info (fun m ->
148143 m "Hook callback request for callback_id: %s" callback_id);
149144···156151 Jsont.Json.encode Hooks.result_jsont result
157152 |> Err.get_ok ~msg:"Failed to encode hook result: "
158153 in
154154+ Log.debug (fun m ->
155155+ m "Hook result JSON: %s" (json_to_string result_json));
159156 let response =
160157 Control_response.success ~request_id ~response:(Some result_json)
161158 in
···176173 Log.err (fun m -> m "%s" error_msg);
177174 Transport.send t.transport
178175 (Control_response.error ~request_id ~message:error_msg))
179179- | Incoming.Control_request.Unknown (subtype, _) ->
180180- let error_msg =
181181- Printf.sprintf "Unsupported control request: %s" subtype
182182- in
176176+ | _ ->
177177+ (* Other request types not handled here *)
178178+ let error_msg = "Unsupported control request type" in
183179 Transport.send t.transport
184180 (Control_response.error ~request_id ~message:error_msg)
185181···229225 loop ()
230226 | Ok (Incoming.Control_request ctrl_req) ->
231227 Log.info (fun m ->
232232- m "Received control request: %s (request_id: %s)"
233233- (Incoming.Control_request.subtype ctrl_req)
234234- (Incoming.Control_request.request_id ctrl_req));
228228+ m "Received control request (request_id: %s)"
229229+ ctrl_req.request_id);
235230 handle_control_request t ctrl_req;
236231 loop ()
237232 | Error err ->
+74-14
lib/hooks.ml
···6565let decision_jsont : decision Jsont.t =
6666 Jsont.enum [ ("continue", Continue); ("block", Block) ]
67676868+(** Wire format for hook-specific output that includes hookEventName *)
6969+module Hook_specific_output = struct
7070+ type t = { hook_event_name : event; output : Jsont.json }
7171+7272+ let create ~event ~output = { hook_event_name = event; output }
7373+7474+ let to_json t =
7575+ (* Encode the event name *)
7676+ let event_name_json =
7777+ Jsont.Json.encode event_jsont t.hook_event_name
7878+ |> Err.get_ok ~msg:"Hook_specific_output.to_json: event_name encoding"
7979+ in
8080+ (* Merge hookEventName into the output object *)
8181+ match t.output with
8282+ | Jsont.Object (members, meta) ->
8383+ let hook_event_name_member =
8484+ (Jsont.Json.name "hookEventName", event_name_json)
8585+ in
8686+ Jsont.Object (hook_event_name_member :: members, meta)
8787+ | _ ->
8888+ (* If output is not an object, wrap it *)
8989+ Jsont.Object
9090+ ( [
9191+ ( Jsont.Json.name "hookEventName",
9292+ event_name_json );
9393+ ],
9494+ Jsont.Meta.none )
9595+end
9696+6897type result = {
6998 decision : decision option;
7099 system_message : string option;
···154183 |> Jsont.Object.finish
155184156185 let output_to_json output =
157157- match Jsont.Json.encode output_jsont output with
158158- | Ok json -> json
159159- | Error msg -> failwith ("PreToolUse.output_to_json: " ^ msg)
186186+ let inner =
187187+ Jsont.Json.encode output_jsont output
188188+ |> Err.get_ok ~msg:"PreToolUse.output_to_json: "
189189+ in
190190+ Hook_specific_output.(create ~event:Pre_tool_use ~output:inner |> to_json)
160191161192 let allow ?reason ?updated_input ?(unknown = Unknown.empty) () =
162193 {
···257288 |> Jsont.Object.finish
258289259290 let output_to_json output =
260260- match Jsont.Json.encode output_jsont output with
261261- | Ok json -> json
262262- | Error msg -> failwith ("PostToolUse.output_to_json: " ^ msg)
291291+ let inner =
292292+ Jsont.Json.encode output_jsont output
293293+ |> Err.get_ok ~msg:"PostToolUse.output_to_json: "
294294+ in
295295+ Hook_specific_output.(create ~event:Post_tool_use ~output:inner |> to_json)
263296264297 let continue ?additional_context ?(unknown = Unknown.empty) () =
265298 { decision = None; reason = None; additional_context; unknown }
···320353 |> Jsont.Object.finish
321354322355 let output_to_json output =
323323- match Jsont.Json.encode output_jsont output with
324324- | Ok json -> json
325325- | Error msg -> failwith ("UserPromptSubmit.output_to_json: " ^ msg)
356356+ let inner =
357357+ Jsont.Json.encode output_jsont output
358358+ |> Err.get_ok ~msg:"UserPromptSubmit.output_to_json: "
359359+ in
360360+ Hook_specific_output.(
361361+ create ~event:User_prompt_submit ~output:inner |> to_json)
326362327363 let continue ?additional_context ?(unknown = Unknown.empty) () =
328364 { decision = None; reason = None; additional_context; unknown }
···378414 |> Jsont.Object.finish
379415380416 let output_to_json output =
381381- match Jsont.Json.encode output_jsont output with
382382- | Ok json -> json
383383- | Error msg -> failwith ("Stop.output_to_json: " ^ msg)
417417+ let inner =
418418+ Jsont.Json.encode output_jsont output
419419+ |> Err.get_ok ~msg:"Stop.output_to_json: "
420420+ in
421421+ Hook_specific_output.(create ~event:Stop ~output:inner |> to_json)
384422385423 let continue ?(unknown = Unknown.empty) () =
386424 { decision = None; reason = None; unknown }
···391429392430(** {1 SubagentStop Hook} - Same structure as Stop *)
393431module SubagentStop = struct
394394- include Stop
432432+ type input = Stop.input
433433+ type t = input
434434+ type output = Stop.output
435435+436436+ let session_id = Stop.session_id
437437+ let transcript_path = Stop.transcript_path
438438+ let stop_hook_active = Stop.stop_hook_active
439439+ let unknown = Stop.unknown
440440+ let input_jsont = Stop.input_jsont
441441+ let of_json = Stop.of_json
442442+ let output_jsont = Stop.output_jsont
443443+ let continue = Stop.continue
444444+ let block = Stop.block
445445+446446+ let output_to_json output =
447447+ let inner =
448448+ Jsont.Json.encode output_jsont output
449449+ |> Err.get_ok ~msg:"SubagentStop.output_to_json: "
450450+ in
451451+ Hook_specific_output.(create ~event:Subagent_stop ~output:inner |> to_json)
395452end
396453397454(** {1 PreCompact Hook} *)
···425482426483 type output = unit (* No specific output for PreCompact *)
427484428428- let output_to_json () = Jsont.Object ([], Jsont.Meta.none)
485485+ let output_to_json () =
486486+ let inner = Jsont.Object ([], Jsont.Meta.none) in
487487+ Hook_specific_output.(create ~event:Pre_compact ~output:inner |> to_json)
488488+429489 let continue () = ()
430490end
431491
+12-1
lib/hooks.mli
···268268269269(** SubagentStop hook - fires when a subagent stops *)
270270module SubagentStop : sig
271271- include module type of Stop
271271+ type input = Stop.input
272272+ type t = input
273273+ type output = Stop.output
272274273275 val of_json : Jsont.json -> t
276276+ val session_id : t -> string
277277+ val transcript_path : t -> string
278278+ val stop_hook_active : t -> bool
279279+ val unknown : t -> Unknown.t
280280+ val input_jsont : input Jsont.t
281281+ val output_jsont : output Jsont.t
282282+ val continue : ?unknown:Unknown.t -> unit -> output
283283+ val block : ?reason:string -> ?unknown:Unknown.t -> unit -> output
284284+ val output_to_json : output -> Jsont.json
274285end
275286276287(** PreCompact hook - fires before message compaction *)
+55-183
lib/incoming.ml
···3344module Log = (val Logs.src_log src : Logs.LOG)
5566-(** Control request types for incoming control_request messages *)
77-module Control_request = struct
88- (** Can use tool permission request *)
99- module Can_use_tool = struct
1010- type t = {
1111- tool_name : string;
1212- input : Jsont.json;
1313- permission_suggestions : Jsont.json list;
1414- }
1515-1616- let tool_name t = t.tool_name
1717- let input t = t.input
1818- let permission_suggestions t = t.permission_suggestions
1919-2020- let jsont : t Jsont.t =
2121- let make tool_name input permission_suggestions =
2222- {
2323- tool_name;
2424- input;
2525- permission_suggestions =
2626- Option.value permission_suggestions ~default:[];
2727- }
2828- in
2929- Jsont.Object.map ~kind:"CanUseTool" make
3030- |> Jsont.Object.mem "tool_name" Jsont.string ~enc:tool_name
3131- |> Jsont.Object.mem "input" Jsont.json ~enc:input
3232- |> Jsont.Object.opt_mem "permission_suggestions" (Jsont.list Jsont.json)
3333- ~enc:(fun t ->
3434- if t.permission_suggestions = [] then None
3535- else Some t.permission_suggestions)
3636- |> Jsont.Object.finish
3737- end
3838-3939- (** Hook callback request *)
4040- module Hook_callback = struct
4141- type t = {
4242- callback_id : string;
4343- input : Jsont.json;
4444- tool_use_id : string option;
4545- }
4646-4747- let callback_id t = t.callback_id
4848- let input t = t.input
4949- let tool_use_id t = t.tool_use_id
5050-5151- let jsont : t Jsont.t =
5252- let make callback_id input tool_use_id =
5353- { callback_id; input; tool_use_id }
5454- in
5555- Jsont.Object.map ~kind:"HookCallback" make
5656- |> Jsont.Object.mem "callback_id" Jsont.string ~enc:callback_id
5757- |> Jsont.Object.mem "input" Jsont.json ~enc:input
5858- |> Jsont.Object.opt_mem "tool_use_id" Jsont.string ~enc:tool_use_id
5959- |> Jsont.Object.finish
6060- end
66+(** Incoming messages from Claude CLI.
6176262- (** Request payload - discriminated by subtype *)
6363- type request =
6464- | Can_use_tool of Can_use_tool.t
6565- | Hook_callback of Hook_callback.t
6666- | Unknown of string * Jsont.json
6767-6868- let request_of_json json =
6969- let subtype_codec =
7070- Jsont.Object.map ~kind:"Subtype" Fun.id
7171- |> Jsont.Object.mem "subtype" Jsont.string ~enc:Fun.id
7272- |> Jsont.Object.finish
7373- in
7474- match Jsont.Json.decode subtype_codec json with
7575- | Error _ -> Unknown ("unknown", json)
7676- | Ok subtype -> (
7777- match subtype with
7878- | "can_use_tool" -> (
7979- match Jsont.Json.decode Can_use_tool.jsont json with
8080- | Ok r -> Can_use_tool r
8181- | Error _ -> Unknown (subtype, json))
8282- | "hook_callback" -> (
8383- match Jsont.Json.decode Hook_callback.jsont json with
8484- | Ok r -> Hook_callback r
8585- | Error _ -> Unknown (subtype, json))
8686- | _ -> Unknown (subtype, json))
8787-8888- type t = { request_id : string; request : request }
8989- (** Full control request message *)
9090-9191- let request_id t = t.request_id
9292- let request t = t.request
9393-9494- let subtype t =
9595- match t.request with
9696- | Can_use_tool _ -> "can_use_tool"
9797- | Hook_callback _ -> "hook_callback"
9898- | Unknown (s, _) -> s
9999-100100- let jsont : t Jsont.t =
101101- let dec json =
102102- let envelope_codec =
103103- Jsont.Object.map ~kind:"ControlRequestEnvelope"
104104- (fun request_id request_json -> (request_id, request_json))
105105- |> Jsont.Object.mem "request_id" Jsont.string ~enc:fst
106106- |> Jsont.Object.mem "request" Jsont.json ~enc:snd
107107- |> Jsont.Object.finish
108108- in
109109- match Jsont.Json.decode envelope_codec json with
110110- | Error err ->
111111- failwith ("Failed to decode control_request envelope: " ^ err)
112112- | Ok (request_id, request_json) ->
113113- { request_id; request = request_of_json request_json }
114114- in
115115- let enc t =
116116- let request_json =
117117- match t.request with
118118- | Can_use_tool r -> (
119119- match Jsont.Json.encode Can_use_tool.jsont r with
120120- | Ok j -> j
121121- | Error err -> failwith ("Failed to encode Can_use_tool: " ^ err))
122122- | Hook_callback r -> (
123123- match Jsont.Json.encode Hook_callback.jsont r with
124124- | Ok j -> j
125125- | Error err -> failwith ("Failed to encode Hook_callback: " ^ err))
126126- | Unknown (_, j) -> j
127127- in
128128- Jsont.Json.object'
129129- [
130130- Jsont.Json.mem (Jsont.Json.name "type")
131131- (Jsont.Json.string "control_request");
132132- Jsont.Json.mem
133133- (Jsont.Json.name "request_id")
134134- (Jsont.Json.string t.request_id);
135135- Jsont.Json.mem (Jsont.Json.name "request") request_json;
136136- ]
137137- in
138138- Jsont.map ~kind:"ControlRequest" ~dec ~enc Jsont.json
139139-end
88+ This uses the Sdk_control module's control_request_jsont and
99+ control_response_jsont for control messages, and Message.jsont for
1010+ conversation messages. The top-level discriminator is the "type" field. *)
1401114112type t =
14213 | Message of Message.t
14314 | Control_response of Sdk_control.control_response
144144- | Control_request of Control_request.t
1515+ | Control_request of Sdk_control.control_request
1451614617let jsont : t Jsont.t =
147147- (* Custom decoder that checks the type field and dispatches to the appropriate codec.
1818+ (* Message types use "user", "assistant", "system", "result" as type values.
1919+ Control uses "control_request" and "control_response".
14820149149- The challenge is that Message can have multiple type values ("user", "assistant",
150150- "system", "result"), while control_response and control_request have single type values.
151151- Jsont's case_mem discriminator doesn't support multiple tags per case, so we implement
152152- a custom decoder/encoder. *)
153153- let type_field_codec =
154154- Jsont.Object.map ~kind:"type_field" Fun.id
155155- |> Jsont.Object.opt_mem "type" Jsont.string ~enc:Fun.id
156156- |> Jsont.Object.finish
2121+ We use case_mem for all types. Note: we use the inner message codecs
2222+ (User.incoming_jsont, etc.) rather than Message.jsont to avoid nesting
2323+ case_mem on the same "type" field. *)
2424+ let case_control_request =
2525+ Jsont.Object.Case.map "control_request" Sdk_control.control_request_jsont
2626+ ~dec:(fun v -> Control_request v)
2727+ in
2828+ let case_control_response =
2929+ Jsont.Object.Case.map "control_response" Sdk_control.control_response_jsont
3030+ ~dec:(fun v -> Control_response v)
15731 in
158158-159159- let dec json =
160160- match Jsont.Json.decode type_field_codec json with
161161- | Error _ | Ok None -> (
162162- (* No type field, try as message *)
163163- match Jsont.Json.decode Message.jsont json with
164164- | Ok msg -> Message msg
165165- | Error err -> failwith ("Failed to decode message: " ^ err))
166166- | Ok (Some typ) -> (
167167- match typ with
168168- | "control_response" -> (
169169- match Jsont.Json.decode Sdk_control.control_response_jsont json with
170170- | Ok resp -> Control_response resp
171171- | Error err -> failwith ("Failed to decode control_response: " ^ err)
172172- )
173173- | "control_request" -> (
174174- match Jsont.Json.decode Control_request.jsont json with
175175- | Ok req -> Control_request req
176176- | Error err -> failwith ("Failed to decode control_request: " ^ err)
177177- )
178178- | "user" | "assistant" | "system" | "result" | _ -> (
179179- (* Message types *)
180180- match Jsont.Json.decode Message.jsont json with
181181- | Ok msg -> Message msg
182182- | Error err -> failwith ("Failed to decode message: " ^ err)))
3232+ let case_user =
3333+ Jsont.Object.Case.map "user" Message.User.incoming_jsont
3434+ ~dec:(fun v -> Message (Message.User v))
3535+ in
3636+ let case_assistant =
3737+ Jsont.Object.Case.map "assistant" Message.Assistant.incoming_jsont
3838+ ~dec:(fun v -> Message (Message.Assistant v))
3939+ in
4040+ let case_system =
4141+ Jsont.Object.Case.map "system" Message.System.jsont
4242+ ~dec:(fun v -> Message (Message.System v))
4343+ in
4444+ let case_result =
4545+ Jsont.Object.Case.map "result" Message.Result.jsont
4646+ ~dec:(fun v -> Message (Message.Result v))
18347 in
184184-185185- let enc = function
4848+ let enc_case = function
4949+ | Control_request v -> Jsont.Object.Case.value case_control_request v
5050+ | Control_response v -> Jsont.Object.Case.value case_control_response v
18651 | Message msg -> (
187187- match Jsont.Json.encode Message.jsont msg with
188188- | Ok json -> json
189189- | Error err -> failwith ("Failed to encode message: " ^ err))
190190- | Control_response resp -> (
191191- match Jsont.Json.encode Sdk_control.control_response_jsont resp with
192192- | Ok json -> json
193193- | Error err -> failwith ("Failed to encode control response: " ^ err))
194194- | Control_request req -> (
195195- match Jsont.Json.encode Control_request.jsont req with
196196- | Ok json -> json
197197- | Error err -> failwith ("Failed to encode control request: " ^ err))
5252+ match msg with
5353+ | Message.User u -> Jsont.Object.Case.value case_user u
5454+ | Message.Assistant a -> Jsont.Object.Case.value case_assistant a
5555+ | Message.System s -> Jsont.Object.Case.value case_system s
5656+ | Message.Result r -> Jsont.Object.Case.value case_result r)
5757+ in
5858+ let cases =
5959+ Jsont.Object.Case.
6060+ [
6161+ make case_control_request;
6262+ make case_control_response;
6363+ make case_user;
6464+ make case_assistant;
6565+ make case_system;
6666+ make case_result;
6767+ ]
19868 in
199199-200200- Jsont.map ~kind:"Incoming" ~dec ~enc Jsont.json
6969+ Jsont.Object.map ~kind:"Incoming" Fun.id
7070+ |> Jsont.Object.case_mem "type" Jsont.string ~enc:Fun.id ~enc_case cases
7171+ ~tag_to_string:Fun.id ~tag_compare:String.compare
7272+ |> Jsont.Object.finish
+2-39
lib/incoming.mli
···99 - "control_request" -> Control_request variant
10101111 This provides a clean, type-safe way to decode incoming messages in a single
1212- operation, avoiding the parse-then-switch-then-parse pattern. *)
1313-1414-(** Control request types for incoming control_request messages *)
1515-module Control_request : sig
1616- (** Can use tool permission request *)
1717- module Can_use_tool : sig
1818- type t
1919-2020- val tool_name : t -> string
2121- val input : t -> Jsont.json
2222- val permission_suggestions : t -> Jsont.json list
2323- val jsont : t Jsont.t
2424- end
2525-2626- (** Hook callback request *)
2727- module Hook_callback : sig
2828- type t
2929-3030- val callback_id : t -> string
3131- val input : t -> Jsont.json
3232- val tool_use_id : t -> string option
3333- val jsont : t Jsont.t
3434- end
3535-3636- (** Request payload - discriminated by subtype *)
3737- type request =
3838- | Can_use_tool of Can_use_tool.t
3939- | Hook_callback of Hook_callback.t
4040- | Unknown of string * Jsont.json
4141-4242- type t
4343- (** Full control request message *)
4444-4545- val request_id : t -> string
4646- val request : t -> request
4747- val subtype : t -> string
4848- val jsont : t Jsont.t
4949-end
1212+ operation. *)
50135114type t =
5215 | Message of Message.t
5316 | Control_response of Sdk_control.control_response
5454- | Control_request of Control_request.t
1717+ | Control_request of Sdk_control.control_request
55185619val jsont : t Jsont.t
5720(** Codec for incoming messages. Uses the "type" field to discriminate. Use
+4-26
lib/message.ml
···286286 }
287287288288 type error = { error : string; unknown : Unknown.t }
289289- type other = { subtype : string; unknown : Unknown.t }
290290- type t = Init of init | Error of error | Other of other
289289+ type t = Init of init | Error of error
291290292291 (* Accessors *)
293292 let session_id = function Init i -> i.session_id | _ -> None
294293 let model = function Init i -> i.model | _ -> None
295294 let cwd = function Init i -> i.cwd | _ -> None
296295 let error_msg = function Error e -> Some e.error | _ -> None
297297-298298- let subtype = function
299299- | Init _ -> "init"
300300- | Error _ -> "error"
301301- | Other o -> o.subtype
302302-303303- let unknown = function
304304- | Init i -> i.unknown
305305- | Error e -> e.unknown
306306- | Other o -> o.unknown
296296+ let subtype = function Init _ -> "init" | Error _ -> "error"
297297+ let unknown = function Init i -> i.unknown | Error e -> e.unknown
307298308299 (* Constructors *)
309300 let init ?session_id ?model ?cwd () =
310301 Init { session_id; model; cwd; unknown = Unknown.empty }
311302312303 let error ~error = Error { error; unknown = Unknown.empty }
313313- let other ~subtype = Other { subtype; unknown = Unknown.empty }
314304315305 (* Individual record codecs *)
316306 let init_jsont : init Jsont.t =
···343333 let case_error =
344334 Jsont.Object.Case.map "error" error_jsont ~dec:(fun v -> Error v)
345335 in
346346- let case_other tag =
347347- (* For unknown subtypes, create Other with the tag as subtype *)
348348- let other_codec : other Jsont.t =
349349- let make unknown : other = { subtype = tag; unknown } in
350350- Jsont.Object.map ~kind:"SystemOther" make
351351- |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun (r : other) ->
352352- r.unknown)
353353- |> Jsont.Object.finish
354354- in
355355- Jsont.Object.Case.map tag other_codec ~dec:(fun v -> Other v)
356356- in
357336 let enc_case = function
358337 | Init v -> Jsont.Object.Case.value case_init v
359338 | Error v -> Jsont.Object.Case.value case_error v
360360- | Other v -> Jsont.Object.Case.value (case_other v.subtype) v
361339 in
362340 let cases = Jsont.Object.Case.[ make case_init; make case_error ] in
363341 Jsont.Object.map ~kind:"System" Fun.id
···665643666644let is_error = function
667645 | Result r -> Result.is_error r
668668- | System s -> System.subtype s = "error"
646646+ | System (System.Error _) -> true
669647 | _ -> false
670648671649let extract_text = function
+10-12
lib/message.mli
···2424 val jsont : t Jsont.t
2525 (** [jsont] is the Jsont codec for user messages. *)
26262727+ val incoming_jsont : t Jsont.t
2828+ (** [incoming_jsont] is the codec for parsing incoming user messages from CLI.
2929+ This parses the envelope format with "message" wrapper. *)
3030+2731 val create_string : string -> t
2832 (** [create_string s] creates a user message with simple text content. *)
2933···9094 val jsont : t Jsont.t
9195 (** [jsont] is the Jsont codec for assistant messages. *)
92969797+ val incoming_jsont : t Jsont.t
9898+ (** [incoming_jsont] is the codec for parsing incoming assistant messages from
9999+ CLI. This parses the envelope format with "message" wrapper. *)
100100+93101 val create :
94102 content:Content_block.t list -> model:string -> ?error:error -> unit -> t
95103 (** [create ~content ~model ?error ()] creates an assistant message.
···141149142150 System messages use a discriminated union on the "subtype" field:
143151 - "init": Session initialization with session_id, model, cwd
144144- - "error": Error messages with error string
145145- - Other subtypes are preserved as [Other] *)
152152+ - "error": Error messages with error string *)
146153147154 type init = {
148155 session_id : string option;
···155162 type error = { error : string; unknown : Unknown.t }
156163 (** Error message fields. *)
157164158158- type other = { subtype : string; unknown : Unknown.t }
159159- (** Unknown subtype fields. *)
160160-161161- type t =
162162- | Init of init
163163- | Error of error
164164- | Other of other (** The type of system messages. *)
165165+ type t = Init of init | Error of error
165166166167 val jsont : t Jsont.t
167168 (** [jsont] is the Jsont codec for system messages. *)
···173174174175 val error : error:string -> t
175176 (** [error ~error] creates an error message. *)
176176-177177- val other : subtype:string -> t
178178- (** [other ~subtype] creates a message with unknown subtype. *)
179177180178 (** {2 Accessors} *)
181179
+3
lib/sdk_control.mli
···228228}
229229(** Control response message. *)
230230231231+val control_request_jsont : control_request Jsont.t
232232+(** [control_request_jsont] is the jsont codec for control request messages. *)
233233+231234val control_response_jsont : control_response Jsont.t
232235(** [control_response_jsont] is the jsont codec for control response messages.
233236*)
+3-4
test/structured_output_demo.ml
···199199 match C.Message.Result.result result with
200200 | Some text -> Printf.printf "Text result: %s\n" text
201201 | None -> ()))
202202- | C.Message.System sys -> (
203203- match C.Message.System.subtype sys with
204204- | "init" -> Printf.printf "Session initialized\n"
205205- | _ -> ())
202202+ | C.Message.System (C.Message.System.Init _) ->
203203+ Printf.printf "Session initialized\n"
204204+ | C.Message.System (C.Message.System.Error _) -> ()
206205 | _ -> ())
207206 messages;
208207