Skip to main content

agentmux_srv/backend/reactive/
mod.rs

1// Copyright 2025, Command Line Inc.
2// Copyright 2025-2026, AgentMux Corp.
3// SPDX-License-Identifier: Apache-2.0
4
5//! Reactive messaging system for agent-to-agent terminal communication.
6//! Port of Go's pkg/reactive/.
7//!
8//! Provides message injection into terminal panes, agent registration,
9//! rate limiting, message sanitization, audit logging, and cross-host
10//! polling via AgentMux cloud service.
11
12pub mod activity_watcher;
13pub mod handler;
14pub mod progress_watcher;
15pub mod poller;
16pub mod registry;
17pub mod sanitize;
18pub mod types;
19#[cfg(test)]
20mod tests;
21
22
23// ---- Constants ----
24
25/// Maximum message length in bytes.
26pub const MAX_MESSAGE_LENGTH: usize = 10_000;
27
28/// Suffix appended when a message is truncated.
29pub const TRUNCATION_SUFFIX: &str = "\n[Message truncated]";
30
31/// Maximum entries in the audit log ring buffer.
32const AUDIT_LOG_MAX: usize = 100;
33
34/// Woken whenever an agent registers, so jekts held for an absent agent are
35/// replayed promptly (`SPEC_DURABLE_JEKT_DELIVERY_2026_09_24.md` §2.3).
36/// `notify_one` does no I/O, so it is safe under the handler lock.
37pub fn held_jekt_wake() -> &'static tokio::sync::Notify {
38    static WAKE: std::sync::LazyLock<tokio::sync::Notify> =
39        std::sync::LazyLock::new(tokio::sync::Notify::new);
40    &WAKE
41}
42
43/// Rate limit: max tokens (requests per second).
44const RATE_LIMIT_MAX: u32 = 10;
45
46/// Default poll interval for AgentMux poller (seconds).
47pub const DEFAULT_POLL_INTERVAL_SECS: u64 = 30;
48
49// ---- Re-exports ----
50
51#[allow(unused_imports)]
52pub use handler::{get_global_handler, Handler, ReactiveHandler};
53#[allow(unused_imports)]
54pub use poller::Poller;
55#[allow(unused_imports)]
56pub use sanitize::{
57    broadcast_turn_message, format_injected_message, sanitize_message, validate_agent_id,
58    validate_muxbus_url,
59};
60#[allow(unused_imports)]
61pub use types::*;
62
63// ---- Helpers ----
64
65/// Get current time as Unix milliseconds.
66fn now_unix_millis() -> u64 {
67    agentmux_common::time::now_ms_u64()
68}
69
70/// A short hex hash of a message, so the audit log can tell messages apart
71/// without storing their text. `DefaultHasher`, not SHA-256: privacy, not
72/// security (it was named `sha256_hex` until the §5.3 #7 cleanup).
73fn audit_hash(input: &str) -> String {
74    use std::collections::hash_map::DefaultHasher;
75    use std::hash::{Hash, Hasher};
76    // Use a fast non-crypto hash for audit log (privacy, not security)
77    let mut hasher = DefaultHasher::new();
78    input.hash(&mut hasher);
79    format!("{:016x}", hasher.finish())
80}