Skip to content
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- The Runtime API test harness builds and serves its router on a thread sized
like the product's runtime workers (`CODEWHALE_MAIN_STACK_BYTES`) instead of
the 2 MiB libtest thread. Two product paths (config load/reload under a
profile, thread lifecycle) marginally overflowed that stack in debug builds
and aborted the whole lib suite with SIGABRT; `runtime_api` now passes with
no `RUST_MIN_STACK` override.
- The sandbox read deny-list matches a rule's resolved path as well as its
literal spelling. On macOS `/etc` and `/var` are symlinks into `/private`,
so a read of `/private/etc/sudoers` walked around the `/etc/sudoers` rule,
Expand Down
35 changes: 34 additions & 1 deletion crates/config/src/provider_templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,31 @@ pub const SENSENOVA_MODELS: &[&str] = &[SENSENOVA_DEFAULT_MODEL];
pub const AGNES_TEMPLATE_ID: &str = "agnes";

/// Baseten Model APIs — OpenAI Chat Completions, discovered at `/v1/models`.
///
/// This 2026-08-29 roster is the official offline seed from Baseten's Model
/// APIs overview. The authenticated live catalog replaces this exact provider
/// partition after startup, so upstream additions and removals do not require a
/// Codewhale release.
pub const BASETEN_TEMPLATE_ID: &str = "baseten";
pub const BASETEN_BASE_URL: &str = "https://inference.baseten.co/v1";
pub const BASETEN_DEFAULT_MODEL: &str = "deepseek-ai/DeepSeek-V4-Pro";
pub const BASETEN_API_KEY_ENV: &str = "BASETEN_API_KEY";
pub const BASETEN_MODELS: &[&str] = &[
BASETEN_DEFAULT_MODEL,
"deepseek-ai/DeepSeek-V4-Flash-0731",
"deepseek-ai/DeepSeek-V4-Pro-0813",
"deepseek-ai/DeepSeek-V4-Flash-0731",
"zai-org/GLM-4.7",
"zai-org/GLM-5.2",
"zai-org/GLM-5.2-Fast",
"zai-org/GLM-5.3",
"zai-org/GLM-5.3-Flash",
"thinkingmachines/inkling",
"thinkingmachines/inkling-small",
"moonshotai/Kimi-K2.6",
"moonshotai/Kimi-K2.7-Code",
"moonshotai/Kimi-K3",
"nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B",
"openai/gpt-oss-120b",
];

/// Groq — OpenAI Chat Completions hosted inference.
Expand Down Expand Up @@ -505,4 +519,23 @@ mod tests {
);
}
}

