mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-08 22:21:45 +00:00
Rename fabro-types to fabro-api-types
Better reflects that this crate contains auto-generated types scoped to the API layer. Pure rename with no behavior change. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
75b5aa35b9
commit
d5152ed7a3
10 changed files with 130 additions and 120 deletions
|
|
@ -40,7 +40,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||
The OpenAPI spec at `docs/api-reference/fabro-api.yaml` is the source of truth for the fabro-api HTTP interface.
|
||||
|
||||
1. Edit `docs/api-reference/fabro-api.yaml`
|
||||
2. `cargo build -p fabro-types` — build.rs regenerates Rust types via typify
|
||||
2. `cargo build -p fabro-api-types` — build.rs regenerates Rust types via typify
|
||||
3. Write/update handler in `lib/crates/fabro-api/src/server.rs`, add route to `build_router()`
|
||||
4. `cargo nextest run -p fabro-api` — conformance test catches spec/router drift
|
||||
5. `cd lib/packages/fabro-api-client && bun run generate` — regenerates TypeScript Axios client
|
||||
|
|
@ -57,7 +57,7 @@ Fabro is an AI-powered workflow orchestration platform. Workflows are defined as
|
|||
- **fabro-exe** — SSH-based sandbox implementation (`ExeSandbox`)
|
||||
- **fabro-sprites** — Sprites VM sandbox implementation via `sprite` CLI
|
||||
- **fabro-llm** — Unified LLM client with providers: Anthropic, OpenAI, Gemini, OpenAI-compatible, plus retry/middleware/streaming
|
||||
- **fabro-types** — Auto-generated Rust types from OpenAPI spec (build.rs + typify)
|
||||
- **fabro-api-types** — Auto-generated Rust types from OpenAPI spec (build.rs + typify)
|
||||
- **fabro-github** — GitHub App auth (JWT signing, installation tokens, PR creation)
|
||||
- **fabro-db** — SQLite with WAL mode, schema migrations
|
||||
- **fabro-mcp** — Model Context Protocol client/server
|
||||
|
|
|
|||
32
Cargo.lock
generated
32
Cargo.lock
generated
|
|
@ -1265,6 +1265,7 @@ dependencies = [
|
|||
"clap",
|
||||
"dirs",
|
||||
"fabro-agent",
|
||||
"fabro-api-types",
|
||||
"fabro-config",
|
||||
"fabro-db",
|
||||
"fabro-github",
|
||||
|
|
@ -1275,7 +1276,6 @@ dependencies = [
|
|||
"fabro-model",
|
||||
"fabro-retro",
|
||||
"fabro-sandbox",
|
||||
"fabro-types",
|
||||
"fabro-util",
|
||||
"fabro-workflows",
|
||||
"futures-util",
|
||||
|
|
@ -1308,6 +1308,21 @@ dependencies = [
|
|||
"x509-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-api-types"
|
||||
version = "0.176.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"prettyplease",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"syn",
|
||||
"typify",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-cli"
|
||||
version = "0.176.2"
|
||||
|
|
@ -1693,21 +1708,6 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-types"
|
||||
version = "0.176.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"prettyplease",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"syn",
|
||||
"typify",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fabro-util"
|
||||
version = "0.176.2"
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ The generated client includes a typed API class for each endpoint group: `RunsAp
|
|||
|
||||
## Rust (Types Only)
|
||||
|
||||
The `fabro-types` crate generates Rust structs and enums from the OpenAPI component schemas at compile time using [typify](https://github.com/oxidecomputer/typify). This provides type-safe representations of all API models but does not include an HTTP client.
|
||||
The `fabro-api-types` crate generates Rust structs and enums from the OpenAPI component schemas at compile time using [typify](https://github.com/oxidecomputer/typify). This provides type-safe representations of all API models but does not include an HTTP client.
|
||||
|
||||
### How It Works
|
||||
|
||||
A `build.rs` script reads `docs/api-reference/fabro-api.yaml`, extracts `components/schemas`, and feeds them to typify. The generated code is written to `OUT_DIR` and included via:
|
||||
|
||||
```rust
|
||||
// lib/crates/fabro-types/src/lib.rs
|
||||
// lib/crates/fabro-api-types/src/lib.rs
|
||||
include!(concat!(env!("OUT_DIR"), "/openapi_types.rs"));
|
||||
```
|
||||
|
||||
|
|
@ -52,13 +52,13 @@ include!(concat!(env!("OUT_DIR"), "/openapi_types.rs"));
|
|||
The types are regenerated automatically on every `cargo build` when the OpenAPI spec changes:
|
||||
|
||||
```bash
|
||||
cargo build -p fabro-types
|
||||
cargo build -p fabro-api-types
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```rust
|
||||
use fabro_types::RunListItem;
|
||||
use fabro_api_types::RunListItem;
|
||||
```
|
||||
|
||||
All generated types derive `serde::Deserialize` and `serde::Serialize`, so they work directly with any Rust HTTP client for request and response parsing.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
[package]
|
||||
name = "fabro-types"
|
||||
name = "fabro-api-types"
|
||||
edition.workspace = true
|
||||
version.workspace = true
|
||||
license.workspace = true
|
||||
|
|
@ -22,7 +22,7 @@ fabro-model = { path = "../fabro-model" }
|
|||
fabro-retro = { path = "../fabro-retro" }
|
||||
fabro-util = { path = "../fabro-util" }
|
||||
fabro-db = { path = "../fabro-db" }
|
||||
fabro-types = { path = "../fabro-types" }
|
||||
fabro-api-types = { path = "../fabro-api-types" }
|
||||
chrono.workspace = true
|
||||
futures-util.workspace = true
|
||||
axum = "0.8"
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ pub struct RetroListParams {
|
|||
#[serde(rename = "page[offset]", default)]
|
||||
offset: u32,
|
||||
workflow: Option<String>,
|
||||
smoothness: Option<fabro_types::SmoothnessRating>,
|
||||
smoothness: Option<fabro_api_types::SmoothnessRating>,
|
||||
}
|
||||
|
||||
fn paginated_response<T: serde::Serialize>(
|
||||
|
|
@ -140,9 +140,9 @@ pub async fn get_run_status(
|
|||
match runs::list_items().into_iter().find(|r| r.id == id) {
|
||||
Some(item) => (
|
||||
StatusCode::OK,
|
||||
Json(fabro_types::RunStatusResponse {
|
||||
Json(fabro_api_types::RunStatusResponse {
|
||||
id: id.clone(),
|
||||
status: fabro_types::RunStatus::Running,
|
||||
status: fabro_api_types::RunStatus::Running,
|
||||
error: None,
|
||||
queue_position: None,
|
||||
created_at: item.created_at,
|
||||
|
|
@ -464,11 +464,11 @@ pub async fn session_events_stub(
|
|||
|
||||
for turn in &session.turns {
|
||||
let (event_type, data) = match turn {
|
||||
fabro_types::SessionTurn::UserTurn(_) => continue,
|
||||
fabro_types::SessionTurn::AssistantTurn(t) => {
|
||||
fabro_api_types::SessionTurn::UserTurn(_) => continue,
|
||||
fabro_api_types::SessionTurn::AssistantTurn(t) => {
|
||||
("assistant_turn", serde_json::to_string(t).unwrap())
|
||||
}
|
||||
fabro_types::SessionTurn::ToolTurn(t) => {
|
||||
fabro_api_types::SessionTurn::ToolTurn(t) => {
|
||||
("tool_turn", serde_json::to_string(t).unwrap())
|
||||
}
|
||||
};
|
||||
|
|
@ -614,7 +614,7 @@ fn ts(s: &str) -> DateTime<Utc> {
|
|||
|
||||
mod runs {
|
||||
use super::ts;
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
|
||||
pub fn list_items() -> Vec<RunListItem> {
|
||||
vec![
|
||||
|
|
@ -1235,7 +1235,7 @@ mod runs {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn verifications() -> Vec<fabro_types::RunVerification> {
|
||||
pub fn verifications() -> Vec<fabro_api_types::RunVerification> {
|
||||
super::verifications::run_verifications()
|
||||
}
|
||||
|
||||
|
|
@ -1336,7 +1336,7 @@ mod runs {
|
|||
}
|
||||
|
||||
mod usage {
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
|
||||
pub fn aggregate() -> AggregateUsage {
|
||||
AggregateUsage {
|
||||
|
|
@ -1388,7 +1388,7 @@ mod usage {
|
|||
|
||||
mod workflows {
|
||||
use super::ts;
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
|
||||
pub fn list_items() -> Vec<WorkflowListItem> {
|
||||
vec![
|
||||
|
|
@ -1768,7 +1768,7 @@ mod workflows {
|
|||
|
||||
mod verifications {
|
||||
use super::ts;
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
|
||||
// ── Category definitions (name, question, controls) ─────────────────
|
||||
|
||||
|
|
@ -2611,7 +2611,7 @@ mod verifications {
|
|||
|
||||
mod signoffs {
|
||||
use super::ts;
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
|
||||
struct SignoffDef {
|
||||
id: &'static str,
|
||||
|
|
@ -2726,7 +2726,7 @@ mod signoffs {
|
|||
|
||||
mod retros {
|
||||
use super::ts;
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn stage(
|
||||
|
|
@ -3060,7 +3060,7 @@ mod retros {
|
|||
|
||||
mod sessions {
|
||||
use super::ts;
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
use uuid::Uuid;
|
||||
|
||||
fn uid(n: u128) -> Uuid {
|
||||
|
|
@ -3202,7 +3202,7 @@ mod sessions {
|
|||
|
||||
mod insights {
|
||||
use super::ts;
|
||||
use fabro_types::*;
|
||||
use fabro_api_types::*;
|
||||
|
||||
pub fn saved_queries() -> Vec<SavedQuery> {
|
||||
vec![
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ use fabro_workflows::records::Checkpoint;
|
|||
use fabro_workflows::run_options::LifecycleOptions;
|
||||
use fabro_workflows::run_options::RunOptions;
|
||||
|
||||
pub use fabro_types::{
|
||||
pub use fabro_api_types::{
|
||||
ApiQuestion, ApiQuestionOption, PaginatedRunList, PaginationMeta,
|
||||
QuestionType as ApiQuestionType, RunStatus, RunStatusResponse, StartRunRequest,
|
||||
SubmitAnswerRequest,
|
||||
|
|
@ -356,21 +356,21 @@ async fn get_aggregate_usage(
|
|||
.aggregate_usage
|
||||
.lock()
|
||||
.expect("aggregate_usage lock poisoned");
|
||||
let by_model: Vec<fabro_types::UsageByModel> = agg
|
||||
let by_model: Vec<fabro_api_types::UsageByModel> = agg
|
||||
.by_model
|
||||
.iter()
|
||||
.map(|(model, totals)| fabro_types::UsageByModel {
|
||||
model: fabro_types::ModelReference { id: model.clone() },
|
||||
.map(|(model, totals)| fabro_api_types::UsageByModel {
|
||||
model: fabro_api_types::ModelReference { id: model.clone() },
|
||||
stages: totals.stages,
|
||||
usage: fabro_types::TokenUsage {
|
||||
usage: fabro_api_types::TokenUsage {
|
||||
input_tokens: totals.input_tokens,
|
||||
output_tokens: totals.output_tokens,
|
||||
cost: totals.cost,
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
let response = fabro_types::AggregateUsage {
|
||||
totals: fabro_types::AggregateUsageTotals {
|
||||
let response = fabro_api_types::AggregateUsage {
|
||||
totals: fabro_api_types::AggregateUsageTotals {
|
||||
runs: agg.total_runs,
|
||||
input_tokens: by_model.iter().map(|m| m.usage.input_tokens).sum(),
|
||||
output_tokens: by_model.iter().map(|m| m.usage.output_tokens).sum(),
|
||||
|
|
@ -476,9 +476,12 @@ async fn list_runs(
|
|||
.map(|(id, managed_run)| RunStatusResponse {
|
||||
id: id.clone(),
|
||||
status: managed_run.status,
|
||||
error: managed_run.error.as_ref().map(|msg| fabro_types::RunError {
|
||||
message: msg.clone(),
|
||||
}),
|
||||
error: managed_run
|
||||
.error
|
||||
.as_ref()
|
||||
.map(|msg| fabro_api_types::RunError {
|
||||
message: msg.clone(),
|
||||
}),
|
||||
queue_position: queue_positions.get(id).copied(),
|
||||
created_at: managed_run.created_at,
|
||||
})
|
||||
|
|
@ -891,9 +894,12 @@ async fn get_run_status(
|
|||
Json(RunStatusResponse {
|
||||
id: id.clone(),
|
||||
status: managed_run.status,
|
||||
error: managed_run.error.as_ref().map(|msg| fabro_types::RunError {
|
||||
message: msg.clone(),
|
||||
}),
|
||||
error: managed_run
|
||||
.error
|
||||
.as_ref()
|
||||
.map(|msg| fabro_api_types::RunError {
|
||||
message: msg.clone(),
|
||||
}),
|
||||
created_at: managed_run.created_at,
|
||||
queue_position,
|
||||
}),
|
||||
|
|
@ -1232,13 +1238,13 @@ fn finish_reason_to_api_stop_reason(reason: &fabro_llm::types::FinishReason) ->
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_api_message(msg: &fabro_types::CompletionMessage) -> fabro_llm::types::Message {
|
||||
fn convert_api_message(msg: &fabro_api_types::CompletionMessage) -> fabro_llm::types::Message {
|
||||
let role = match msg.role {
|
||||
fabro_types::CompletionMessageRole::System => fabro_llm::types::Role::System,
|
||||
fabro_types::CompletionMessageRole::User => fabro_llm::types::Role::User,
|
||||
fabro_types::CompletionMessageRole::Assistant => fabro_llm::types::Role::Assistant,
|
||||
fabro_types::CompletionMessageRole::Tool => fabro_llm::types::Role::Tool,
|
||||
fabro_types::CompletionMessageRole::Developer => fabro_llm::types::Role::Developer,
|
||||
fabro_api_types::CompletionMessageRole::System => fabro_llm::types::Role::System,
|
||||
fabro_api_types::CompletionMessageRole::User => fabro_llm::types::Role::User,
|
||||
fabro_api_types::CompletionMessageRole::Assistant => fabro_llm::types::Role::Assistant,
|
||||
fabro_api_types::CompletionMessageRole::Tool => fabro_llm::types::Role::Tool,
|
||||
fabro_api_types::CompletionMessageRole::Developer => fabro_llm::types::Role::Developer,
|
||||
};
|
||||
let content: Vec<fabro_llm::types::ContentPart> = msg
|
||||
.content
|
||||
|
|
@ -1256,15 +1262,15 @@ fn convert_api_message(msg: &fabro_types::CompletionMessage) -> fabro_llm::types
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_llm_message(msg: &fabro_llm::types::Message) -> fabro_types::CompletionMessage {
|
||||
fn convert_llm_message(msg: &fabro_llm::types::Message) -> fabro_api_types::CompletionMessage {
|
||||
let role = match msg.role {
|
||||
fabro_llm::types::Role::System => fabro_types::CompletionMessageRole::System,
|
||||
fabro_llm::types::Role::User => fabro_types::CompletionMessageRole::User,
|
||||
fabro_llm::types::Role::Assistant => fabro_types::CompletionMessageRole::Assistant,
|
||||
fabro_llm::types::Role::Tool => fabro_types::CompletionMessageRole::Tool,
|
||||
fabro_llm::types::Role::Developer => fabro_types::CompletionMessageRole::Developer,
|
||||
fabro_llm::types::Role::System => fabro_api_types::CompletionMessageRole::System,
|
||||
fabro_llm::types::Role::User => fabro_api_types::CompletionMessageRole::User,
|
||||
fabro_llm::types::Role::Assistant => fabro_api_types::CompletionMessageRole::Assistant,
|
||||
fabro_llm::types::Role::Tool => fabro_api_types::CompletionMessageRole::Tool,
|
||||
fabro_llm::types::Role::Developer => fabro_api_types::CompletionMessageRole::Developer,
|
||||
};
|
||||
let content: Vec<fabro_types::CompletionContentPart> = msg
|
||||
let content: Vec<fabro_api_types::CompletionContentPart> = msg
|
||||
.content
|
||||
.iter()
|
||||
.filter_map(|part| {
|
||||
|
|
@ -1272,7 +1278,7 @@ fn convert_llm_message(msg: &fabro_llm::types::Message) -> fabro_types::Completi
|
|||
serde_json::from_value(json).ok()
|
||||
})
|
||||
.collect();
|
||||
fabro_types::CompletionMessage {
|
||||
fabro_api_types::CompletionMessage {
|
||||
role,
|
||||
content,
|
||||
name: msg.name.clone(),
|
||||
|
|
@ -1283,7 +1289,7 @@ fn convert_llm_message(msg: &fabro_llm::types::Message) -> fabro_types::Completi
|
|||
async fn create_completion(
|
||||
_auth: AuthenticatedService,
|
||||
State(state): State<Arc<AppState>>,
|
||||
Json(req): Json<fabro_types::CreateCompletionRequest>,
|
||||
Json(req): Json<fabro_api_types::CreateCompletionRequest>,
|
||||
) -> Response {
|
||||
// Resolve model
|
||||
let model_id = req.model.unwrap_or_else(|| {
|
||||
|
|
@ -1330,12 +1336,12 @@ async fn create_completion(
|
|||
// Convert tool_choice
|
||||
let tool_choice: Option<fabro_llm::types::ToolChoice> =
|
||||
req.tool_choice.map(|tc| match tc.mode {
|
||||
fabro_types::CompletionToolChoiceMode::Auto => fabro_llm::types::ToolChoice::Auto,
|
||||
fabro_types::CompletionToolChoiceMode::None => fabro_llm::types::ToolChoice::None,
|
||||
fabro_types::CompletionToolChoiceMode::Required => {
|
||||
fabro_api_types::CompletionToolChoiceMode::Auto => fabro_llm::types::ToolChoice::Auto,
|
||||
fabro_api_types::CompletionToolChoiceMode::None => fabro_llm::types::ToolChoice::None,
|
||||
fabro_api_types::CompletionToolChoiceMode::Required => {
|
||||
fabro_llm::types::ToolChoice::Required
|
||||
}
|
||||
fabro_types::CompletionToolChoiceMode::Named => {
|
||||
fabro_api_types::CompletionToolChoiceMode::Named => {
|
||||
fabro_llm::types::ToolChoice::named(tc.tool_name.unwrap_or_default())
|
||||
}
|
||||
});
|
||||
|
|
@ -1390,18 +1396,18 @@ async fn create_completion(
|
|||
)]);
|
||||
return Sse::new(sse_stream).into_response();
|
||||
}
|
||||
let empty_msg = fabro_types::CompletionMessage {
|
||||
role: fabro_types::CompletionMessageRole::Assistant,
|
||||
let empty_msg = fabro_api_types::CompletionMessage {
|
||||
role: fabro_api_types::CompletionMessageRole::Assistant,
|
||||
content: vec![],
|
||||
name: None,
|
||||
tool_call_id: None,
|
||||
};
|
||||
return Json(fabro_types::CompletionResponse {
|
||||
return Json(fabro_api_types::CompletionResponse {
|
||||
id: msg_id,
|
||||
model: model_id,
|
||||
message: empty_msg,
|
||||
stop_reason: "end_turn".to_string(),
|
||||
usage: fabro_types::CompletionUsage {
|
||||
usage: fabro_api_types::CompletionUsage {
|
||||
input_tokens: 0,
|
||||
output_tokens: 0,
|
||||
},
|
||||
|
|
@ -1493,12 +1499,12 @@ async fn create_completion(
|
|||
params = params.top_p(top_p);
|
||||
}
|
||||
match fabro_llm::generate::generate_object(params, schema).await {
|
||||
Ok(result) => Json(fabro_types::CompletionResponse {
|
||||
Ok(result) => Json(fabro_api_types::CompletionResponse {
|
||||
id: msg_id,
|
||||
model: model_id,
|
||||
message: convert_llm_message(&result.response.message),
|
||||
stop_reason: finish_reason_to_api_stop_reason(&result.finish_reason),
|
||||
usage: fabro_types::CompletionUsage {
|
||||
usage: fabro_api_types::CompletionUsage {
|
||||
input_tokens: result.usage.input_tokens,
|
||||
output_tokens: result.usage.output_tokens,
|
||||
},
|
||||
|
|
@ -1510,12 +1516,12 @@ async fn create_completion(
|
|||
}
|
||||
} else {
|
||||
match client.complete(&request).await {
|
||||
Ok(response) => Json(fabro_types::CompletionResponse {
|
||||
Ok(response) => Json(fabro_api_types::CompletionResponse {
|
||||
id: response.id,
|
||||
model: response.model,
|
||||
message: convert_llm_message(&response.message),
|
||||
stop_reason: finish_reason_to_api_stop_reason(&response.finish_reason),
|
||||
usage: fabro_types::CompletionUsage {
|
||||
usage: fabro_api_types::CompletionUsage {
|
||||
input_tokens: response.usage.input_tokens,
|
||||
output_tokens: response.usage.output_tokens,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ pub struct SessionState {
|
|||
pub model_id: String,
|
||||
pub model_provider: Option<String>,
|
||||
pub system_prompt: Option<String>,
|
||||
pub turns: Vec<fabro_types::SessionTurn>,
|
||||
pub turns: Vec<fabro_api_types::SessionTurn>,
|
||||
pub created_at: chrono::DateTime<chrono::Utc>,
|
||||
pub updated_at: chrono::DateTime<chrono::Utc>,
|
||||
pub event_tx: broadcast::Sender<SessionEvent>,
|
||||
|
|
@ -72,17 +72,17 @@ fn resolve_model(model_arg: Option<String>) -> (String, Option<String>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn turns_to_messages(turns: &[fabro_types::SessionTurn]) -> Vec<fabro_llm::types::Message> {
|
||||
fn turns_to_messages(turns: &[fabro_api_types::SessionTurn]) -> Vec<fabro_llm::types::Message> {
|
||||
turns
|
||||
.iter()
|
||||
.filter_map(|turn| match turn {
|
||||
fabro_types::SessionTurn::UserTurn(t) => {
|
||||
fabro_api_types::SessionTurn::UserTurn(t) => {
|
||||
Some(fabro_llm::types::Message::user(&t.content))
|
||||
}
|
||||
fabro_types::SessionTurn::AssistantTurn(t) => {
|
||||
fabro_api_types::SessionTurn::AssistantTurn(t) => {
|
||||
Some(fabro_llm::types::Message::assistant(&t.content))
|
||||
}
|
||||
fabro_types::SessionTurn::ToolTurn(_) => None,
|
||||
fabro_api_types::SessionTurn::ToolTurn(_) => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
@ -120,13 +120,15 @@ fn spawn_generation(store: SessionStore, session_id: uuid::Uuid, dry_run: bool,
|
|||
{
|
||||
let mut store = store.write().expect("session store lock poisoned");
|
||||
if let Some(session) = store.get_mut(&session_id) {
|
||||
session.turns.push(fabro_types::SessionTurn::AssistantTurn(
|
||||
fabro_types::AssistantTurn {
|
||||
kind: fabro_types::AssistantTurnKind::Assistant,
|
||||
content,
|
||||
created_at: now,
|
||||
},
|
||||
));
|
||||
session
|
||||
.turns
|
||||
.push(fabro_api_types::SessionTurn::AssistantTurn(
|
||||
fabro_api_types::AssistantTurn {
|
||||
kind: fabro_api_types::AssistantTurnKind::Assistant,
|
||||
content,
|
||||
created_at: now,
|
||||
},
|
||||
));
|
||||
session.updated_at = now;
|
||||
}
|
||||
}
|
||||
|
|
@ -187,13 +189,15 @@ fn spawn_generation(store: SessionStore, session_id: uuid::Uuid, dry_run: bool,
|
|||
{
|
||||
let mut store = store.write().expect("session store lock poisoned");
|
||||
if let Some(session) = store.get_mut(&session_id) {
|
||||
session.turns.push(fabro_types::SessionTurn::AssistantTurn(
|
||||
fabro_types::AssistantTurn {
|
||||
kind: fabro_types::AssistantTurnKind::Assistant,
|
||||
content: full_text,
|
||||
created_at: now,
|
||||
},
|
||||
));
|
||||
session
|
||||
.turns
|
||||
.push(fabro_api_types::SessionTurn::AssistantTurn(
|
||||
fabro_api_types::AssistantTurn {
|
||||
kind: fabro_api_types::AssistantTurnKind::Assistant,
|
||||
content: full_text,
|
||||
created_at: now,
|
||||
},
|
||||
));
|
||||
session.updated_at = now;
|
||||
}
|
||||
}
|
||||
|
|
@ -204,7 +208,7 @@ fn spawn_generation(store: SessionStore, session_id: uuid::Uuid, dry_run: bool,
|
|||
pub async fn create_session(
|
||||
_auth: AuthenticatedService,
|
||||
State(state): State<Arc<crate::server::AppState>>,
|
||||
Json(req): Json<fabro_types::CreateSessionRequest>,
|
||||
Json(req): Json<fabro_api_types::CreateSessionRequest>,
|
||||
) -> Response {
|
||||
let (model_id, model_provider) = resolve_model(req.model);
|
||||
let now = chrono::Utc::now();
|
||||
|
|
@ -214,8 +218,8 @@ pub async fn create_session(
|
|||
let (event_tx, _) = broadcast::channel(256);
|
||||
let generation_seq = Arc::new(AtomicU64::new(1));
|
||||
|
||||
let user_turn = fabro_types::SessionTurn::UserTurn(fabro_types::UserTurn {
|
||||
kind: fabro_types::UserTurnKind::User,
|
||||
let user_turn = fabro_api_types::SessionTurn::UserTurn(fabro_api_types::UserTurn {
|
||||
kind: fabro_api_types::UserTurnKind::User,
|
||||
content: req.content,
|
||||
created_at: now,
|
||||
});
|
||||
|
|
@ -242,10 +246,10 @@ pub async fn create_session(
|
|||
|
||||
(
|
||||
StatusCode::CREATED,
|
||||
Json(fabro_types::CreateSessionResponse {
|
||||
Json(fabro_api_types::CreateSessionResponse {
|
||||
id: session_id,
|
||||
title,
|
||||
model: fabro_types::ModelReference { id: model_id },
|
||||
model: fabro_api_types::ModelReference { id: model_id },
|
||||
created_at: now,
|
||||
updated_at: now,
|
||||
}),
|
||||
|
|
@ -262,10 +266,10 @@ pub async fn retrieve_session(
|
|||
match store.get(&id) {
|
||||
Some(session) => (
|
||||
StatusCode::OK,
|
||||
Json(fabro_types::SessionDetail {
|
||||
Json(fabro_api_types::SessionDetail {
|
||||
id: session.id,
|
||||
title: session.title.clone(),
|
||||
model: fabro_types::ModelReference {
|
||||
model: fabro_api_types::ModelReference {
|
||||
id: session.model_id.clone(),
|
||||
},
|
||||
created_at: session.created_at,
|
||||
|
|
@ -282,20 +286,20 @@ pub async fn send_message(
|
|||
_auth: AuthenticatedService,
|
||||
State(state): State<Arc<crate::server::AppState>>,
|
||||
Path(id): Path<uuid::Uuid>,
|
||||
Json(req): Json<fabro_types::SendMessageRequest>,
|
||||
Json(req): Json<fabro_api_types::SendMessageRequest>,
|
||||
) -> Response {
|
||||
let seq = {
|
||||
let mut store = state.sessions.write().expect("session store lock poisoned");
|
||||
match store.get_mut(&id) {
|
||||
Some(session) => {
|
||||
let now = chrono::Utc::now();
|
||||
session
|
||||
.turns
|
||||
.push(fabro_types::SessionTurn::UserTurn(fabro_types::UserTurn {
|
||||
kind: fabro_types::UserTurnKind::User,
|
||||
session.turns.push(fabro_api_types::SessionTurn::UserTurn(
|
||||
fabro_api_types::UserTurn {
|
||||
kind: fabro_api_types::UserTurnKind::User,
|
||||
content: req.content,
|
||||
created_at: now,
|
||||
}));
|
||||
},
|
||||
));
|
||||
session.updated_at = now;
|
||||
session.generation_seq.fetch_add(1, Ordering::Relaxed) + 1
|
||||
}
|
||||
|
|
@ -307,7 +311,7 @@ pub async fn send_message(
|
|||
|
||||
(
|
||||
StatusCode::ACCEPTED,
|
||||
Json(fabro_types::SendMessageResponse { accepted: true }),
|
||||
Json(fabro_api_types::SendMessageResponse { accepted: true }),
|
||||
)
|
||||
.into_response()
|
||||
}
|
||||
|
|
@ -373,16 +377,16 @@ pub async fn list_sessions(
|
|||
let limit = pagination.limit.clamp(1, 100) as usize;
|
||||
let offset = pagination.offset as usize;
|
||||
|
||||
let mut items: Vec<fabro_types::SessionListItem> = store
|
||||
let mut items: Vec<fabro_api_types::SessionListItem> = store
|
||||
.values()
|
||||
.map(|session| {
|
||||
let last_message_preview = session
|
||||
.turns
|
||||
.last()
|
||||
.map(|t| match t {
|
||||
fabro_types::SessionTurn::UserTurn(u) => u.content.clone(),
|
||||
fabro_types::SessionTurn::AssistantTurn(a) => a.content.clone(),
|
||||
fabro_types::SessionTurn::ToolTurn(_) => String::new(),
|
||||
fabro_api_types::SessionTurn::UserTurn(u) => u.content.clone(),
|
||||
fabro_api_types::SessionTurn::AssistantTurn(a) => a.content.clone(),
|
||||
fabro_api_types::SessionTurn::ToolTurn(_) => String::new(),
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let preview = if last_message_preview.len() > 100 {
|
||||
|
|
@ -390,10 +394,10 @@ pub async fn list_sessions(
|
|||
} else {
|
||||
last_message_preview
|
||||
};
|
||||
fabro_types::SessionListItem {
|
||||
fabro_api_types::SessionListItem {
|
||||
id: session.id,
|
||||
title: session.title.clone(),
|
||||
model: fabro_types::ModelReference {
|
||||
model: fabro_api_types::ModelReference {
|
||||
id: session.model_id.clone(),
|
||||
},
|
||||
last_message_preview: preview,
|
||||
|
|
@ -412,9 +416,9 @@ pub async fn list_sessions(
|
|||
|
||||
(
|
||||
StatusCode::OK,
|
||||
Json(fabro_types::PaginatedSessionList {
|
||||
Json(fabro_api_types::PaginatedSessionList {
|
||||
data,
|
||||
meta: fabro_types::PaginationMeta { has_more },
|
||||
meta: fabro_api_types::PaginationMeta { has_more },
|
||||
}),
|
||||
)
|
||||
.into_response()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue