Skip to main content

ainl_contracts/
learner.rs

1//! Shared learner payloads (trajectory steps, failure taxonomy, proposal envelopes).
2//!
3//! Consumed by `ainl-trajectory` / `ainl-failure-learning` crates; hosts embed these in graph nodes.
4
5use serde::{Deserialize, Serialize};
6
7use crate::vitals::CognitiveVitals;
8use crate::{ContextFreshness, ImpactDecision};
9
10/// One step in an execution trajectory (tool / adapter granularity).
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12pub struct TrajectoryStep {
13    pub step_id: String,
14    /// Unix epoch milliseconds.
15    pub timestamp_ms: i64,
16    pub adapter: String,
17    pub operation: String,
18    #[serde(default)]
19    pub inputs_preview: Option<String>,
20    #[serde(default)]
21    pub outputs_preview: Option<String>,
22    pub duration_ms: u64,
23    pub success: bool,
24    #[serde(default)]
25    pub error: Option<String>,
26    #[serde(default)]
27    pub vitals: Option<CognitiveVitals>,
28    #[serde(default)]
29    pub freshness_at_step: Option<ContextFreshness>,
30    /// Optional per-step state snapshot (host-defined JSON, e.g. turn counters, budget).
31    #[serde(default, skip_serializing_if = "Option::is_none")]
32    pub frame_vars: Option<serde_json::Value>,
33    /// Optional structured tool telemetry (latency breakdown, I/O, HTTP, etc.).
34    #[serde(default, skip_serializing_if = "Option::is_none")]
35    pub tool_telemetry: Option<serde_json::Value>,
36}
37
38/// Overall outcome of a recorded trajectory.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case")]
41pub enum TrajectoryOutcome {
42    Success,
43    PartialSuccess,
44    Failure,
45    Aborted,
46}
47
48/// Normalised failure kinds for learning + FTS indexing.
49#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
50#[serde(rename_all = "snake_case", tag = "kind", content = "details")]
51pub enum FailureKind {
52    AdapterTypo {
53        offered: String,
54        #[serde(default)]
55        suggestion: Option<String>,
56    },
57    ValidatorReject {
58        rule: String,
59    },
60    AdapterTimeout {
61        adapter: String,
62        ms: u64,
63    },
64    ToolError {
65        tool: String,
66        message: String,
67    },
68    LoopGuardFire {
69        tool: String,
70        repeat_count: u32,
71    },
72    Other {
73        message: String,
74    },
75}
76
77/// Closed-loop improvement proposal envelope (validate → adopt).
78#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
79pub struct ProposalEnvelope {
80    pub schema_version: u32,
81    pub original_hash: String,
82    pub proposed_hash: String,
83    pub kind: String,
84    pub rationale: String,
85    pub freshness_at_proposal: ContextFreshness,
86    pub impact_decision: ImpactDecision,
87}