diff options
| author | soryu <soryu@soryu.co> | 2026-01-11 05:52:14 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-15 00:21:16 +0000 |
| commit | 87044a747b47bd83249d61a45842c7f7b2eae56d (patch) | |
| tree | ef2000ce79ffcc2723ef841acef5aa1deb1d5378 /makima/src/server/handlers/templates.rs | |
| parent | 077820c4167c168072d217a1b01df840463a12a8 (diff) | |
| download | soryu-87044a747b47bd83249d61a45842c7f7b2eae56d.tar.gz soryu-87044a747b47bd83249d61a45842c7f7b2eae56d.zip | |
Contract system
Diffstat (limited to 'makima/src/server/handlers/templates.rs')
| -rw-r--r-- | makima/src/server/handlers/templates.rs | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/makima/src/server/handlers/templates.rs b/makima/src/server/handlers/templates.rs new file mode 100644 index 0000000..868d5b4 --- /dev/null +++ b/makima/src/server/handlers/templates.rs @@ -0,0 +1,107 @@ +//! Templates API handler. + +use axum::{extract::Query, http::StatusCode, response::IntoResponse, Json}; +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +use crate::llm::templates; + +/// Query parameters for listing templates +#[derive(Debug, Deserialize, ToSchema)] +pub struct ListTemplatesQuery { + /// Filter by contract phase (research, specify, plan, execute, review) + pub phase: Option<String>, +} + +/// Template summary for API response +#[derive(Debug, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct TemplateSummary { + /// Template identifier + pub id: String, + /// Display name + pub name: String, + /// Contract phase this template is designed for + pub phase: String, + /// Brief description + pub description: String, + /// Number of body elements in the template + pub element_count: usize, +} + +/// Response for listing templates +#[derive(Debug, Serialize, ToSchema)] +pub struct ListTemplatesResponse { + pub templates: Vec<TemplateSummary>, +} + +/// List available file templates +#[utoipa::path( + get, + path = "/api/v1/templates", + params( + ("phase" = Option<String>, Query, description = "Filter by contract phase") + ), + responses( + (status = 200, description = "Templates retrieved successfully", body = ListTemplatesResponse) + ), + tag = "templates" +)] +pub async fn list_templates( + Query(query): Query<ListTemplatesQuery>, +) -> impl IntoResponse { + let template_list = match query.phase.as_deref() { + Some(phase) => templates::templates_for_phase(phase), + None => templates::all_templates(), + }; + + let summaries: Vec<TemplateSummary> = template_list + .iter() + .map(|t| TemplateSummary { + id: t.id.clone(), + name: t.name.clone(), + phase: t.phase.clone(), + description: t.description.clone(), + element_count: t.suggested_body.len(), + }) + .collect(); + + ( + StatusCode::OK, + Json(ListTemplatesResponse { + templates: summaries, + }), + ) + .into_response() +} + +/// Get a specific template by ID +#[utoipa::path( + get, + path = "/api/v1/templates/{id}", + params( + ("id" = String, Path, description = "Template ID") + ), + responses( + (status = 200, description = "Template retrieved successfully", body = templates::FileTemplate), + (status = 404, description = "Template not found") + ), + tag = "templates" +)] +pub async fn get_template( + axum::extract::Path(id): axum::extract::Path<String>, +) -> impl IntoResponse { + let all = templates::all_templates(); + let template = all.into_iter().find(|t| t.id == id); + + match template { + Some(t) => (StatusCode::OK, Json(serde_json::json!(t))).into_response(), + None => ( + StatusCode::NOT_FOUND, + Json(serde_json::json!({ + "error": format!("Template '{}' not found", id) + })), + ) + .into_response(), + } +} |
