Skip to main content

licoup_workflow/
strategy.rs

1//! Strategy definition, binding, projection and error vocabulary.
2//!
3//! The persisted definition/binding/projection records are the generic engine
4//! vocabulary, re-exported unchanged so the store's rows and the wire
5//! projections keep their exact shape. What stays here is the host-facing
6//! error surface: [`StrategyErrorCode`] is the `strategy.*` command's typed
7//! refusal spelling, and [`ASSISTANT_TEMPORARY_DEFINITION_PREFIX`] names the
8//! definition space the Assistant author owns.
9
10pub use acativa::workflow::strategy::{
11    BindingCandidate, BindingValue, StrategyAuthorization, StrategyDefinition,
12    StrategyDefinitionSummary, StrategyDiagnostic, StrategyProjection,
13};
14
15use serde::{Deserialize, Serialize};
16
17#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
18#[serde(rename_all = "snake_case")]
19pub enum StrategyErrorCode {
20    InvalidRequest,
21    PackageUnavailable,
22    PackageTooLarge,
23    PackageEntryInvalid,
24    PackageLayoutInvalid,
25    PackageDuplicateEntry,
26    PackageResourceLimit,
27    WorkflowInvalid,
28    DefinitionNotFound,
29    PreparationNotFound,
30    RevisionConflict,
31    BindingIncomplete,
32    AuthorizationRequired,
33    AuthorizationStale,
34    RuntimeUnavailable,
35    RuntimeDrifted,
36    SandboxUnavailable,
37    PermitDenied,
38    RunNotFound,
39    RunNotRetryable,
40    CallbackStale,
41    CallbackConflict,
42    EffectInDoubt,
43    UnsupportedAction,
44}
45
46impl StrategyErrorCode {
47    pub const fn wire(self) -> &'static str {
48        match self {
49            Self::InvalidRequest => "invalid_request",
50            Self::PackageUnavailable => "package_unavailable",
51            Self::PackageTooLarge => "package_too_large",
52            Self::PackageEntryInvalid => "package_entry_invalid",
53            Self::PackageLayoutInvalid => "package_layout_invalid",
54            Self::PackageDuplicateEntry => "package_duplicate_entry",
55            Self::PackageResourceLimit => "package_resource_limit",
56            Self::WorkflowInvalid => "workflow_invalid",
57            Self::DefinitionNotFound => "definition_not_found",
58            Self::PreparationNotFound => "preparation_not_found",
59            Self::RevisionConflict => "revision_conflict",
60            Self::BindingIncomplete => "binding_incomplete",
61            Self::AuthorizationRequired => "authorization_required",
62            Self::AuthorizationStale => "authorization_stale",
63            Self::RuntimeUnavailable => "runtime_unavailable",
64            Self::RuntimeDrifted => "runtime_drifted",
65            Self::SandboxUnavailable => "sandbox_unavailable",
66            Self::PermitDenied => "permit_denied",
67            Self::RunNotFound => "run_not_found",
68            Self::RunNotRetryable => "run_not_retryable",
69            Self::CallbackStale => "callback_stale",
70            Self::CallbackConflict => "callback_conflict",
71            Self::EffectInDoubt => "effect_in_doubt",
72            Self::UnsupportedAction => "unsupported_action",
73        }
74    }
75}
76
77#[derive(Clone, Debug, Eq, PartialEq)]
78pub struct StrategyError {
79    pub code: StrategyErrorCode,
80    pub stage: &'static str,
81    pub component: &'static str,
82    pub retryable: bool,
83    pub recovery: &'static str,
84}
85
86impl StrategyError {
87    pub const fn new(
88        code: StrategyErrorCode,
89        stage: &'static str,
90        component: &'static str,
91        retryable: bool,
92        recovery: &'static str,
93    ) -> Self {
94        Self {
95            code,
96            stage,
97            component,
98            retryable,
99            recovery,
100        }
101    }
102}
103
104impl std::fmt::Display for StrategyError {
105    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        formatter.write_str(self.code.wire())
107    }
108}
109
110impl std::error::Error for StrategyError {}
111
112/// Source prefix naming a definition the Assistant created for one temporary
113/// Graph run rather than one the user imported. The prefix is part of the
114/// definition identity, so it stays with the definition vocabulary.
115pub const ASSISTANT_TEMPORARY_DEFINITION_PREFIX: &str = "assistant-temporary";