Skip to main content

ag_session/
transcript_notice.rs

1use std::fmt;
2
3/// Canonical labels for bracketed workflow notices appended to a session
4/// transcript.
5///
6/// Session output rendering uses the same labels to recognize trailing
7/// workflow notices, so producing notices through this enum keeps new labels
8/// aligned with summary render ordering.
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
10pub enum TranscriptNotice {
11    /// Prompt `/apply` command status.
12    Apply,
13    /// Automatic published-branch push result.
14    BranchPush,
15    /// Automatic published-branch push failure.
16    BranchPushError,
17    /// Session auto-commit result.
18    Commit,
19    /// Agent-assisted auto-commit recovery attempt.
20    CommitAssist,
21    /// Session auto-commit failure.
22    CommitError,
23    /// Advisory for a commit that ran without a configured pre-commit hook.
24    CommitWarning,
25    /// Follow-on session creation failure.
26    ContinueError,
27    /// Generic prompt submission failure.
28    Error,
29    /// Session fork creation failure.
30    ForkError,
31    /// Follow-up task execution failure.
32    FollowUpTaskError,
33    /// Merge workflow progress.
34    Merge,
35    /// Merge workflow failure.
36    MergeError,
37    /// Main checkout changed during a provider turn.
38    MainCheckoutWarning,
39    /// Prompt image-paste failure.
40    PasteImageError,
41    /// Session personality selection or fallback status.
42    Personality,
43    /// Queued prompt failure.
44    QueueError,
45    /// Session sync workflow progress.
46    Rebase,
47    /// Agent-assisted session sync recovery attempt.
48    RebaseAssist,
49    /// Session sync workflow failure.
50    RebaseError,
51    /// Reply submission failure.
52    ReplyError,
53    /// Review-request creation result.
54    ReviewRequest,
55    /// Successful forge review-thread replies and resolution.
56    ReviewComments,
57    /// Partial or failed forge review-thread resolution.
58    ReviewCommentsWarning,
59    /// Review-request sync warning.
60    ReviewRequestSyncWarning,
61    /// Draft session start failure.
62    StartError,
63    /// Completed-turn metadata persistence failure.
64    TurnMetadataError,
65}
66
67impl TranscriptNotice {
68    /// Returns the bracketed transcript prefix for this notice kind.
69    pub const fn prefix(self) -> &'static str {
70        match self {
71            Self::Apply => "[Apply]",
72            Self::BranchPush => "[Branch Push]",
73            Self::BranchPushError => "[Branch Push Error]",
74            Self::Commit => "[Commit]",
75            Self::CommitAssist => "[Commit Assist]",
76            Self::CommitError => "[Commit Error]",
77            Self::CommitWarning => "[Commit Warning]",
78            Self::ContinueError => "[Continue Error]",
79            Self::Error => "[Error]",
80            Self::ForkError => "[Fork Error]",
81            Self::FollowUpTaskError => "[Follow-Up Task Error]",
82            Self::Merge => "[Merge]",
83            Self::MergeError => "[Merge Error]",
84            Self::MainCheckoutWarning => "[Main Checkout Warning]",
85            Self::PasteImageError => "[Paste Image Error]",
86            Self::Personality => "[Personality]",
87            Self::QueueError => "[Queue Error]",
88            Self::Rebase => "[Sync]",
89            Self::RebaseAssist => "[Sync Assist]",
90            Self::RebaseError => "[Sync Error]",
91            Self::ReplyError => "[Reply Error]",
92            Self::ReviewRequest => "[Review Request]",
93            Self::ReviewComments => "[Review Comments]",
94            Self::ReviewCommentsWarning => "[Review Comments Warning]",
95            Self::ReviewRequestSyncWarning => "[Review Request Sync Warning]",
96            Self::StartError => "[Start Error]",
97            Self::TurnMetadataError => "[Turn Metadata Error]",
98        }
99    }
100
101    /// Formats one transcript notice as a newline-delimited paragraph.
102    pub fn format(self, detail: impl fmt::Display) -> String {
103        format!("\n{}\n", self.format_line(detail))
104    }
105
106    /// Formats one transcript notice as a single display line without
107    /// paragraph separators.
108    pub fn format_line(self, detail: impl fmt::Display) -> String {
109        format!("{} {}", self.prefix(), detail)
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    #[test]
118    fn test_transcript_notice_prefixes_match_canonical_labels() {
119        // Arrange
120        let notices = [
121            (TranscriptNotice::Apply, "[Apply]"),
122            (TranscriptNotice::BranchPush, "[Branch Push]"),
123            (TranscriptNotice::BranchPushError, "[Branch Push Error]"),
124            (TranscriptNotice::Commit, "[Commit]"),
125            (TranscriptNotice::CommitAssist, "[Commit Assist]"),
126            (TranscriptNotice::CommitError, "[Commit Error]"),
127            (TranscriptNotice::CommitWarning, "[Commit Warning]"),
128            (TranscriptNotice::ContinueError, "[Continue Error]"),
129            (TranscriptNotice::Error, "[Error]"),
130            (TranscriptNotice::ForkError, "[Fork Error]"),
131            (
132                TranscriptNotice::FollowUpTaskError,
133                "[Follow-Up Task Error]",
134            ),
135            (TranscriptNotice::Merge, "[Merge]"),
136            (TranscriptNotice::MergeError, "[Merge Error]"),
137            (
138                TranscriptNotice::MainCheckoutWarning,
139                "[Main Checkout Warning]",
140            ),
141            (TranscriptNotice::PasteImageError, "[Paste Image Error]"),
142            (TranscriptNotice::Personality, "[Personality]"),
143            (TranscriptNotice::QueueError, "[Queue Error]"),
144            (TranscriptNotice::Rebase, "[Sync]"),
145            (TranscriptNotice::RebaseAssist, "[Sync Assist]"),
146            (TranscriptNotice::RebaseError, "[Sync Error]"),
147            (TranscriptNotice::ReplyError, "[Reply Error]"),
148            (TranscriptNotice::ReviewRequest, "[Review Request]"),
149            (TranscriptNotice::ReviewComments, "[Review Comments]"),
150            (
151                TranscriptNotice::ReviewCommentsWarning,
152                "[Review Comments Warning]",
153            ),
154            (
155                TranscriptNotice::ReviewRequestSyncWarning,
156                "[Review Request Sync Warning]",
157            ),
158            (TranscriptNotice::StartError, "[Start Error]"),
159            (TranscriptNotice::TurnMetadataError, "[Turn Metadata Error]"),
160        ];
161
162        // Act
163        let prefixes = notices.map(|(notice, _)| notice.prefix());
164        let expected = notices.map(|(_, expected)| expected);
165
166        // Assert
167        assert_eq!(prefixes, expected);
168    }
169
170    #[test]
171    fn test_transcript_notice_format_wraps_detail_as_paragraph() {
172        // Arrange
173        let notice = TranscriptNotice::RebaseAssist;
174
175        // Act
176        let formatted = notice.format("Attempt 1/3. Resolving conflicts in:\n- src/main.rs");
177
178        // Assert
179        assert_eq!(
180            formatted,
181            "\n[Sync Assist] Attempt 1/3. Resolving conflicts in:\n- src/main.rs\n"
182        );
183    }
184
185    #[test]
186    fn test_transcript_notice_format_line_omits_paragraph_spacing() {
187        // Arrange
188        let notice = TranscriptNotice::Commit;
189
190        // Act
191        let formatted = notice.format_line("No changes to commit.");
192
193        // Assert
194        assert_eq!(formatted, "[Commit] No changes to commit.");
195    }
196}