My agentic slop goes here. Not intended for anyone else!
at main 7.6 kB view raw
1(** Client interface for interacting with Claude. 2 3 This module provides the high-level client API for sending messages to 4 Claude and receiving responses. It handles the bidirectional streaming 5 protocol, permission callbacks, and hooks. 6 7 {2 Basic Usage} 8 9 {[ 10 Eio.Switch.run @@ fun sw -> 11 let client = Client.create ~sw ~process_mgr () in 12 Client.query client "What is 2+2?"; 13 14 let messages = Client.receive_all client in 15 List.iter (function 16 | Message.Assistant msg -> 17 Printf.printf "Claude: %s\n" (Message.Assistant.text msg) 18 | _ -> () 19 ) messages 20 ]} 21 22 {2 Features} 23 24 - {b Message Streaming}: Messages are streamed lazily via {!Seq.t} 25 - {b Permission Control}: Custom permission callbacks for tool usage 26 - {b Hooks}: Intercept and modify tool execution 27 - {b Dynamic Control}: Change settings mid-conversation 28 - {b Resource Management}: Automatic cleanup via Eio switches 29 30 {2 Message Flow} 31 32 1. Create a client with {!create} 33 2. Send messages with {!query} or {!send_message} 34 3. Receive responses with {!receive} or {!receive_all} 35 4. Continue multi-turn conversations by sending more messages 36 5. Client automatically cleans up when the switch exits 37 38 {2 Advanced Features} 39 40 - Permission discovery mode for understanding required permissions 41 - Mid-conversation model switching and permission mode changes 42 - Server capability introspection *) 43 44(** The log source for client operations *) 45val src : Logs.Src.t 46 47type t 48(** The type of Claude clients. *) 49 50val create : 51 ?options:Options.t -> 52 sw:Eio.Switch.t -> 53 process_mgr:_ Eio.Process.mgr -> 54 unit -> t 55(** [create ?options ~sw ~process_mgr ()] creates a new Claude client. 56 57 @param options Configuration options (defaults to {!Options.default}) 58 @param sw Eio switch for resource management 59 @param process_mgr Eio process manager for spawning the Claude CLI *) 60 61val query : t -> string -> unit 62(** [query t prompt] sends a text message to Claude. 63 64 This is a convenience function for simple string messages. For more 65 complex messages with tool results or multiple content blocks, use 66 {!send_message} instead. *) 67 68val send_message : t -> Message.t -> unit 69(** [send_message t msg] sends a message to Claude. 70 71 Supports all message types including user messages with tool results. *) 72 73val send_user_message : t -> Message.User.t -> unit 74(** [send_user_message t msg] sends a user message to Claude. *) 75 76val receive : t -> Message.t Seq.t 77(** [receive t] returns a lazy sequence of messages from Claude. 78 79 The sequence yields messages as they arrive from Claude, including: 80 - {!constructor:Message.Assistant} - Claude's responses 81 - {!constructor:Message.System} - System notifications 82 - {!constructor:Message.Result} - Final result with usage statistics 83 84 Control messages (permission requests, hook callbacks) are handled 85 internally and not yielded to the sequence. *) 86 87val receive_all : t -> Message.t list 88(** [receive_all t] collects all messages into a list. 89 90 This is a convenience function that consumes the {!receive} sequence. 91 Use this when you want to process all messages at once rather than 92 streaming them. *) 93 94val interrupt : t -> unit 95(** [interrupt t] sends an interrupt signal to stop Claude's execution. *) 96 97val discover_permissions : t -> t 98(** [discover_permissions t] enables permission discovery mode. 99 100 In discovery mode, all tool usage is logged but allowed. Use 101 {!get_discovered_permissions} to retrieve the list of permissions 102 that were requested during execution. 103 104 This is useful for understanding what permissions your prompt requires. *) 105 106val get_discovered_permissions : t -> Permissions.Rule.t list 107(** [get_discovered_permissions t] returns permissions discovered during execution. 108 109 Only useful after enabling {!discover_permissions}. *) 110 111val with_permission_callback : t -> Permissions.callback -> t 112(** [with_permission_callback t callback] updates the permission callback. 113 114 Allows dynamically changing the permission callback without recreating 115 the client. *) 116 117(** {1 Dynamic Control Methods} 118 119 These methods allow you to change Claude's behavior mid-conversation 120 without recreating the client. This is useful for: 121 122 - Adjusting permission strictness based on user feedback 123 - Switching to faster/cheaper models for simple tasks 124 - Adapting to changing requirements during long conversations 125 - Introspecting server capabilities 126 127 {2 Example: Adaptive Permission Control} 128 129 {[ 130 (* Start with strict permissions *) 131 let client = Client.create ~sw ~process_mgr 132 ~options:(Options.default 133 |> Options.with_permission_mode Permissions.Mode.Default) () 134 in 135 136 Client.query client "Analyze this code"; 137 let _ = Client.receive_all client in 138 139 (* User approves, switch to auto-accept edits *) 140 Client.set_permission_mode client Permissions.Mode.Accept_edits; 141 142 Client.query client "Now refactor it"; 143 let _ = Client.receive_all client in 144 ]} 145 146 {2 Example: Model Switching for Efficiency} 147 148 {[ 149 (* Use powerful model for complex analysis *) 150 let client = Client.create ~sw ~process_mgr 151 ~options:(Options.default |> Options.with_model "claude-sonnet-4-5") () 152 in 153 154 Client.query client "Design a new architecture for this system"; 155 let _ = Client.receive_all client in 156 157 (* Switch to faster model for simple tasks *) 158 Client.set_model client "claude-haiku-4"; 159 160 Client.query client "Now write a README"; 161 let _ = Client.receive_all client in 162 ]} 163 164 {2 Example: Server Introspection} 165 166 {[ 167 let info = Client.get_server_info client in 168 Printf.printf "Claude CLI version: %s\n" 169 (Sdk_control.Server_info.version info); 170 Printf.printf "Capabilities: %s\n" 171 (String.concat ", " (Sdk_control.Server_info.capabilities info)); 172 ]} *) 173 174val set_permission_mode : t -> Permissions.Mode.t -> unit 175(** [set_permission_mode t mode] changes the permission mode mid-conversation. 176 177 This allows switching between permission modes without recreating the client: 178 - {!Permissions.Mode.Default} - Prompt for all permissions 179 - {!Permissions.Mode.Accept_edits} - Auto-accept file edits 180 - {!Permissions.Mode.Plan} - Planning mode with restricted execution 181 - {!Permissions.Mode.Bypass_permissions} - Skip all permission checks 182 183 @raise Failure if the server returns an error *) 184 185val set_model : t -> Model.t -> unit 186(** [set_model t model] switches to a different AI model mid-conversation. 187 188 Common models: 189 - [`Sonnet_4_5] - Most capable, balanced performance 190 - [`Opus_4] - Maximum capability for complex tasks 191 - [`Haiku_4] - Fast and cost-effective 192 193 @raise Failure if the model is invalid or unavailable *) 194 195val set_model_string : t -> string -> unit 196(** [set_model_string t model] switches to a different AI model using a string. 197 198 This is a convenience function that parses the string using {!Model.of_string}. 199 200 @raise Failure if the model is invalid or unavailable *) 201 202val get_server_info : t -> Sdk_control.Server_info.t 203(** [get_server_info t] retrieves server capabilities and metadata. 204 205 Returns information about: 206 - Server version string 207 - Available capabilities 208 - Supported commands 209 - Available output styles 210 211 Useful for feature detection and debugging. 212 213 @raise Failure if the server returns an error *)