Files
cortiq-gateway/Cargo.toml
T
infosave2007 b339c2b622
Docker / publish (push) Canceled after 0s
Release / crates-io (push) Canceled after 0s
Release / release (macos-14, aarch64-apple-darwin) (push) Canceled after 0s
Release / release (ubuntu-latest, x86_64-unknown-linux-gnu) (push) Canceled after 0s
Release / release (windows-latest, x86_64-pc-windows-msvc) (push) Canceled after 0s
fix(openai): strict OpenAI wire compatibility — Open WebUI can chat again
/v1/chat/completions answered ordinary client payloads with a bare HTTP 422
(a plain-text body no OpenAI client can parse), so Open WebUI showed neither
an answer nor an error — it just hung. Parse the body leniently instead:
content as string/null/content-part array, tools: null, stream: null, a
string reasoning_effort, max_completion_tokens, messages[].name and
tool_call_id, and a missing Content-Type. Unreadable bodies now come back as
an OpenAI error envelope with 400.

Responses are strict OpenAI JSON: no "tool_calls": null, finish_reason mapped
to the spec's closed set (cortiq serve's max_tokens -> length), never an empty
id, and `model` echoes the id the client requested — the model that actually
answered stays in cortiq.selected_model and X-Cortiq-Selected-Model.

Streaming is re-normalised rather than forwarded verbatim: a leading role
delta, message-shaped chunks converted to delta, one terminal finish_reason,
always a trailing data: [DONE], and an SSE error event when the upstream dies
mid-flight. Adds X-Accel-Buffering: no so a fronting proxy cannot buffer the
stream into a hang.

GET /v1/models now lists managed [[cmf.servers]] models with their live
running/healthy state, so clients can pin a local .cmf directly.

Also strips client bookkeeping keys (chat_id, session_id, metadata, features,
...) from the upstream call and drops the leftover [to_wire] debug prints.
2026-08-21 09:10:31 +03:00

80 lines
2.2 KiB
TOML

[package]
name = "cortiq-gateway"
version = "0.2.45"
edition = "2021"
rust-version = "1.75"
license = "Apache-2.0"
description = "Universal LLM gateway with intelligent routing and an embedded multilingual admin console"
repository = "https://github.com/infosave2007/cortiq-gateway"
homepage = "https://api.allaigate.com"
readme = "README.md"
keywords = ["llm", "gateway", "proxy", "openai", "routing"]
categories = ["web-programming::http-server", "command-line-utilities"]
# Files shipped in the published crate. The embedded admin SPA MUST be included
# because rust-embed compiles it in; docs/screenshots are excluded to keep the
# crate lean. The web/ subfolders are listed one by one rather than as web/**/*
# so stray scratch files dropped next to the SPA never end up published.
include = [
"src/**/*",
"web/index.html",
"web/favicon.svg",
"web/css/**/*",
"web/js/**/*",
"config/gateway.example.toml",
"README.md",
"CHANGELOG.md",
"LICENSE",
]
[dependencies]
# async runtime + HTTP server
tokio = { version = "1", features = ["full"] }
axum = { version = "0.7", features = ["macros"] }
tower = "0.5"
tower-http = { version = "0.6", features = ["limit", "trace", "cors"] }
# HTTP client to providers and to cortiq-router (rustls, no OpenSSL)
reqwest = { version = "0.12", default-features = false, features = ["json", "stream", "rustls-tls"] }
# serialization
serde = { version = "1", features = ["derive"] }
serde_json = "1"
toml = "0.8"
# hot-reloadable shared state + embedded admin SPA
arc-swap = "1"
rust-embed = "8"
mime_guess = "2"
# cross-platform CSPRNG for admin/key token generation (Linux/macOS/Windows)
getrandom = "0.2"
# streaming / async utils
futures = "0.3"
async-trait = "0.1"
async-stream = "0.3"
bytes = "1"
tokio-stream = "0.1"
# CLI / config
clap = { version = "4", features = ["derive"] }
# open browser on first run (optional)
open = { version = "5", optional = true }
# host metrics for the admin dashboard (CPU / RAM / disk)
sysinfo = "0.39"
# errors / logging / metrics
thiserror = "1"
anyhow = "1"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
[features]
default = ["open-browser"]
open-browser = ["open"]
[profile.release]
lto = true
codegen-units = 1