Skip to main content

bock_ai/
request.rs

1//! Request and response types for the four AI interaction modes
2//! defined in §17.8: Generate, Repair, Optimize, and Select.
3//!
4//! All confidence values are `f64` in the range `0.0..=1.0` (see §17.4).
5//! Providers are expected to populate reasoning and alternatives where
6//! feasible so that decision manifest entries can be constructed from a
7//! response without a second provider round-trip.
8
9use std::collections::HashMap;
10
11use bock_air::AIRNode;
12use bock_types::Strictness;
13use serde::{Deserialize, Serialize};
14
15// ─── Shared helper types ─────────────────────────────────────────────────────
16
17/// Minimal target profile view consumed by the provider interface.
18///
19/// Intentionally lightweight: it carries the identifying fields every
20/// provider prompt needs (target id and display name) plus summary bags
21/// so a richer profile (e.g., the capability matrix owned by
22/// `bock-codegen`) can be flattened into textual context without
23/// creating a crate dependency cycle.
24///
25/// D.5 will have `bock-codegen` construct one of these when calling
26/// the provider.
27#[derive(Debug, Clone, Default, PartialEq, Eq)]
28pub struct TargetProfile {
29    /// Short identifier: `"js"`, `"ts"`, `"python"`, `"rust"`, `"go"`, ...
30    pub id: String,
31    /// Human-readable display name (`"JavaScript"`, `"Rust"`).
32    pub display_name: String,
33    /// Flattened capability map (e.g., `"memory_model" -> "GC"`).
34    pub capabilities: HashMap<String, String>,
35    /// Flattened convention map (e.g., `"naming" -> "snake_case"`).
36    pub conventions: HashMap<String, String>,
37}
38
39/// Per-module context fed to generation/repair/optimize calls.
40///
41/// Supplies the provider with enough surrounding information to produce
42/// idiomatic target code without leaking the full project. Concrete
43/// fields may grow in later phases.
44#[derive(Debug, Clone, Default, PartialEq, Eq)]
45pub struct ModuleContext {
46    /// Canonical module path (e.g., `"src/net/http_client.bock"`).
47    pub module_path: String,
48    /// Names and short signatures of imports visible in this module.
49    pub imports: Vec<String>,
50    /// Names of sibling definitions in the same module.
51    pub siblings: Vec<String>,
52    /// Project-level semantic annotations reaching this module
53    /// (`@context`, `@domain`, `@security`).
54    pub annotations: Vec<String>,
55}
56
57/// Reference to a prior decision that should bias the current call.
58///
59/// Lets providers stay consistent with already-made choices (e.g., same
60/// async runtime, same JSON library) without re-examining every option.
61/// Corresponds to a decision manifest entry per §17.4.
62#[derive(Debug, Clone, PartialEq, Eq)]
63pub struct DecisionRef {
64    /// Decision key, e.g., `"async_runtime"`.
65    pub decision: String,
66    /// Selected value, e.g., `"tokio"`.
67    pub choice: String,
68}
69
70/// Hints for the optimization pass (Tier 3).
71#[derive(Debug, Clone, PartialEq, Eq)]
72pub enum OptimizationHint {
73    /// Prefer runtime performance.
74    Performance,
75    /// Prefer idiomatic target-language style.
76    Idiomatic,
77    /// Prefer smaller generated code size.
78    CodeSize,
79    /// Provider-specific hint carrying a free-form label.
80    Custom(String),
81}
82
83/// An alternative considered by the provider but not chosen.
84///
85/// Populated into decision manifest entries so reviewers can see what
86/// else the model weighed against the accepted choice.
87#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
88pub struct Alternative {
89    /// Short label identifying the alternative.
90    pub label: String,
91    /// Why this alternative was rejected.
92    pub reasoning: Option<String>,
93    /// Confidence assigned to this alternative.
94    pub confidence: f64,
95}
96
97/// Candidate codegen rule emitted by a successful `repair` response.
98///
99/// See §17.7. The rule describes a pattern/template pair that, if
100/// accepted, would let Tier 2 generate the correct code deterministically
101/// for future AIR nodes of the same shape.
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
103pub struct CandidateRule {
104    /// Target language the rule applies to (e.g., `"js"`).
105    pub target_id: String,
106    /// AIR pattern the rule matches, in a format TBD per §17.7.
107    pub pattern: String,
108    /// Code template to emit when the pattern matches.
109    pub template: String,
110    /// Priority for conflict resolution (higher wins).
111    pub priority: i32,
112}
113
114// ─── Generate (Tier 1) ───────────────────────────────────────────────────────
115
116/// Input to [`AiProvider::generate`](crate::provider::AiProvider::generate).
117#[derive(Debug, Clone)]
118pub struct GenerateRequest {
119    /// AIR node to be translated.
120    pub node: AIRNode,
121    /// Target profile (language + capabilities + conventions).
122    pub target: TargetProfile,
123    /// Surrounding module context.
124    pub module_context: ModuleContext,
125    /// Previously accepted decisions the provider should stay consistent with.
126    pub prior_decisions: Vec<DecisionRef>,
127    /// Graduated strictness level for the current compilation.
128    pub strictness: Strictness,
129}
130
131/// Response from [`AiProvider::generate`](crate::provider::AiProvider::generate).
132#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
133pub struct GenerateResponse {
134    /// Target-language code produced for the AIR node.
135    pub code: String,
136    /// Confidence in the produced code (`0.0..=1.0`, see §17.4).
137    pub confidence: f64,
138    /// Optional free-form reasoning for decision manifest entries.
139    pub reasoning: Option<String>,
140    /// Alternatives considered but not chosen.
141    pub alternatives: Vec<Alternative>,
142}
143
144// ─── Repair (§17.7) ──────────────────────────────────────────────────────────
145
146/// Input to [`AiProvider::repair`](crate::provider::AiProvider::repair).
147#[derive(Debug, Clone)]
148pub struct RepairRequest {
149    /// The code that failed target compilation or verification.
150    pub original_code: String,
151    /// Diagnostic message from the target compiler/verifier.
152    pub compiler_error: String,
153    /// The AIR node the failing code was generated from.
154    pub node: AIRNode,
155    /// Target profile under which the failure occurred.
156    pub target: TargetProfile,
157}
158
159/// Response from [`AiProvider::repair`](crate::provider::AiProvider::repair).
160#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
161pub struct RepairResponse {
162    /// Fixed target-language code.
163    pub fixed_code: String,
164    /// Confidence in the fix (`0.0..=1.0`).
165    pub confidence: f64,
166    /// Optional candidate rule distilled from the repair, to be proposed
167    /// for merging into the local rule cache.
168    pub candidate_rule: Option<CandidateRule>,
169    /// Optional free-form reasoning.
170    pub reasoning: Option<String>,
171}
172
173// ─── Optimize (Tier 3) ───────────────────────────────────────────────────────
174
175/// Input to [`AiProvider::optimize`](crate::provider::AiProvider::optimize).
176#[derive(Debug, Clone)]
177pub struct OptimizeRequest {
178    /// Target-language code that already compiles and verifies.
179    pub working_code: String,
180    /// The AIR node the code was generated from.
181    pub node: AIRNode,
182    /// Target profile.
183    pub target: TargetProfile,
184    /// Desired optimization directions.
185    pub optimization_hints: Vec<OptimizationHint>,
186}
187
188/// Response from [`AiProvider::optimize`](crate::provider::AiProvider::optimize).
189#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
190pub struct OptimizeResponse {
191    /// Improved target-language code (same semantics as input).
192    pub optimized_code: String,
193    /// Confidence in the optimization (`0.0..=1.0`).
194    pub confidence: f64,
195    /// Short descriptions of each observable improvement.
196    pub improvements: Vec<String>,
197    /// Optional free-form reasoning.
198    pub reasoning: Option<String>,
199}
200
201// ─── Select (§10.8) ──────────────────────────────────────────────────────────
202
203/// A single option in a closed-set selection.
204#[derive(Debug, Clone, PartialEq, Eq)]
205pub struct SelectOption {
206    /// Stable identifier. Must be unique within a request's option set.
207    pub id: String,
208    /// Human-readable description shown to the model for discrimination.
209    pub description: String,
210}
211
212/// Context supplied alongside the option set for a `select()` call.
213///
214/// The recovery-context discipline of §10.8 applies: no AIR, no source,
215/// no call stack. This struct is the sanctioned surface for classification
216/// prompts.
217#[derive(Debug, Clone, Default, PartialEq, Eq)]
218pub struct SelectContext {
219    /// Error text, if the selection is triggered by a failure.
220    pub error: Option<String>,
221    /// Semantic annotations reaching the decision site
222    /// (`@context`, `@domain`, `@security`).
223    pub annotations: Vec<String>,
224    /// Recent similar decisions, bounded per §10.8 (10 items).
225    pub history: Vec<String>,
226    /// Free-form metadata (operation id, elapsed time, attempt count, ...).
227    pub metadata: HashMap<String, String>,
228}
229
230/// Input to [`AiProvider::select`](crate::provider::AiProvider::select).
231#[derive(Debug, Clone)]
232pub struct SelectRequest {
233    /// The closed set of options. `SelectResponse::selected_id` must be
234    /// one of these.
235    pub options: Vec<SelectOption>,
236    /// Selection context.
237    pub context: SelectContext,
238    /// Natural-language description of what is being selected.
239    pub rationale_prompt: String,
240}
241
242/// Response from [`AiProvider::select`](crate::provider::AiProvider::select).
243#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
244pub struct SelectResponse {
245    /// Identifier of the chosen option. MUST be a value present in the
246    /// request's option set — callers should verify with
247    /// [`crate::provider::validate_select_response`].
248    pub selected_id: String,
249    /// Confidence in the selection (`0.0..=1.0`).
250    pub confidence: f64,
251    /// Optional free-form reasoning.
252    pub reasoning: Option<String>,
253}
254
255#[cfg(test)]
256mod tests {
257    use super::*;
258
259    #[test]
260    fn target_profile_default_is_empty() {
261        let p = TargetProfile::default();
262        assert!(p.id.is_empty());
263        assert!(p.capabilities.is_empty());
264    }
265
266    #[test]
267    fn alternative_fields() {
268        let alt = Alternative {
269            label: "async-std".into(),
270            reasoning: Some("less ecosystem momentum".into()),
271            confidence: 0.3,
272        };
273        assert_eq!(alt.label, "async-std");
274        assert!(alt.confidence < 0.5);
275    }
276
277    #[test]
278    fn select_option_equality() {
279        let a = SelectOption {
280            id: "retry".into(),
281            description: "retry with exponential backoff".into(),
282        };
283        let b = SelectOption {
284            id: "retry".into(),
285            description: "retry with exponential backoff".into(),
286        };
287        assert_eq!(a, b);
288    }
289}
290
291// Confidence is expressed throughout this module as `f64` in the range
292// `0.0..=1.0`. See §17.4 of bock-spec.md — raw float, no wrapper.