My aggregated monorepo of OCaml code, automaintained
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Show active sessions in status command with stats

The status command now displays information about active sessions:
- Lists all active sessions (channel topics and DMs)
- Shows number of turns in each session
- Shows how long each session has been active
- Shows last update time for each session

Example output:
- Active sessions (2):
- **channel foo > topic bar**: 5 turns, last updated 30s ago (active for 1.5h)
- **DM with user@example.com**: 3 turns, last updated 2m ago (active for 45m)

Co-Authored-By: Claude (claude-opus-4-5) <noreply@anthropic.com>

+35 -5
+35 -5
poe/lib/handler.ml
··· 19 19 Once active, all messages in that scope are accumulated into context. 20 20 Resets on bot restart (intentional - requires new @mention to reactivate). *) 21 21 module Active_sessions = struct 22 - let sessions : (string, unit) Hashtbl.t = Hashtbl.create 16 22 + (* Store scope and activation time *) 23 + let sessions : (string, Session.scope * float) Hashtbl.t = Hashtbl.create 16 23 24 24 25 let activate scope = 25 26 let key = Session.scope_to_string scope in 26 27 if not (Hashtbl.mem sessions key) then begin 27 - Hashtbl.add sessions key (); 28 + Hashtbl.add sessions key (scope, Unix.gettimeofday ()); 28 29 Log.info (fun m -> m "Session activated for %s" key) 29 30 end 30 31 ··· 36 37 let key = Session.scope_to_string scope in 37 38 Hashtbl.remove sessions key; 38 39 Log.info (fun m -> m "Session deactivated for %s" key) 40 + 41 + let list_all () = 42 + Hashtbl.fold (fun _key (scope, activated_at) acc -> 43 + (scope, activated_at) :: acc 44 + ) sessions [] 39 45 end 40 46 41 47 let run_git_pull ~proc ~cwd = ··· 328 334 | None -> None 329 335 ) subdirs 330 336 331 - let handle_status env config = 337 + let format_duration seconds = 338 + if seconds < 60.0 then Printf.sprintf "%.0fs" seconds 339 + else if seconds < 3600.0 then Printf.sprintf "%.0fm" (seconds /. 60.0) 340 + else Printf.sprintf "%.1fh" (seconds /. 3600.0) 341 + 342 + let handle_status env ~storage config = 332 343 let admin_list = if config.Config.admin_emails = [] then "none configured" 333 344 else String.concat ", " config.Config.admin_emails 334 345 in ··· 349 360 handle mono_url opam_url) 350 361 |> String.concat "\n") 351 362 in 363 + (* Build active sessions section *) 364 + let active_sessions = Active_sessions.list_all () in 365 + let now = Unix.gettimeofday () in 366 + let sessions_section = 367 + if active_sessions = [] then 368 + "- Active sessions: none" 369 + else 370 + let session_lines = active_sessions |> List.map (fun (scope, activated_at) -> 371 + let session = Session.load storage ~scope ~now in 372 + let scope_str = Session.scope_to_string scope in 373 + let active_for = format_duration (now -. activated_at) in 374 + let stats = Session.stats session in 375 + Printf.sprintf " - **%s**: %s (active for %s)" scope_str stats active_for 376 + ) in 377 + Printf.sprintf "- Active sessions (%d):\n%s" 378 + (List.length active_sessions) 379 + (String.concat "\n" session_lines) 380 + in 352 381 Zulip_bot.Response.reply 353 382 (Printf.sprintf 354 383 {|**Poe Bot Status:** ··· 357 386 - Topic: `%s` 358 387 - Verse path: `%s` 359 388 - Admin emails: %s 389 + %s 360 390 %s|} 361 391 config.Config.channel config.Config.topic 362 - verse_path admin_list users_section) 392 + verse_path admin_list users_section sessions_section) 363 393 364 394 let handle_refresh env ~client ~storage ~config = 365 395 let monorepo_path = Eio.Path.(env.fs / config.Config.monorepo_path) in ··· 466 496 Log.info (fun m -> m "Received message (mentioned): %s" content); 467 497 match Commands.parse content with 468 498 | Commands.Help -> handle_help () 469 - | Commands.Status -> handle_status env config 499 + | Commands.Status -> handle_status env ~storage config 470 500 | Commands.Broadcast -> 471 501 Broadcast.run ~sw:env.sw ~proc:env.process_mgr ~clock:env.clock 472 502 ~fs:env.fs ~client ~storage ~config