Skip to main content

cap_rs/
core.rs

1//! Core protocol types — events, frames, content blocks, usage.
2//!
3//! These types are defined in the spec at <https://github.com/rsclaw-ai/cap-protocol/blob/main/docs/cap-v1.md>
4//! sections §7 (events) and §10 (lifecycle).
5//!
6//! All enums are marked `#[non_exhaustive]` during v0.x so new variants can
7//! be added without a semver-breaking change.
8
9use std::time::Duration;
10
11// ---------------------------------------------------------------------------
12// ClientFrame — what the orchestrator sends to the agent.
13// ---------------------------------------------------------------------------
14
15/// A frame sent by the client (orchestrator) to the agent during a session.
16#[derive(Debug, Clone)]
17#[non_exhaustive]
18pub enum ClientFrame {
19    /// A user prompt with one or more content parts.
20    Prompt { content: Vec<Content> },
21
22    /// An answer to a previously emitted [`AgentEvent::AskUser`].
23    AskUserAnswer { ask_id: String, value: serde_json::Value },
24
25    /// An answer to a previously emitted [`AgentEvent::PermissionRequest`].
26    PermissionResponse { req_id: String, decision: PermissionDecision },
27
28    /// Cancel the current turn (graceful).
29    Cancel,
30}
31
32/// A content part of a user prompt.
33#[derive(Debug, Clone)]
34#[non_exhaustive]
35pub enum Content {
36    Text(String),
37    Image { mime: String, data: Vec<u8> },
38    // File / ToolResult etc. land later
39}
40
41// ---------------------------------------------------------------------------
42// AgentEvent — what the agent streams back to the client.
43// ---------------------------------------------------------------------------
44
45/// A streaming event from the agent. Subset of spec §7.
46#[derive(Debug, Clone)]
47#[non_exhaustive]
48pub enum AgentEvent {
49    /// Session has been initialized and is ready to accept prompts.
50    Ready { session_id: String, model: Option<String> },
51
52    /// Streaming text chunk from the assistant.
53    TextChunk { msg_id: String, text: String, channel: TextChannel },
54
55    /// Agent's internal reasoning (when exposed by the model).
56    Thought { msg_id: String, text: String },
57
58    /// Agent started a tool call.
59    ToolCallStart { call_id: String, name: String, input: serde_json::Value },
60
61    /// Agent's tool call returned a result.
62    ToolCallEnd { call_id: String, output: String, is_error: bool },
63
64    /// Agent published an updated plan (full state, replaces previous).
65    Plan { entries: Vec<PlanEntry> },
66
67    /// Agent asks the user a structured question.
68    AskUser { ask_id: String, prompt: String, kind: AskKind, options: Vec<AskOption> },
69
70    /// Agent requests permission for a security-sensitive action.
71    PermissionRequest {
72        req_id: String,
73        tool: String,
74        intent: serde_json::Value,
75        scope: PermissionScope,
76    },
77
78    /// Turn complete. Usage stats included.
79    Done { stop_reason: StopReason, usage: Usage },
80
81    /// Non-fatal error during the turn.
82    Error { code: String, message: String },
83}
84
85/// Channel hint for [`AgentEvent::TextChunk`].
86#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87#[non_exhaustive]
88pub enum TextChannel {
89    Assistant,
90    System,
91}
92
93/// Plan entry from spec §7.3.
94#[derive(Debug, Clone)]
95pub struct PlanEntry {
96    pub id: String,
97    pub content: String,
98    pub status: PlanStatus,
99    pub priority: PlanPriority,
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103#[non_exhaustive]
104pub enum PlanStatus { Pending, InProgress, Completed, Cancelled, Blocked }
105
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107#[non_exhaustive]
108pub enum PlanPriority { High, Medium, Low }
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111#[non_exhaustive]
112pub enum AskKind { YesNo, Options, FreeText }
113
114#[derive(Debug, Clone)]
115pub struct AskOption {
116    pub id: String,
117    pub label: String,
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
121#[non_exhaustive]
122pub enum PermissionScope { Read, Write, Execute, Network }
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
125#[non_exhaustive]
126pub enum PermissionDecision { AllowOnce, AllowAlways, Deny }
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129#[non_exhaustive]
130pub enum StopReason {
131    EndTurn,
132    MaxTokens,
133    ToolUse,
134    StopSequence,
135    Cancelled,
136    Error,
137}
138
139/// Token / cost accounting for a completed turn.
140#[derive(Debug, Clone, Default)]
141pub struct Usage {
142    pub input_tokens: u64,
143    pub output_tokens: u64,
144    pub cache_read_tokens: u64,
145    pub cache_creation_tokens: u64,
146    pub cost_usd_estimate: Option<f64>,
147    pub duration: Option<Duration>,
148    pub model_id: Option<String>,
149}