Files
Kigi-CLI/crates/codegen/kigi-agent/src/system_reminder.rs
T
ZacharyZhang-NY a02b555e66 docs(comments): rewrite comments across all crates to the guidelines
Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).

No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.

Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).

Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
2026-07-23 16:55:39 -04:00

106 lines
3.2 KiB
Rust

//! Reminder policy — wraps kigi-tools reminder config.
/// Seeds `TodoGateConfig::max_fires_per_prompt`; the gate reads the live value
/// from `ReminderPolicy.todo_gate`, never this constant.
pub const DEFAULT_TODO_GATE_MAX_FIRES: u32 = 2;
/// Session-level system reminder policy.
#[derive(Debug, Clone)]
pub struct ReminderPolicy {
pub enabled: bool,
pub todo_nudge: TodoNudgeConfig,
pub todo_gate: TodoGateConfig,
}
impl Default for ReminderPolicy {
fn default() -> Self {
Self {
enabled: true,
todo_nudge: TodoNudgeConfig::default(),
todo_gate: TodoGateConfig::default(),
}
}
}
/// Reminds the model to call `todo_write` once it has gone
/// `turns_since_todo_write` turns without one, then stays quiet for
/// `turns_between_reminders` turns.
#[derive(Debug, Clone)]
pub struct TodoNudgeConfig {
pub enabled: bool,
pub turns_since_todo_write: u32,
pub turns_between_reminders: u32,
}
impl Default for TodoNudgeConfig {
fn default() -> Self {
Self {
enabled: true,
turns_since_todo_write: 3,
turns_between_reminders: 5,
}
}
}
/// Turn-end gate: inspects `TodoState` after every content-only assistant
/// message and forces another turn via `<system-reminder>` injection if
/// pending/unbacked-in-progress todos remain — see
/// `kigi-shell::session::acp_session::evaluate_todo_gate`.
///
/// **Disabled by default.** Operators opt in via the `todo_gate_enabled`
/// remote settings key, or via the `--todo-gate` CLI flag (session-scoped
/// force-enable, highest precedence).
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TodoGateConfig {
pub enabled: bool,
/// Past this many fires per user prompt the next turn is allowed to end
/// with `TurnOutcome::Completed`, bounding worst-case extra inference cost.
pub max_fires_per_prompt: u32,
}
impl Default for TodoGateConfig {
fn default() -> Self {
Self {
enabled: false,
max_fires_per_prompt: DEFAULT_TODO_GATE_MAX_FIRES,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_todo_gate_is_disabled_with_const_cap() {
let cfg = TodoGateConfig::default();
assert!(!cfg.enabled, "TodoGate must be opt-in");
assert_eq!(cfg.max_fires_per_prompt, DEFAULT_TODO_GATE_MAX_FIRES);
assert_eq!(DEFAULT_TODO_GATE_MAX_FIRES, 2);
}
#[test]
fn reminder_policy_default_disables_gate_but_keeps_nudge_and_global_enabled() {
let policy = ReminderPolicy::default();
assert!(
policy.enabled,
"global system reminders stay enabled by default"
);
assert!(
!policy.todo_gate.enabled,
"TodoGate ships disabled; remote/local opt-in required"
);
assert_eq!(policy.todo_gate.max_fires_per_prompt, 2);
assert!(policy.todo_nudge.enabled);
}
#[test]
fn todo_gate_enable_does_not_disturb_nudge() {
let mut policy = ReminderPolicy::default();
policy.todo_gate.enabled = true;
assert!(policy.todo_gate.enabled);
assert!(policy.todo_nudge.enabled, "TodoNudge must stay enabled");
assert!(policy.enabled, "global enable must stay true");
}
}