aion-server 0.30.0

Aion workflow server library: HTTP, gRPC, WebSocket, and worker endpoints. Run it with the `aion` binary from the aion-cli crate.
Documentation
//! `GET /assistant` — what assistant surface this server carries.
//!
//! The ops console is served from the binary at `/`; this is the same doctrine
//! for the assistant. The answer is about a SESSION surface, not about a
//! document: which agent harnesses this build ships and whether this machine
//! can run each one, what tools a session's agent is handed, whether a session
//! can be opened at all, and what the reading caller is authorized to do.
//!
//! # Authorization
//!
//! Behind the same [`HttpCaller`] extractor as every data route, for the reason
//! `/build` is: the description carries this deployment's own harness
//! availability and this caller's grant standing, which is deployment state,
//! not public information.
//!
//! # 🔴 Probe the BODY, never the status
//!
//! The ops-console SPA catch-all answers `200 text/html` for any unmatched
//! path, so a binary WITHOUT this route still answers 200 here. A probe that
//! reads only the status code cannot tell an assistant-carrying build from one
//! without it; read the content type and the body.

use aion_proto::WireError;
use axum::{Json, extract::State};

use super::auth::HttpCaller;
use super::error::HttpWireError;
use crate::ServerState;
use crate::assistant::{AssistantDescriptor, describe};

/// `GET /assistant`.
pub(crate) async fn assistant_descriptor(
    State(state): State<ServerState>,
    HttpCaller(caller): HttpCaller,
) -> Result<Json<AssistantDescriptor>, HttpWireError> {
    // The description is read for THIS caller: its grant rows report what this
    // request's own resolved identity holds, and its `default_harness` is this
    // caller's own last pick — never a deployment-wide answer.
    let described = describe(state.assistant_sessions(), &caller)
        .await
        .map_err(|error| {
            HttpWireError(
                WireError::backend(format!(
                    "the built-in assistant could not be described: {error}"
                ))
                .with_error_type("AssistantDescriptionFailed"),
            )
        })?;
    Ok(Json(described))
}

#[cfg(test)]
#[path = "assistant_tests.rs"]
mod assistant_tests;