#[test]
fn baseten_offline_seed_matches_the_current_official_model_api_roster() {
let template = provider_setup_template(BASETEN_TEMPLATE_ID).expect("baseten");
assert_eq!(template.picker_models(), BASETEN_MODELS);
assert_eq!(BASETEN_MODELS.len(), 15);
for required in [
"deepseek-ai/DeepSeek-V4-Pro",
"zai-org/GLM-5.3",
"thinkingmachines/inkling",
"moonshotai/Kimi-K3",
"openai/gpt-oss-120b",
] {
assert!(
BASETEN_MODELS.contains(&required),
"missing current Baseten seed {required}"
);
}
}
}
40 changes: 35 additions & 5 deletions crates/config/src/route/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,29 @@ impl RouteResolver {
/// Returns [`RouteError`] when the model is empty, the provider is invalid,
/// or a clearly-foreign model is requested for a strict direct provider.
pub fn resolve(&self, req: &RouteRequest) -> Result<ReadyRouteCandidate, RouteError> {
self.resolve_inner(req, false)
}

/// Resolve with catalog facts authenticated against this exact endpoint.
///
/// The ordinary [`Self::resolve`] path strips capabilities and pricing when
/// a route uses a custom base URL, because a same-named first-party model is
/// not evidence about an arbitrary proxy. Callers may use this seam only
/// when the injected offering came from the selected provider identity's
/// own endpoint and its base-URL fingerprint matches the request endpoint.
/// All normal routing and protocol validation still applies.
pub fn resolve_with_endpoint_catalog_authority(
&self,
req: &RouteRequest,
) -> Result<ReadyRouteCandidate, RouteError> {
self.resolve_inner(req, true)
}

fn resolve_inner(
&self,
req: &RouteRequest,
endpoint_catalog_authoritative: bool,
) -> Result<ReadyRouteCandidate, RouteError> {
// 1. Provider scope from explicit choice only; default otherwise.
// The provider is NEVER inferred from a model prefix.
let provider_kind = req.explicit_provider.unwrap_or_default();
Expand Down Expand Up @@ -235,14 +258,21 @@ impl RouteResolver {
selected.endpoint_key = "responses".to_string();
}
}
if custom_endpoint {
if custom_endpoint && !endpoint_catalog_authoritative {
// Capabilities and pricing belong to the exact provider endpoint
// offering that reported them. Reusing a provider enum and a
// first-party model id against a custom compatible endpoint does
// not prove that proxy serves the same modality, tool, reasoning,
// or billing contract. Keep the caller's model id and Chat
// pass-through above, but clear every unowned offering fact at the
// authority boundary instead of presenting it as verified.
// not prove that proxy serves the same canonical model, limits,
// modality, tool, reasoning, or billing contract. Keep the
// caller's wire model id, but clear every unowned offering fact at
// the authority boundary instead of presenting it as verified.
// The endpoint_key/protocol stays: it is the provider adapter's
// wire contract (a model-aware roster row or fixed policy), not an
// endpoint-catalog fact, and coercing it to Chat would silently
// change how a Responses- or Messages-bound route speaks.
// Deepseek's custom-endpoint Chat pass-through is handled above.
selected.canonical_model = None;
selected.limits = RouteLimits::default();
selected.capabilities = RouteCapabilities::default();
selected.pricing = PricingSku::UnknownOrStale;
}
Expand Down
27 changes: 27 additions & 0 deletions crates/config/src/route/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1663,6 +1663,33 @@ fn custom_endpoint_does_not_inherit_first_party_pricing() {
);
}

#[test]
fn exact_endpoint_catalog_may_carry_its_own_pricing_on_a_custom_base_url() {
use super::candidate::PricingSku;

let request = RouteRequest {
explicit_provider: Some(ProviderKind::Deepseek),
model_selector: Some(LogicalModelRef::from("deepseek-v4-pro")),
saved_provider_model: None,
base_url_override: Some("https://authenticated-catalog.example.test/v1".to_string()),
limit_overrides: Vec::new(),
};
let out = priced_deepseek_resolver()
.resolve_with_endpoint_catalog_authority(&request)
.expect("exact endpoint-owned catalog route resolves");

match out.pricing() {
Some(PricingSku::Token {
input_per_mtok,
output_per_mtok,
}) => {
assert_eq!(*input_per_mtok, Some(0.28));
assert_eq!(*output_per_mtok, Some(0.42));
}
other => panic!("expected exact endpoint pricing, got {other:?}"),
}
}

#[test]
fn unpriced_offering_stays_unknown() {
use super::candidate::PricingSku;
Expand Down
6 changes: 6 additions & 0 deletions crates/tui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- The Runtime API test harness builds and serves its router on a thread sized
like the product's runtime workers (`CODEWHALE_MAIN_STACK_BYTES`) instead of
the 2 MiB libtest thread. Two product paths (config load/reload under a
profile, thread lifecycle) marginally overflowed that stack in debug builds
and aborted the whole lib suite with SIGABRT; `runtime_api` now passes with
no `RUST_MIN_STACK` override.
- The sandbox read deny-list matches a rule's resolved path as well as its
literal spelling. On macOS `/etc` and `/var` are symlinks into `/private`,
so a read of `/private/etc/sudoers` walked around the `/etc/sudoers` rule,
Expand Down
Loading
Loading