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.