zeph-acp 0.20.0

ACP (Agent Client Protocol) server for IDE embedding
Documentation
// SPDX-FileCopyrightText: 2026 Andrei G <bug-ops>
// SPDX-License-Identifier: MIT OR Apache-2.0

//! ACP discovery manifest endpoints.
//!
//! These endpoints are **always public** (not behind `BearerAuthLayer`) so that
//! IDE extensions and ACP Registry tooling can discover the server without a token.
//!
//! | Endpoint | Purpose |
//! |----------|---------|
//! | `GET /.well-known/acp.json` | ACP transport discovery manifest |
//! | `GET /agent.json` | Agent identity manifest for ACP Registry |

use agent_client_protocol as acp;
use axum::Json;
use axum::extract::State;
use axum::response::IntoResponse;
use serde_json::{Value, json};

use crate::transport::http::AcpHttpState;

/// `GET /.well-known/acp.json` — publicly accessible agent discovery manifest.
///
/// Returns a JSON document describing the agent's identity, supported transports,
/// and authentication requirements. This endpoint is never behind auth middleware.
pub async fn discovery_handler(State(state): State<AcpHttpState>) -> impl IntoResponse {
    let auth = if state.server_config.auth_bearer_token.is_some() {
        json!({ "type": "bearer" })
    } else {
        Value::Null
    };

    let manifest = json!({
        "name": state.server_config.agent_name,
        "version": state.server_config.agent_version,
        "protocol": "acp",
        "protocol_version": acp::schema::ProtocolVersion::LATEST,
        "transports": {
            "http_sse": { "url": "/acp" },
            "websocket": { "url": "/acp/ws" },
            "health": { "url": "/health" }
        },
        "authentication": auth,
        "readiness": {
            "stdio_notification": "zeph/ready",
            "http_health_endpoint": "/health"
        }
    });

    Json(manifest)
}

/// `GET /agent.json` — machine-readable agent identity manifest for ACP Registry discovery.
///
/// Returns static agent metadata: identifier, display name, version, description, and
/// distribution targets. This endpoint is never behind auth middleware.
pub async fn agent_json_handler(State(state): State<AcpHttpState>) -> impl IntoResponse {
    // `id` and `description` are fixed software-identity values for the Zeph project (not
    // deployment-configurable); `name` and `version` are deployment-specific from server config.
    let manifest = json!({
        "id": "zeph",
        "name": state.server_config.agent_name,
        "version": state.server_config.agent_version,
        "description": "Lightweight Rust AI agent with hybrid inference, semantic memory, and multi-channel I/O",
        "distribution": {
            "type": "binary",
            "platforms": ["linux-x64", "darwin-arm64", "darwin-x64"]
        }
    });

    Json(manifest)
}