Something went wrong. Try again.
Provider-neutral LLM requests, transcripts and responses, I/O-free
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475(*--------------------------------------------------------------------------- Copyright (c) 2026 Thomas Gazagnaire. All rights reserved. SPDX-License-Identifier: ISC ---------------------------------------------------------------------------*)
let ( let* ) = Result.bind
let system_prompt instructions = String.concat "\n\n" [ String.trim instructions; "You receive one section of a Markdown document: its heading line, then \ its body. Reply with the rewritten body alone: no heading, no preamble, \ no commentary, and no fence around the whole reply. Copy every fenced \ code block byte for byte. Add no heading."; ]
let error_message e = match Llm.Error.status e with | Some s -> Fmt.str "HTTP %d: %s" s (Llm.Error.message e) | None -> Llm.Error.message e
let invalid f = match f () with v -> Ok v | exception Invalid_argument e -> Error e
let request ~model ~system (s : Section.t) = let* sys = invalid (fun () -> Llm.Message.system system) in let* prelude = Result.map_error Llm.Request.Error.message (Llm.Request.Prelude.v [ sys ]) in let* user = invalid (fun () -> Llm.Message.user_text (s.heading ^ "\n" ^ s.body)) in let* transcript = Result.map_error Llm.Transcript.Error.message (Llm.Transcript.of_list [ user ]) in Result.map_error Llm.Request.Error.message (Llm.Request.v ~model ~prelude transcript)
let run ?on_event ~client ~model ~instructions ~sections doc = let t = Section.of_string doc in let* found = List.fold_left (fun acc name -> let* acc = acc in let* s = Section.get t name in Ok (s :: acc)) (Ok []) sections in let system = system_prompt instructions in let* edits, usage = List.fold_left (fun acc s -> let* edits, usage = acc in let* req = request ~model ~system s in let* r = Result.map_error (fun e -> Fmt.str "section %S: %s" s.Section.heading (error_message e)) (Llm.Client.response ?on_event client req) in let usage = match Llm.Response.usage r with | Some u -> Llm.Usage.add usage u | None -> usage in let body = Section.body_of_reply s (Llm.Response.text r) in Ok ((s, body) :: edits, usage)) (Ok ([], Llm.Usage.zero)) (List.rev found) in let* doc = Section.replace t (List.rev edits) in Ok (doc, usage)