Skip to main content

acp_utils/conversation/
turn.rs

1use agent_client_protocol::schema::v2 as acp;
2use schemars::JsonSchema;
3use serde::Serialize;
4use thiserror::Error;
5
6/// Where the current prompt is in its lifecycle.
7#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, JsonSchema)]
8#[serde(rename_all = "snake_case")]
9pub enum TurnPhase {
10    /// No prompt is outstanding; a new one can be sent.
11    #[default]
12    Idle,
13    /// A prompt was sent and the agent has not accepted it yet.
14    Submitting,
15    /// The agent accepted the prompt, or started a turn itself, and has not reached idle.
16    Running,
17    /// The agent reached idle before accepting the prompt, whose response is still owed.
18    CompletedBeforeAcceptance,
19}
20
21/// A turn the conversation was waiting on reached idle.
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub struct TurnFinished {
24    pub stop_reason: Option<acp::StopReason>,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
28#[error("the session is already in a turn")]
29pub struct TurnInProgress;
30
31impl TurnPhase {
32    pub fn is_idle(self) -> bool {
33        self == Self::Idle
34    }
35
36    pub fn waiting_for_response(self) -> bool {
37        matches!(self, Self::Submitting | Self::Running)
38    }
39
40    pub(super) fn accepted(self) -> Self {
41        match self {
42            Self::Submitting => Self::Running,
43            Self::CompletedBeforeAcceptance => Self::Idle,
44            Self::Idle | Self::Running => self,
45        }
46    }
47
48    pub(super) fn finished(self) -> Self {
49        match self {
50            Self::Submitting => Self::CompletedBeforeAcceptance,
51            Self::Running => Self::Idle,
52            Self::Idle | Self::CompletedBeforeAcceptance => self,
53        }
54    }
55}