My agentic slop goes here. Not intended for anyone else!
1module Identity = struct
2 type t = {
3 full_name : string;
4 email : string;
5 mention_name : string;
6 }
7
8 let create ~full_name ~email ~mention_name =
9 { full_name; email; mention_name }
10
11 let full_name t = t.full_name
12 let email t = t.email
13 let mention_name t = t.mention_name
14
15 let pp fmt t =
16 Format.fprintf fmt "Bot{email=%s, name=%s}" t.email t.full_name
17end
18
19module Message_context = struct
20 type t = {
21 message_id : int;
22 sender_email : string;
23 sender_full_name : string;
24 content : string;
25 message_type : Zulip.Message_type.t;
26 topic : string option;
27 channel : string option;
28 }
29
30 let create ~message_id ~sender_email ~sender_full_name ~content ~message_type ?topic ?channel () =
31 { message_id; sender_email; sender_full_name; content; message_type; topic; channel }
32
33 let message_id t = t.message_id
34 let sender_email t = t.sender_email
35 let sender_full_name t = t.sender_full_name
36 let content t = t.content
37 let message_type t = t.message_type
38 let topic t = t.topic
39 let channel t = t.channel
40 let is_direct_message t = t.message_type = `Direct
41 let is_channel_message t = t.message_type = `Channel
42
43 let pp fmt t =
44 Format.fprintf fmt "Message{id=%d, from=%s, type=%a}"
45 t.message_id t.sender_email Zulip.Message_type.pp t.message_type
46end
47
48module Response = struct
49 type t =
50 | Reply of string
51 | Send_to_channel of string * string * string (* channel, topic, content *)
52 | Send_direct of string list * string (* users, content *)
53 | React of string (* emoji *)
54 | None
55
56 let reply ~content = Reply content
57 let send_to_channel ~channel ~topic ~content = Send_to_channel (channel, topic, content)
58 let send_direct ~users ~content = Send_direct (users, content)
59 let react ~emoji = React emoji
60 let none = None
61end
62
63module type Bot_handler = sig
64 val initialize : Bot_config.t -> (unit, Zulip.Error.t) result
65 val usage : unit -> string
66 val description : unit -> string
67 val handle_message :
68 config:Bot_config.t ->
69 storage:Bot_storage.t ->
70 identity:Identity.t ->
71 message:Message_context.t ->
72 env:_ ->
73 (Response.t, Zulip.Error.t) result
74end
75
76type t = {
77 module_impl : (module Bot_handler);
78 config : Bot_config.t;
79 storage : Bot_storage.t;
80 identity : Identity.t;
81}
82
83let create module_impl ~config ~storage ~identity =
84 { module_impl; config; storage; identity }
85
86let handle_message t message =
87 (* Mock EIO environment for backwards compatibility *)
88 let mock_env = object
89 method fs = failwith "EIO environment not available - use handle_message_with_env"
90 method net = failwith "EIO environment not available - use handle_message_with_env"
91 method clock = failwith "EIO environment not available - use handle_message_with_env"
92 end in
93 let (module Handler) = t.module_impl in
94 Handler.handle_message ~config:t.config ~storage:t.storage ~identity:t.identity ~message ~env:mock_env
95
96let handle_message_with_env t env message =
97 let (module Handler) = t.module_impl in
98 Handler.handle_message ~config:t.config ~storage:t.storage ~identity:t.identity ~message ~env
99
100let identity t = t.identity
101
102let usage t =
103 let (module Handler) = t.module_impl in
104 Handler.usage ()
105
106let description t =
107 let (module Handler) = t.module_impl in
108 Handler.description ()