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

more

Changed files
+54 -142
stack
zulip
lib
zulip
zulip_bot
+16 -19
stack/zulip/lib/zulip/lib/event_queue.ml
···
module Events_response = struct
type t = { events : Event.t list }
-
(* Custom codec that handles Event.t which has its own of_json *)
let codec =
-
let kind = "EventsResponse" in
-
let of_string s =
-
match Jsont_bytesrw.decode_string' Jsont.json s with
-
| Error e -> Error (Jsont.Error.to_string e)
-
| Ok (Jsont.Object (fields, _)) ->
+
(* Use keep_unknown pattern to handle the whole object and extract events manually *)
+
let make raw_json =
+
match raw_json with
+
| Jsont.Object (fields, _) ->
let assoc = List.map (fun ((k, _), v) -> (k, v)) fields in
(match List.assoc_opt "events" assoc with
-
| Some (Jsont.Array (event_list, _)) ->
-
let events = List.fold_left (fun acc event_json ->
-
match Event.of_json event_json with
+
| Some (Jsont.Array (items, _)) ->
+
(* Parse each event, skipping failures *)
+
let events = List.fold_left (fun acc item ->
+
match Event.of_json item with
| Ok event -> event :: acc
| Error _ -> acc
-
) [] event_list in
-
Ok { events = List.rev events }
-
| None -> Ok { events = [] }
-
| _ -> Error "events field is not an array")
-
| Ok _ -> Error "Expected JSON object"
+
) [] items |> List.rev in
+
{ events }
+
| Some _ -> { events = [] }
+
| None -> { events = [] })
+
| _ -> { events = [] }
in
-
let enc _t =
-
(* Not used for responses, but required by codec *)
-
Fmt.str "{\"events\": []}"
-
in
-
Jsont.of_of_string ~kind of_string ~enc
+
Jsont.Object.map ~kind:"EventsResponse" make
+
|> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun _ -> Jsont.Object ([], Jsont.Meta.none))
+
|> Jsont.Object.finish
end
let get_events t client ?last_event_id () =
+38 -123
stack/zulip/lib/zulip_bot/lib/message.ml
···
(* Jsont codec for User - handles both user_id and id fields *)
let jsont : t Jsont.t =
-
let of_string s =
-
match Jsont_bytesrw.decode_string' Jsont.json s with
-
| Error _ -> Error "Failed to decode JSON"
-
| Ok json ->
-
match json with
-
| Jsont.Object (fields, _) ->
-
let assoc = List.map (fun ((k, _), v) -> (k, v)) fields in
-
let user_id =
-
match List.assoc_opt "user_id" assoc with
-
| Some (Jsont.Number (f, _)) -> Some (int_of_float f)
-
| _ ->
-
match List.assoc_opt "id" assoc with
-
| Some (Jsont.Number (f, _)) -> Some (int_of_float f)
-
| _ -> None
-
in
-
let email =
-
match List.assoc_opt "email" assoc with
-
| Some (Jsont.String (s, _)) -> Some s
-
| _ -> None
-
in
-
let full_name =
-
match List.assoc_opt "full_name" assoc with
-
| Some (Jsont.String (s, _)) -> Some s
-
| _ -> None
-
in
-
let short_name =
-
match List.assoc_opt "short_name" assoc with
-
| Some (Jsont.String (s, _)) -> Some s
-
| _ -> None
-
in
-
(match (user_id, email, full_name) with
-
| (Some user_id, Some email, Some full_name) ->
-
(* Keep unknown fields *)
-
let unknown_fields = List.filter (fun (k, _) ->
-
k <> "user_id" && k <> "id" && k <> "email" && k <> "full_name" && k <> "short_name"
-
) assoc in
-
let unknown_mems = List.map (fun (k, v) -> ((k, Jsont.Meta.none), v)) unknown_fields in
-
let unknown = Jsont.Object (unknown_mems, Jsont.Meta.none) in
-
Ok { user_id; email; full_name; short_name; unknown }
-
| _ -> Error "Missing required user fields")
-
| _ -> Error "Expected JSON object for user"
+
let make email full_name short_name unknown =
+
(* user_id will be extracted in a custom way from the object *)
+
fun user_id_opt id_opt ->
+
let user_id = match user_id_opt, id_opt with
+
| Some uid, _ -> uid
+
| None, Some id -> id
+
| None, None -> Jsont.Error.msgf Jsont.Meta.none "Missing user_id or id field"
+
in
+
{ user_id; email; full_name; short_name; unknown }
in
-
let to_string { user_id; email; full_name; short_name; unknown } =
-
let fields = [
-
(("user_id", Jsont.Meta.none), Jsont.Number (float_of_int user_id, Jsont.Meta.none));
-
(("email", Jsont.Meta.none), Jsont.String (email, Jsont.Meta.none));
-
(("full_name", Jsont.Meta.none), Jsont.String (full_name, Jsont.Meta.none));
-
] in
-
let fields = match short_name with
-
| Some sn -> (("short_name", Jsont.Meta.none), Jsont.String (sn, Jsont.Meta.none)) :: fields
-
| None -> fields
-
in
-
let unknown_mems = match unknown with
-
| Jsont.Object (mems, _) -> mems
-
| _ -> []
-
in
-
let json = Jsont.Object (fields @ unknown_mems, Jsont.Meta.none) in
-
match Jsont_bytesrw.encode_string' Jsont.json json with
-
| Ok s -> s
-
| Error e -> failwith ("Failed to encode user: " ^ Jsont.Error.to_string e)
-
in
-
Jsont.of_of_string ~kind:"User" of_string ~enc:to_string
+
Jsont.Object.map ~kind:"User" make
+
|> Jsont.Object.mem "email" Jsont.string ~enc:email
+
|> Jsont.Object.mem "full_name" Jsont.string ~enc:full_name
+
|> Jsont.Object.opt_mem "short_name" Jsont.string ~enc:short_name
+
|> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun t -> t.unknown)
+
|> Jsont.Object.opt_mem "user_id" Jsont.int ~enc:(fun t -> Some t.user_id)
+
|> Jsont.Object.opt_mem "id" Jsont.int ~enc:(fun _ -> None)
+
|> Jsont.Object.finish
let of_json (json : Zulip.json) : (t, Zulip.zerror) result =
match Zulip.Encode.from_json jsont json with
···
(* Jsont codec for Reaction - handles user_id in different locations *)
let jsont : t Jsont.t =
-
let of_string s =
-
match Jsont_bytesrw.decode_string' Jsont.json s with
-
| Error _ -> Error "Failed to decode JSON"
-
| Ok json ->
-
match json with
-
| Jsont.Object (fields, _) ->
-
let assoc = List.map (fun ((k, _), v) -> (k, v)) fields in
-
let emoji_name =
-
match List.assoc_opt "emoji_name" assoc with
-
| Some (Jsont.String (s, _)) -> Some s
-
| _ -> None
-
in
-
let emoji_code =
-
match List.assoc_opt "emoji_code" assoc with
-
| Some (Jsont.String (s, _)) -> Some s
-
| _ -> None
-
in
-
let reaction_type =
-
match List.assoc_opt "reaction_type" assoc with
-
| Some (Jsont.String (s, _)) -> Some s
-
| _ -> None
-
in
-
(* user_id can be either directly in the object or nested in a "user" field *)
-
let user_id =
-
match List.assoc_opt "user_id" assoc with
-
| Some (Jsont.Number (f, _)) -> Some (int_of_float f)
-
| _ ->
-
match List.assoc_opt "user" assoc with
-
| Some (Jsont.Object (user_fields, _)) ->
-
let user_assoc = List.map (fun ((k, _), v) -> (k, v)) user_fields in
-
(match List.assoc_opt "user_id" user_assoc with
-
| Some (Jsont.Number (f, _)) -> Some (int_of_float f)
-
| _ -> None)
-
| _ -> None
-
in
-
(match (emoji_name, emoji_code, reaction_type, user_id) with
-
| (Some emoji_name, Some emoji_code, Some reaction_type, Some user_id) ->
-
(* Keep unknown fields *)
-
let unknown_fields = List.filter (fun (k, _) ->
-
k <> "emoji_name" && k <> "emoji_code" && k <> "reaction_type" && k <> "user_id" && k <> "user"
-
) assoc in
-
let unknown_mems = List.map (fun (k, v) -> ((k, Jsont.Meta.none), v)) unknown_fields in
-
let unknown = Jsont.Object (unknown_mems, Jsont.Meta.none) in
-
Ok { emoji_name; emoji_code; reaction_type; user_id; unknown }
-
| _ -> Error "Missing required reaction fields")
-
| _ -> Error "Expected JSON object for reaction"
+
(* Helper codec for nested user object - extracts just the user_id *)
+
let user_obj_codec =
+
Jsont.Object.map ~kind:"ReactionUser" Fun.id
+
|> Jsont.Object.mem "user_id" Jsont.int ~enc:Fun.id
+
|> Jsont.Object.finish
in
-
let to_string { emoji_name; emoji_code; reaction_type; user_id; unknown } =
-
let fields = [
-
(("emoji_name", Jsont.Meta.none), Jsont.String (emoji_name, Jsont.Meta.none));
-
(("emoji_code", Jsont.Meta.none), Jsont.String (emoji_code, Jsont.Meta.none));
-
(("reaction_type", Jsont.Meta.none), Jsont.String (reaction_type, Jsont.Meta.none));
-
(("user_id", Jsont.Meta.none), Jsont.Number (float_of_int user_id, Jsont.Meta.none));
-
] in
-
let unknown_mems = match unknown with
-
| Jsont.Object (mems, _) -> mems
-
| _ -> []
-
in
-
let json = Jsont.Object (fields @ unknown_mems, Jsont.Meta.none) in
-
match Jsont_bytesrw.encode_string' Jsont.json json with
-
| Ok s -> s
-
| Error e -> failwith ("Failed to encode reaction: " ^ Jsont.Error.to_string e)
+
let make emoji_name emoji_code reaction_type unknown =
+
fun user_id_direct user_obj_nested ->
+
let user_id = match user_id_direct, user_obj_nested with
+
| Some uid, _ -> uid
+
| None, Some uid -> uid
+
| None, None -> Jsont.Error.msgf Jsont.Meta.none "Missing user_id field"
+
in
+
{ emoji_name; emoji_code; reaction_type; user_id; unknown }
in
-
Jsont.of_of_string ~kind:"Reaction" of_string ~enc:to_string
+
Jsont.Object.map ~kind:"Reaction" make
+
|> Jsont.Object.mem "emoji_name" Jsont.string ~enc:emoji_name
+
|> Jsont.Object.mem "emoji_code" Jsont.string ~enc:emoji_code
+
|> Jsont.Object.mem "reaction_type" Jsont.string ~enc:reaction_type
+
|> Jsont.Object.keep_unknown Jsont.json_mems ~enc:(fun t -> t.unknown)
+
|> Jsont.Object.opt_mem "user_id" Jsont.int ~enc:(fun t -> Some t.user_id)
+
|> Jsont.Object.opt_mem "user" user_obj_codec ~enc:(fun _ -> None)
+
|> Jsont.Object.finish
let of_json (json : Zulip.json) : (t, Zulip.zerror) result =
match Zulip.Encode.from_json jsont json with