use axum::extract::State;
use axum::response::IntoResponse;
use serde_json::json;
use super::pipeline::{
PipelineConfig, PipelineError, PipelineOutcome, PipelineRequest, resolve_web_scope_hint,
run_pipeline,
};
use super::{AgentMessageRequest, AppState};
pub async fn agent_message(
State(state): State<AppState>,
axum::Json(body): axum::Json<AgentMessageRequest>,
) -> Result<impl IntoResponse, PipelineError> {
tracing::info!(channel = "api", session_id = ?body.session_id, "Processing agent message");
let scope_hint = resolve_web_scope_hint(&state, &body).await?;
let request = PipelineRequest {
state: &state,
config: PipelineConfig::api(),
raw_content: &body.content,
session_id_hint: body.session_id.as_deref(),
scope_hint,
is_correction_turn: false,
channel_context: None,
content_parts: None,
};
let outcome = run_pipeline(request).await?;
let platform = body.channel.as_deref().unwrap_or("web").trim();
let format_for_client =
|text: &str| roboticus_channels::formatter::formatter_for(platform).format(text);
match outcome {
PipelineOutcome::Complete {
session_id,
user_message_id,
result,
} => Ok(axum::Json(json!({
"session_id": session_id,
"user_message_id": user_message_id,
"assistant_message_id": result.assistant_message_id,
"content": format_for_client(&result.content),
"selected_model": result.selected_model,
"model": result.model,
"model_shift_from": result.model_shift_from,
"cached": result.cached,
"tokens_saved": result.tokens_saved,
"tokens_in": result.tokens_in,
"tokens_out": result.tokens_out,
"cost": result.cost,
"react_turns": result.react_turns,
}))),
PipelineOutcome::SpecialistProposal { session_id, prompt } => Ok(axum::Json(json!({
"session_id": session_id,
"content": format_for_client(&prompt),
"decomposition": "requires_specialist_creation",
}))),
PipelineOutcome::StreamReady(_) => {
Err(PipelineError::Internal(
"unexpected streaming outcome on API endpoint".into(),
))
}
}
}