Skip to main content

cookie_agent_protocol/
goal.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::GoalId;
5
6#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
7#[serde(rename_all = "snake_case")]
8pub enum GoalStatus {
9    Active,
10    Paused,
11    Completed,
12    Cancelled,
13}
14
15/// User-only transitions. Completion is derived from a nonempty finished checklist.
16#[derive(Clone, Copy, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
17#[serde(rename_all = "snake_case")]
18pub enum GoalLifecycleAction {
19    Pause,
20    Resume,
21    Cancel,
22}
23
24#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
25#[serde(deny_unknown_fields)]
26pub struct GoalItem {
27    pub description: String,
28    pub finished: bool,
29}
30
31/// Root-session projection, rebuilt from goal events independently of compaction.
32/// Activation starts with an empty checklist; each subsequent event advances revision.
33#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
34#[serde(deny_unknown_fields)]
35pub struct GoalState {
36    pub goal_id: GoalId,
37    pub objective: String,
38    pub status: GoalStatus,
39    pub items: Vec<GoalItem>,
40    pub revision: u64,
41}
42
43#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
44#[serde(deny_unknown_fields)]
45pub struct GoalGetParams {}
46
47#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
48#[serde(deny_unknown_fields)]
49pub struct GoalGetResult {
50    #[serde(deserialize_with = "crate::deserialize_required_option")]
51    #[schemars(with = "crate::NullableSchema<GoalState>", required)]
52    pub goal: Option<GoalState>,
53}
54
55/// `goal_update` replaces the current root goal's checklist at actor execution,
56/// even if the goal changed since the calling run started. It is never a lifecycle
57/// command. The engine rejects absent/terminal goals and blank descriptions.
58/// Replacements are serialized; the last accepted update wins. Duplicate descriptions
59/// are allowed. Empty items preserve active/paused status. A nonempty
60/// all-finished update completes even while paused, without scheduling a wake.
61#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
62#[serde(deny_unknown_fields)]
63pub struct GoalUpdateParams {
64    pub items: Vec<GoalItem>,
65}
66
67#[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)]
68#[serde(deny_unknown_fields)]
69pub struct GoalUpdateResult {
70    pub goal: GoalState,
71}
72
73/// Whether a reminder introduces the objective or continues previously consumed work.
74/// Legacy reminder events always represented continuations.
75#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, JsonSchema, PartialEq, Serialize)]
76#[serde(rename_all = "snake_case")]
77pub enum GoalReminderKind {
78    Started,
79    #[default]
80    Continuation,
81}
82
83/// Pending reminder metadata, NOT a durable send idempotency key.
84/// Coalescing uses the goal ID and revision, independently of the presentation kind.
85/// After consumption another continuation at the same revision uses a fresh send.
86#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, JsonSchema, PartialEq, Serialize)]
87#[serde(deny_unknown_fields)]
88pub struct GoalReminderIdentity {
89    pub goal_id: GoalId,
90    pub revision: u64,
91    #[serde(default)]
92    pub kind: GoalReminderKind,
93}