Skip to main content

serve/
serve.rs

1//! Serve the bridge over HTTP with the System One compatible surface.
2//!
3//! ```bash
4//! export JEV_BRIDGE_UPSTREAM_URL=http://127.0.0.1:8080/v1
5//! export JEV_BRIDGE_UPSTREAM_KEY=...      # only if the server requires it
6//! export JEV_BRIDGE_API_KEY=...           # optional, for clients of this service
7//! cargo run --example serve
8//! ```
9//!
10//! Then:
11//!
12//! ```bash
13//! curl http://127.0.0.1:8100/health
14//! curl http://127.0.0.1:8100/v1/systemone \
15//!   -H 'Content-Type: application/json' \
16//!   -d '{"model":"example-bridge","state":"I was charged twice.",
17//!        "questions":{"queue":{"type":"choice","criteria":{"billing":"Refunds","sales":"Pricing"}}}}'
18//! ```
19
20use std::sync::Arc;
21
22use anyhow::{Context, Result};
23use serde_json::json;
24
25use jev_bridge::server::{router, AppState, Bridge, BridgeConfig};
26
27const ADDRESS: &str = "127.0.0.1:8100";
28
29#[tokio::main]
30async fn main() -> Result<()> {
31    let openai_base = std::env::var("JEV_BRIDGE_UPSTREAM_URL")
32        .unwrap_or_else(|_| "http://127.0.0.1:8080/v1".to_string());
33    let native_base = std::env::var("JEV_BRIDGE_NATIVE_URL")
34        .unwrap_or_else(|_| openai_base.trim_end_matches("/v1").to_string());
35    let upstream_model =
36        std::env::var("JEV_BRIDGE_UPSTREAM_MODEL").unwrap_or_else(|_| "local-model".to_string());
37
38    let bridge = Bridge::connect(
39        reqwest::Client::new(),
40        BridgeConfig {
41            openai_base,
42            native_base,
43            upstream_model,
44            upstream_key: std::env::var("JEV_BRIDGE_UPSTREAM_KEY").ok(),
45            served_model: "example-bridge".to_string(),
46            description: "example bridge over a generic inference API".to_string(),
47            release_date: "2026-09-22".to_string(),
48            chat_template_kwargs: json!({"enable_thinking": false}),
49            max_input_tokens: None,
50            local: Default::default(),
51            accept_any_model: false,
52            scoring: Default::default(),
53            confidence: Default::default(),
54            readout: Default::default(),
55        },
56    )
57    .await
58    .context("connecting to the upstream service failed")?;
59
60    println!("transport: {} via {}", bridge.probe().name(), bridge.probe().endpoint());
61
62    let state = Arc::new(AppState {
63        bridge,
64        api_key: std::env::var("JEV_BRIDGE_API_KEY").ok(),
65        readout_check: None,
66    });
67    let listener = tokio::net::TcpListener::bind(ADDRESS)
68        .await
69        .with_context(|| format!("binding {ADDRESS} failed"))?;
70    println!("listening on http://{ADDRESS}");
71    axum::serve(listener, router(state))
72        .with_graceful_shutdown(async {
73            let _ = tokio::signal::ctrl_c().await;
74        })
75        .await
76        .context("the HTTP server stopped unexpectedly")
77}