runifold_agent/
completion.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
10pub struct CompletionRequirement {
11 max_terminal_repairs: u32,
12 retry_empty_response: bool,
13}
14
15impl CompletionRequirement {
16 pub const fn new() -> Self {
18 Self {
19 max_terminal_repairs: 0,
20 retry_empty_response: false,
21 }
22 }
23
24 #[must_use]
26 pub const fn max_repairs(mut self, maximum: u32) -> Self {
27 self.max_terminal_repairs = maximum;
28 self
29 }
30
31 #[must_use]
34 pub const fn retry_empty_response(mut self, enabled: bool) -> Self {
35 self.retry_empty_response = enabled;
36 self
37 }
38
39 pub const fn max_terminal_repairs(self) -> u32 {
41 self.max_terminal_repairs
42 }
43
44 pub const fn retries_empty_response(self) -> bool {
46 self.retry_empty_response
47 }
48}
49
50#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
52#[serde(rename_all = "snake_case")]
53#[non_exhaustive]
54pub enum TerminalRequirementFailureKind {
55 EmptyResponse,
57 MissingStructuredText,
59 InvalidStructuredOutput,
61 Refusal,
63}
64
65#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
67pub struct TerminalRequirementFailure {
68 pub kind: TerminalRequirementFailureKind,
70 pub line: Option<usize>,
72 pub column: Option<usize>,
74}
75
76impl TerminalRequirementFailure {
77 pub(crate) const fn new(kind: TerminalRequirementFailureKind) -> Self {
78 Self {
79 kind,
80 line: None,
81 column: None,
82 }
83 }
84
85 pub(crate) const fn repairable(&self, policy: CompletionRequirement) -> bool {
86 match self.kind {
87 TerminalRequirementFailureKind::EmptyResponse
88 | TerminalRequirementFailureKind::MissingStructuredText => {
89 policy.retries_empty_response()
90 }
91 TerminalRequirementFailureKind::InvalidStructuredOutput => true,
92 TerminalRequirementFailureKind::Refusal => false,
93 }
94 }
95}