My agentic slop goes here. Not intended for anyone else!

more

+8 -6
claudeio/lib/client.ml
···
(* Extract session ID from system messages *)
(match msg with
| Message.System sys when Message.System.subtype sys = "init" ->
-
(try
-
let data = Message.System.data sys in
-
let session_id = Ezjsonm.find data ["session_id"] |> Ezjsonm.get_string in
+
(match Message.System.Data.get_string (Message.System.data sys) "session_id" with
+
| Some session_id ->
t.session_id <- Some session_id;
Log.info (fun m -> m "Session ID: %s" session_id)
-
with Not_found -> ())
+
| None -> ())
| _ -> ());
Seq.Cons (msg, loop)
···
let msg = Message.user_string prompt in
Transport.send t.transport (Message.to_json msg)
-
let send_message t json =
-
Transport.send t.transport json
+
let send_message t msg =
+
Transport.send t.transport (Message.to_json msg)
+
+
let send_user_message t user_msg =
+
Transport.send t.transport (Message.User.to_json user_msg)
let receive t =
handle_messages t
+2 -1
claudeio/lib/client.mli
···
unit -> t
val query : t -> string -> unit
-
val send_message : t -> Ezjsonm.value -> unit
+
val send_message : t -> Message.t -> unit
+
val send_user_message : t -> Message.User.t -> unit
val receive : t -> Message.t Seq.t
val receive_all : t -> Message.t list
+49 -4
claudeio/lib/content_block.ml
···
end
module Tool_use = struct
+
module Input = struct
+
type t = value
+
+
let of_string_pairs pairs =
+
`O (List.map (fun (k, v) -> (k, `String v)) pairs)
+
+
let of_assoc assoc = `O assoc
+
+
let get_string t key =
+
match t with
+
| `O fields ->
+
(try Some (get_string (List.assoc key fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let get_int t key =
+
match t with
+
| `O fields ->
+
(try Some (get_int (List.assoc key fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let get_bool t key =
+
match t with
+
| `O fields ->
+
(try Some (get_bool (List.assoc key fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let get_float t key =
+
match t with
+
| `O fields ->
+
(try Some (get_float (List.assoc key fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let keys t =
+
match t with
+
| `O fields -> List.map fst fields
+
| _ -> []
+
+
let to_json t = t
+
let of_json json = json
+
end
+
type t = {
id : string;
name : string;
-
input : value;
+
input : Input.t;
}
let create ~id ~name ~input = { id; name; input }
···
("type", `String "tool_use");
("id", `String t.id);
("name", `String t.name);
-
("input", t.input);
+
("input", Input.to_json t.input);
]
let of_json = function
| `O fields ->
let id = get_string (List.assoc "id" fields) in
let name = get_string (List.assoc "name" fields) in
-
let input = List.assoc "input" fields in
+
let input = Input.of_json (List.assoc "input" fields) in
{ id; name; input }
| _ -> raise (Invalid_argument "Tool_use.of_json: expected object")
let pp fmt t =
Fmt.pf fmt "@[<2>Tool_use@ { id = %S;@ name = %S;@ input = %a }@]"
-
t.id t.name pp_json t.input
+
t.id t.name pp_json (Input.to_json t.input)
end
module Tool_result = struct
+49 -17
claudeio/lib/content_block.mli
···
This module defines the various types of content blocks that can appear
in Claude messages, including text, tool use, tool results, and thinking blocks. *)
-
open Ezjsonm
-
(** The log source for content block operations *)
val src : Logs.Src.t
···
val text : t -> string
(** [text t] returns the text content of the block. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the text block to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a text block from JSON.
@raise Invalid_argument if the JSON is not a valid text block. *)
···
module Tool_use : sig
(** Tool invocation requests from the assistant. *)
+
module Input : sig
+
(** Tool input parameters. *)
+
+
type t
+
(** Abstract type for tool inputs. *)
+
+
val of_string_pairs : (string * string) list -> t
+
(** [of_string_pairs pairs] creates tool input from string key-value pairs. *)
+
+
val of_assoc : (string * Ezjsonm.value) list -> t
+
(** [of_assoc assoc] creates tool input from an association list. *)
+
+
val get_string : t -> string -> string option
+
(** [get_string t key] returns the string value for [key], if present. *)
+
+
val get_int : t -> string -> int option
+
(** [get_int t key] returns the integer value for [key], if present. *)
+
+
val get_bool : t -> string -> bool option
+
(** [get_bool t key] returns the boolean value for [key], if present. *)
+
+
val get_float : t -> string -> float option
+
(** [get_float t key] returns the float value for [key], if present. *)
+
+
val keys : t -> string list
+
(** [keys t] returns all keys in the input. *)
+
+
val to_json : t -> Ezjsonm.value
+
(** [to_json t] converts to JSON representation. Internal use only. *)
+
+
val of_json : Ezjsonm.value -> t
+
(** [of_json json] parses from JSON. Internal use only. *)
+
end
+
type t
(** The type of tool use blocks. *)
-
val create : id:string -> name:string -> input:value -> t
+
val create : id:string -> name:string -> input:Input.t -> t
(** [create ~id ~name ~input] creates a new tool use block.
@param id Unique identifier for this tool invocation
@param name Name of the tool to invoke
-
@param input JSON parameters for the tool *)
+
@param input Parameters for the tool *)
val id : t -> string
(** [id t] returns the unique identifier of the tool use. *)
···
val name : t -> string
(** [name t] returns the name of the tool being invoked. *)
-
val input : t -> value
-
(** [input t] returns the JSON input parameters for the tool. *)
+
val input : t -> Input.t
+
(** [input t] returns the input parameters for the tool. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the tool use block to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a tool use block from JSON.
@raise Invalid_argument if the JSON is not a valid tool use block. *)
···
val is_error : t -> bool option
(** [is_error t] returns whether this result represents an error. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the tool result block to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a tool result block from JSON.
@raise Invalid_argument if the JSON is not a valid tool result block. *)
···
val signature : t -> string
(** [signature t] returns the cryptographic signature. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the thinking block to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a thinking block from JSON.
@raise Invalid_argument if the JSON is not a valid thinking block. *)
···
val text : string -> t
(** [text s] creates a text content block. *)
-
val tool_use : id:string -> name:string -> input:value -> t
+
val tool_use : id:string -> name:string -> input:Tool_use.Input.t -> t
(** [tool_use ~id ~name ~input] creates a tool use content block. *)
val tool_result : tool_use_id:string -> ?content:string -> ?is_error:bool -> unit -> t
···
val thinking : thinking:string -> signature:string -> t
(** [thinking ~thinking ~signature] creates a thinking content block. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts any content block to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a content block from JSON.
@raise Invalid_argument if the JSON is not a valid content block. *)
+82 -8
claudeio/lib/message.ml
···
end
module System = struct
+
module Data = struct
+
type t = value
+
+
let empty = `O []
+
+
let of_assoc assoc = `O assoc
+
+
let get_string t key =
+
match t with
+
| `O fields ->
+
(try Some (get_string (List.assoc key fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let get_int t key =
+
match t with
+
| `O fields ->
+
(try Some (get_int (List.assoc key fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let get_bool t key =
+
match t with
+
| `O fields ->
+
(try Some (get_bool (List.assoc key fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let to_json t = t
+
let of_json json = json
+
end
+
type t = {
subtype : string;
-
data : value;
+
data : Data.t;
}
let create ~subtype ~data = { subtype; data }
···
`O [
("type", `String "system");
("subtype", `String t.subtype);
-
("data", t.data);
+
("data", Data.to_json t.data);
]
let of_json = function
| `O fields ->
let subtype = get_string (List.assoc "subtype" fields) in
-
let data = try List.assoc "data" fields with Not_found -> `O fields in
+
let data = Data.of_json (try List.assoc "data" fields with Not_found -> `O fields) in
{ subtype; data }
| _ -> raise (Invalid_argument "System.of_json: expected object")
let pp fmt t =
Fmt.pf fmt "@[<2>System@ { subtype = %S;@ data = %a }@]"
t.subtype
-
pp_json t.data
+
pp_json (Data.to_json t.data)
end
module Result = struct
+
module Usage = struct
+
type t = value
+
+
let input_tokens t =
+
match t with
+
| `O fields ->
+
(try Some (get_int (List.assoc "input_tokens" fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let output_tokens t =
+
match t with
+
| `O fields ->
+
(try Some (get_int (List.assoc "output_tokens" fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let total_tokens t =
+
match t with
+
| `O fields ->
+
(try Some (get_int (List.assoc "total_tokens" fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let cache_creation_input_tokens t =
+
match t with
+
| `O fields ->
+
(try Some (get_int (List.assoc "cache_creation_input_tokens" fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let cache_read_input_tokens t =
+
match t with
+
| `O fields ->
+
(try Some (get_int (List.assoc "cache_read_input_tokens" fields))
+
with Not_found | _ -> None)
+
| _ -> None
+
+
let to_json t = t
+
let of_json json = json
+
end
+
type t = {
subtype : string;
duration_ms : int;
···
num_turns : int;
session_id : string;
total_cost_usd : float option;
-
usage : value option;
+
usage : Usage.t option;
result : string option;
}
···
| None -> fields
in
let fields = match t.usage with
-
| Some usage -> ("usage", usage) :: fields
+
| Some usage -> ("usage", Usage.to_json usage) :: fields
| None -> fields
in
let fields = match t.result with
···
try Some (get_float (List.assoc "total_cost_usd" fields))
with Not_found -> None
in
-
let usage = List.assoc_opt "usage" fields in
+
let usage = Option.map Usage.of_json (List.assoc_opt "usage" fields) in
let result =
try Some (get_string (List.assoc "result" fields))
with Not_found -> None
···
t.subtype t.duration_ms t.duration_api_ms t.is_error t.num_turns
t.session_id
Fmt.(option float) t.total_cost_usd
-
Fmt.(option pp_json) t.usage
+
Fmt.(option (fun fmt u -> pp_json fmt (Usage.to_json u))) t.usage
Fmt.(option string) t.result
end
+73 -19
claudeio/lib/message.mli
···
received from Claude, including user input, assistant responses, system
messages, and result metadata. *)
-
open Ezjsonm
-
(** The log source for message operations *)
val src : Logs.Src.t
···
val content : t -> content
(** [content t] returns the content of the user message. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the user message to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a user message from JSON.
@raise Invalid_argument if the JSON is not a valid user message. *)
···
val model : t -> string
(** [model t] returns the model identifier. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the assistant message to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses an assistant message from JSON.
@raise Invalid_argument if the JSON is not a valid assistant message. *)
···
module System : sig
(** System control and status messages. *)
+
module Data : sig
+
(** System message data. *)
+
+
type t
+
(** Abstract type for system message data. *)
+
+
val empty : t
+
(** [empty] creates empty data. *)
+
+
val of_assoc : (string * Ezjsonm.value) list -> t
+
(** [of_assoc assoc] creates data from an association list. *)
+
+
val get_string : t -> string -> string option
+
(** [get_string t key] returns the string value for [key], if present. *)
+
+
val get_int : t -> string -> int option
+
(** [get_int t key] returns the integer value for [key], if present. *)
+
+
val get_bool : t -> string -> bool option
+
(** [get_bool t key] returns the boolean value for [key], if present. *)
+
+
val to_json : t -> Ezjsonm.value
+
(** [to_json t] converts to JSON representation. Internal use only. *)
+
+
val of_json : Ezjsonm.value -> t
+
(** [of_json json] parses from JSON. Internal use only. *)
+
end
+
type t
(** The type of system messages. *)
-
val create : subtype:string -> data:value -> t
+
val create : subtype:string -> data:Data.t -> t
(** [create ~subtype ~data] creates a system message.
@param subtype The subtype of the system message
-
@param data Additional JSON data for the message *)
+
@param data Additional data for the message *)
val subtype : t -> string
(** [subtype t] returns the subtype of the system message. *)
-
val data : t -> value
+
val data : t -> Data.t
(** [data t] returns the additional data of the system message. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the system message to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a system message from JSON.
@raise Invalid_argument if the JSON is not a valid system message. *)
···
module Result : sig
(** Final result messages with metadata about the conversation. *)
+
module Usage : sig
+
(** Usage statistics for API calls. *)
+
+
type t
+
(** Abstract type for usage statistics. *)
+
+
val input_tokens : t -> int option
+
(** [input_tokens t] returns the number of input tokens used. *)
+
+
val output_tokens : t -> int option
+
(** [output_tokens t] returns the number of output tokens generated. *)
+
+
val total_tokens : t -> int option
+
(** [total_tokens t] returns the total number of tokens. *)
+
+
val cache_creation_input_tokens : t -> int option
+
(** [cache_creation_input_tokens t] returns cache creation input tokens. *)
+
+
val cache_read_input_tokens : t -> int option
+
(** [cache_read_input_tokens t] returns cache read input tokens. *)
+
+
val to_json : t -> Ezjsonm.value
+
(** [to_json t] converts to JSON representation. Internal use only. *)
+
+
val of_json : Ezjsonm.value -> t
+
(** [of_json json] parses from JSON. Internal use only. *)
+
end
+
type t
(** The type of result messages. *)
···
num_turns:int ->
session_id:string ->
?total_cost_usd:float ->
-
?usage:value ->
+
?usage:Usage.t ->
?result:string ->
unit -> t
(** [create ~subtype ~duration_ms ~duration_api_ms ~is_error ~num_turns
···
val total_cost_usd : t -> float option
(** [total_cost_usd t] returns the optional total cost in USD. *)
-
val usage : t -> value option
+
val usage : t -> Usage.t option
(** [usage t] returns the optional usage statistics. *)
val result : t -> string option
(** [result t] returns the optional result string. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts the result message to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a result message from JSON.
@raise Invalid_argument if the JSON is not a valid result message. *)
···
val assistant : content:Content_block.t list -> model:string -> t
(** [assistant ~content ~model] creates an assistant message. *)
-
val system : subtype:string -> data:value -> t
+
val system : subtype:string -> data:System.Data.t -> t
(** [system ~subtype ~data] creates a system message. *)
val result :
···
num_turns:int ->
session_id:string ->
?total_cost_usd:float ->
-
?usage:value ->
+
?usage:Result.Usage.t ->
?result:string ->
unit -> t
(** [result ~subtype ~duration_ms ~duration_api_ms ~is_error ~num_turns
~session_id ?total_cost_usd ?usage ?result ()] creates a result message. *)
-
val to_json : t -> value
+
val to_json : t -> Ezjsonm.value
(** [to_json t] converts any message to its JSON representation. *)
-
val of_json : value -> t
+
val of_json : Ezjsonm.value -> t
(** [of_json json] parses a message from JSON.
@raise Invalid_argument if the JSON is not a valid message. *)