agent_types/guard.rs
1//! Guard-related pure types: GuardDecision, GuardCtx.
2
3use serde::{Deserialize, Serialize};
4
5use crate::execution::FinishReason;
6use crate::session::SessionId;
7
8/// Guard decision — returned by guard, executed by base loop.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub enum GuardDecision {
11 /// Continue loop, optionally inject nudge message
12 Continue { nudge: Option<String> },
13 /// Normal completion (fire_turn_end + RunOutcome::Completed)
14 Complete,
15 /// Abnormal termination (fire_guard_fail + RunOutcome::Failed)
16 Fail { error: String },
17
18 // ─── Thinking control ─────────────────────────────────────
19 /// Temporarily disable thinking functionality
20 ///
21 /// Used for reasoning-only loop scenarios: model keeps thinking but produces no output.
22 /// After calling, runtime will:
23 /// 1. Set thinking_disabled_for_rest_of_run = true
24 /// 2. Inject nudge message
25 /// 3. Continue loop
26 DisableThinking { nudge: String },
27
28 /// Restore thinking functionality to previous state
29 ///
30 /// Used for thinking recovery scenarios: model starts working normally (has text or tool call).
31 /// After calling, runtime will:
32 /// 1. Restore thinking_disabled_for_rest_of_run to original state
33 /// 2. Reset related counters
34 RestoreThinking,
35}
36
37/// Guard context information — built by runtime, passed to guard.
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct GuardCtx {
40 pub session_id: SessionId,
41 pub turn_count: u32,
42 pub user_input: String,
43 pub model_response: String,
44 pub finish_reason: FinishReason,
45 pub available_tools: Vec<String>,
46 // RunState information
47 pub reasoning_only_strikes: usize,
48 pub empty_response_strikes: usize,
49 pub run_has_tool_calls: bool,
50 /// The most recent assistant tool calls were ALL rejected before
51 /// execution (truncated/invalid arguments) and the model was told to
52 /// re-issue them (`RunState.truncation_strikes > 0`). While this is
53 /// true, a text-only response cannot be task completion — the work the
54 /// text describes was never executed (session 20260904_efad759c: a
55 /// fabricated success narrative passed the completion judge).
56 pub last_tool_calls_invalid: bool,
57 /// All user messages in the current session, ordered oldest-first.
58 /// Guards can use this to reconstruct full conversation context
59 /// (e.g. "继续" after a multi-turn discussion).
60 pub all_user_inputs: Vec<String>,
61 // Scene hints (runtime detected, guard can trust or ignore)
62 pub is_reasoning_only: bool,
63 pub is_empty_response: bool,
64 pub is_text_only: bool,
65 // Environment state
66 pub thinking_disabled: bool,
67 /// Original thinking configuration (for restoration)
68 ///
69 /// From RunState.original_thinking_enabled
70 pub original_thinking_enabled: bool,
71 /// Remaining turns before hitting max_turns limit
72 ///
73 /// Guards can use this to nudge the model to wrap up when running low on turns.
74 /// When remaining_turns == 0, the run will be terminated with MaxTurnsExceeded.
75 pub remaining_turns: u32,
76}