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(** Messages exchanged with Claude. Opaque types.
7
8 This module provides opaque message types that wrap the proto types but hide
9 the unknown fields and wire format details from the public API. *)
10
11val src : Logs.Src.t
12(** The log source for message operations *)
13
14(** {1 User Messages} *)
15
16module User : sig
17 (** Messages sent by the user. *)
18
19 type t
20 (** The type of user messages (opaque). *)
21
22 val of_string : string -> t
23 (** [of_string s] creates a user message with simple text content. *)
24
25 val of_blocks : Content_block.t list -> t
26 (** [of_blocks blocks] creates a user message with content blocks. *)
27
28 val with_tool_result :
29 tool_use_id:string -> content:Jsont.json -> ?is_error:bool -> unit -> t
30 (** [with_tool_result ~tool_use_id ~content ?is_error ()] creates a user
31 message containing a tool result. Content can be a string or array. *)
32
33 val as_text : t -> string option
34 (** [as_text t] returns the text content if the message is a simple string,
35 None otherwise. *)
36
37 val blocks : t -> Content_block.t list
38 (** [blocks t] returns the content blocks, or a single text block if it's a
39 string message. *)
40
41 (** {1 Internal - for lib use only} *)
42
43 val of_proto : Proto.Message.User.t -> t
44 (** [of_proto proto] wraps a proto user message. *)
45
46 val to_proto : t -> Proto.Message.User.t
47 (** [to_proto t] extracts the proto user message. *)
48
49 val incoming_jsont : t Jsont.t
50 (** Internal codec for parsing incoming messages. *)
51
52 val to_json : t -> Jsont.json
53 (** Internal conversion to JSON for wire format. *)
54end
55
56(** {1 Assistant Messages} *)
57
58module Assistant : sig
59 (** Messages from Claude assistant. *)
60
61 type error =
62 [ `Authentication_failed (** Authentication with Claude API failed *)
63 | `Billing_error (** Billing or account issue *)
64 | `Rate_limit (** Rate limit exceeded *)
65 | `Invalid_request (** Request was invalid *)
66 | `Server_error (** Internal server error *)
67 | `Unknown (** Unknown error type *) ]
68 (** The type of assistant message errors based on Python SDK error types. *)
69
70 type t
71 (** The type of assistant messages (opaque). *)
72
73 val content : t -> Content_block.t list
74 (** [content t] returns the content blocks of the assistant message. *)
75
76 val model : t -> string
77 (** [model t] returns the model identifier. *)
78
79 val error : t -> error option
80 (** [error t] returns the optional error that occurred during message
81 generation. *)
82
83 (** {2 Convenience accessors} *)
84
85 val text_blocks : t -> string list
86 (** [text_blocks t] extracts all text content from the message. *)
87
88 val tool_uses : t -> Content_block.Tool_use.t list
89 (** [tool_uses t] extracts all tool use blocks from the message. *)
90
91 val thinking_blocks : t -> Content_block.Thinking.t list
92 (** [thinking_blocks t] extracts all thinking blocks from the message. *)
93
94 val combined_text : t -> string
95 (** [combined_text t] concatenates all text blocks into a single string. *)
96
97 val has_tool_use : t -> bool
98 (** [has_tool_use t] returns true if the message contains any tool use blocks.
99 *)
100
101 (** {1 Internal - for lib use only} *)
102
103 val of_proto : Proto.Message.Assistant.t -> t
104 (** [of_proto proto] wraps a proto assistant message. *)
105
106 val to_proto : t -> Proto.Message.Assistant.t
107 (** [to_proto t] extracts the proto assistant message. *)
108
109 val incoming_jsont : t Jsont.t
110 (** Internal codec for parsing incoming messages. *)
111
112 val to_json : t -> Jsont.json
113 (** Internal conversion to JSON for wire format. *)
114end
115
116(** {1 System Messages} *)
117
118module System : sig
119 (** System control and status messages. *)
120
121 type t
122 (** The type of system messages (opaque). *)
123
124 val is_init : t -> bool
125 (** [is_init t] returns true if the message is an init message. *)
126
127 val is_error : t -> bool
128 (** [is_error t] returns true if the message is an error message. *)
129
130 val session_id : t -> string option
131 (** [session_id t] returns session_id from Init, None otherwise. *)
132
133 val model : t -> string option
134 (** [model t] returns model from Init, None otherwise. *)
135
136 val cwd : t -> string option
137 (** [cwd t] returns cwd from Init, None otherwise. *)
138
139 val error_message : t -> string option
140 (** [error_message t] returns error from Error, None otherwise. *)
141
142 (** {1 Internal - for lib use only} *)
143
144 val of_proto : Proto.Message.System.t -> t
145 (** [of_proto proto] wraps a proto system message. *)
146
147 val to_proto : t -> Proto.Message.System.t
148 (** [to_proto t] extracts the proto system message. *)
149
150 val jsont : t Jsont.t
151 (** Internal codec for wire format. *)
152
153 val to_json : t -> Jsont.json
154 (** Internal conversion to JSON for wire format. *)
155end
156
157(** {1 Result Messages} *)
158
159module Result : sig
160 (** Final result messages with metadata about the conversation. *)
161
162 module Usage : sig
163 (** Usage statistics for API calls. *)
164
165 type t
166 (** Type for usage statistics (opaque). *)
167
168 val input_tokens : t -> int option
169 (** [input_tokens t] returns the number of input tokens used. *)
170
171 val output_tokens : t -> int option
172 (** [output_tokens t] returns the number of output tokens generated. *)
173
174 val total_tokens : t -> int option
175 (** [total_tokens t] returns the total number of tokens. *)
176
177 val cache_creation_input_tokens : t -> int option
178 (** [cache_creation_input_tokens t] returns cache creation input tokens. *)
179
180 val cache_read_input_tokens : t -> int option
181 (** [cache_read_input_tokens t] returns cache read input tokens. *)
182
183 (** {1 Internal - for lib use only} *)
184
185 val of_proto : Proto.Message.Result.Usage.t -> t
186 (** [of_proto proto] wraps a proto usage object. *)
187 end
188
189 type t
190 (** The type of result messages (opaque). *)
191
192 val duration_ms : t -> int
193 (** [duration_ms t] returns the total duration in milliseconds. *)
194
195 val duration_api_ms : t -> int
196 (** [duration_api_ms t] returns the API duration in milliseconds. *)
197
198 val is_error : t -> bool
199 (** [is_error t] returns whether this result represents an error. *)
200
201 val num_turns : t -> int
202 (** [num_turns t] returns the number of conversation turns. *)
203
204 val session_id : t -> string
205 (** [session_id t] returns the session identifier. *)
206
207 val total_cost_usd : t -> float option
208 (** [total_cost_usd t] returns the optional total cost in USD. *)
209
210 val usage : t -> Usage.t option
211 (** [usage t] returns the optional usage statistics. *)
212
213 val result_text : t -> string option
214 (** [result_text t] returns the optional result string. *)
215
216 val structured_output : t -> Jsont.json option
217 (** [structured_output t] returns the optional structured JSON output. *)
218
219 (** {1 Internal - for lib use only} *)
220
221 val of_proto : Proto.Message.Result.t -> t
222 (** [of_proto proto] wraps a proto result message. *)
223
224 val to_proto : t -> Proto.Message.Result.t
225 (** [to_proto t] extracts the proto result message. *)
226
227 val jsont : t Jsont.t
228 (** Internal codec for wire format. *)
229
230 val to_json : t -> Jsont.json
231 (** Internal conversion to JSON for wire format. *)
232end
233
234(** {1 Message Union Type} *)
235
236type t =
237 | User of User.t
238 | Assistant of Assistant.t
239 | System of System.t
240 | Result of Result.t
241 (** The type of messages, which can be user, assistant, system, or result.
242 *)
243
244val of_proto : Proto.Message.t -> t
245(** [of_proto proto] converts a proto message to a lib message. *)
246
247val to_proto : t -> Proto.Message.t
248(** [to_proto t] converts a lib message to a proto message. *)
249
250(** {1 Internal - wire format conversion} *)
251
252val to_json : t -> Jsont.json
253(** [to_json t] converts any message to its JSON wire format representation. *)
254
255(** {1 Convenience Constructors} *)
256
257val user_string : string -> t
258(** [user_string s] creates a user message with text content. *)
259
260val user_blocks : Content_block.t list -> t
261(** [user_blocks blocks] creates a user message with content blocks. *)
262
263(** {1 Message Analysis} *)
264
265val is_user : t -> bool
266(** [is_user t] returns true if the message is from a user. *)
267
268val is_assistant : t -> bool
269(** [is_assistant t] returns true if the message is from the assistant. *)
270
271val is_system : t -> bool
272(** [is_system t] returns true if the message is a system message. *)
273
274val is_result : t -> bool
275(** [is_result t] returns true if the message is a result message. *)
276
277val is_error : t -> bool
278(** [is_error t] returns true if the message represents an error. *)
279
280val extract_text : t -> string option
281(** [extract_text t] attempts to extract text content from any message type. *)
282
283val extract_tool_uses : t -> Content_block.Tool_use.t list
284(** [extract_tool_uses t] extracts tool use blocks from assistant messages. *)
285
286val get_session_id : t -> string option
287(** [get_session_id t] extracts the session ID from system or result messages.
288*)
289
290(** {1 Logging} *)
291
292val pp : Format.formatter -> t -> unit
293(** [pp fmt t] pretty-prints any message. *)
294
295val log_received : t -> unit
296(** [log_received t] logs that a message was received. *)
297
298val log_sending : t -> unit
299(** [log_sending t] logs that a message is being sent. *)