My agentic slop goes here. Not intended for anyone else!
1(* Test script to verify real-time bot event processing *)
2
3open Zulip_bot
4
5(* Logging setup *)
6let src = Logs.Src.create "test_realtime_bot" ~doc:"Test real-time bot"
7module Log = (val Logs.src_log src : Logs.LOG)
8
9(* Simple test bot that logs everything *)
10module Test_bot_handler : Bot_handler.S = struct
11 let initialize _config =
12 Log.info (fun m -> m "Bot initialized");
13 Ok ()
14
15 let usage () = "Test Bot - Verifies real-time event processing"
16
17 let description () = "A test bot that logs all messages received"
18
19 let handle_message ~config:_ ~storage ~identity:_ ~message ~env:_ =
20 Log.info (fun m -> m "Received message");
21
22 (* Extract and log message details *)
23 let content = Bot_handler.Message_context.content message in
24 let sender = Bot_handler.Message_context.sender_email message in
25 let is_direct = Bot_handler.Message_context.is_direct message in
26
27 Log.info (fun m -> m "Content: %s"
28 (Option.value content ~default:"<none>"));
29 Log.info (fun m -> m "Sender: %s"
30 (Option.value sender ~default:"<unknown>"));
31 Log.info (fun m -> m "Direct: %b" is_direct);
32
33 (* Test storage *)
34 let test_key = "last_message" in
35 let test_value = Option.value content ~default:"" in
36
37 (match Bot_storage.put storage ~key:test_key ~value:test_value with
38 | Ok () -> Log.info (fun m -> m "Stored message in bot storage")
39 | Error e -> Log.err (fun m -> m "Storage error: %s" (Zulip.error_message e)));
40
41 (* Always reply with confirmation *)
42 let reply = Printf.sprintf "Test bot received: %s"
43 (Option.value content ~default:"<empty>") in
44 Ok (Bot_handler.Response.Reply reply)
45end
46
47let run_test verbosity env =
48 (* Setup logging *)
49 Logs.set_reporter (Logs_fmt.reporter ());
50 Logs.set_level (Some (match verbosity with
51 | 0 -> Logs.Info
52 | 1 -> Logs.Debug
53 | _ -> Logs.Debug));
54
55 Log.info (fun m -> m "Real-time Bot Test");
56 Log.info (fun m -> m "==================");
57
58 (* Load auth *)
59 let auth = match Zulip.Auth.from_zuliprc () with
60 | Ok a ->
61 Log.info (fun m -> m "Loaded auth for: %s" (Zulip.Auth.email a));
62 Log.info (fun m -> m "Server: %s" (Zulip.Auth.server_url a));
63 a
64 | Error e ->
65 Log.err (fun m -> m "Failed to load .zuliprc: %s" (Zulip.error_message e));
66 exit 1
67 in
68
69 Eio.Switch.run @@ fun sw ->
70 let client = Zulip.Client.create ~sw env auth in
71
72 (* Create bot components *)
73 let config = Bot_config.create [] in
74 let bot_email = Zulip.Auth.email auth in
75 let storage = Bot_storage.create client ~bot_email in
76 let identity = Bot_handler.Identity.create
77 ~full_name:"Test Bot"
78 ~email:bot_email
79 ~mention_name:"testbot"
80 in
81
82 (* Create handler and runner *)
83 let handler = Bot_handler.create
84 (module Test_bot_handler)
85 ~config ~storage ~identity
86 in
87 let runner = Bot_runner.create ~env ~client ~handler in
88
89 Log.info (fun m -> m "Starting bot in real-time mode...");
90 Log.info (fun m -> m "The bot will:");
91 Log.info (fun m -> m "- Register for message events");
92 Log.info (fun m -> m "- Poll for new messages");
93 Log.info (fun m -> m "- Process and reply to messages");
94 Log.info (fun m -> m "- Store messages in Zulip bot storage");
95 Log.info (fun m -> m "Press Ctrl+C to stop.");
96
97 (* Run the bot *)
98 Bot_runner.run_realtime runner
99
100(* Command-line interface *)
101open Cmdliner
102
103let verbosity =
104 let doc = "Increase verbosity (can be used multiple times)" in
105 let verbosity_flags = Arg.(value & flag_all & info ["v"; "verbose"] ~doc) in
106 Term.(const List.length $ verbosity_flags)
107
108let main_cmd =
109 let doc = "Test real-time bot for Zulip" in
110 let man = [
111 `S Manpage.s_description;
112 `P "This bot tests real-time event processing with the Zulip API. \
113 It will echo received messages and store them in bot storage.";
114 `P "The bot requires a configured ~/.zuliprc file with API credentials.";
115 ] in
116 let info = Cmd.info "test_realtime_bot" ~version:"1.0.0" ~doc ~man in
117 let run verbosity =
118 Eio_main.run (run_test verbosity)
119 in
120 let term = Term.(const run $ verbosity) in
121 Cmd.v info term
122
123let () = exit (Cmd.eval main_cmd)