Skip to main content

recursive/agent/
types.rs

1//! Cross-cutting agent types shared by the kernel, runtime, and tools.
2//!
3//! These types were extracted from `agent.rs` during Goal 219.  They have
4//! no dependency on the deprecated `Agent` / `StepEvent` types and are
5//! re-exported from `crate::agent::*` for backward compatibility.
6//!
7//! When Goal 219 Commit 2 deletes the deprecated `Agent` path, this
8//! module will be the sole owner of these four types.
9
10use serde::{Deserialize, Serialize};
11
12/// Decision returned by a permission hook to allow, deny, or transform a tool call.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum PermissionDecision {
16    /// Let the tool execute with the original arguments.
17    Allow,
18    /// Block execution and return the reason as a tool error to the model.
19    Deny(String),
20    /// Replace the arguments before execution.
21    Transform(serde_json::Value),
22}
23
24/// Controls whether the agent executes tools immediately or presents a plan first.
25#[derive(Debug, Clone, PartialEq, Default)]
26pub enum PlanningMode {
27    /// Execute tool calls immediately (current behavior).
28    #[default]
29    Immediate,
30    /// Buffer tool calls and emit a plan for confirmation before executing.
31    PlanFirst,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(tag = "kind", rename_all = "snake_case")]
36/// Why the agent's run terminated.
37///
38/// # Variants
39///
40/// - `NoMoreToolCalls`: Model produced a response without tool calls (natural completion).
41/// - `BudgetExceeded`: Ran out of steps (hit `max_steps`). Agent likely unfinished.
42/// - `ProviderStop(reason)`: LLM provider stopped unexpectedly. `reason` may be "length"
43///   (truncated by token limit), "stop"/"end_turn", or a provider-specific code.
44/// - `Stuck`: Agent got stuck calling the same tool repeatedly with the same arguments.
45///   `repeated_call` is the tool name, `repeats` is how many times before stopping.
46/// - `TranscriptLimit`: Transcript size hit `max_transcript_chars` hard limit before
47///   compaction could reduce it further. Agent cannot continue. `chars` is final size,
48///   `limit` is the configured maximum.
49#[non_exhaustive]
50pub enum FinishReason {
51    /// Model generated final response without requesting more tools.
52    NoMoreToolCalls,
53    /// Agent exceeded the maximum number of steps allowed.
54    BudgetExceeded,
55    /// LLM provider stopped with a specific reason or status code.
56    ProviderStop(String),
57    /// Agent detected repeated identical tool calls (stuck loop).
58    Stuck {
59        repeated_call: String,
60        repeats: usize,
61    },
62    /// Transcript size exceeded hard limit and cannot be reduced further.
63    TranscriptLimit { chars: usize, limit: usize },
64    /// Agent proposed a plan (PlanFirst mode) and is waiting for confirmation.
65    PlanPending,
66    /// Agent was cancelled by a shutdown signal (SIGINT/SIGTERM).
67    Cancelled,
68
69    /// The auto permission classifier reached its denial limit
70    /// (3 consecutive or 10 total denials). All subsequent tool
71    /// calls are blocked to prevent denial loops.
72    PermissionDenialLimit,
73}