Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ Use your `server.auth_token` if configured; otherwise `tinyllm` is a client
placeholder. Choose models your account can access. The prefix is the provider
table name; the rest is the upstream model ID, including any further slashes.
Client reasoning effort and service tier override configured model defaults.
For a configured OpenAI GPT model, append `-fast` (for example,
For an OpenAI model ID beginning with `gpt-`, append `-fast` (for example,
`openai/gpt-5.6-sol-fast`) to request the priority tier while sending the base model
upstream, overriding client and configured service tiers; subscription requests also
upstream, overriding client and configured service tiers; the base needs no model
table, matching how unlisted IDs are forwarded; subscription requests also
carry Codex's routing hint. The suffix does not stack, and upstream decides what it
delivers: responses may still report `default`. Fast/priority processing can consume
more credits or cost more.
Expand Down
14 changes: 8 additions & 6 deletions src/providers/openai/compatible_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn replayed(details: &Value) -> Value {
}

#[test]
fn fast_suffix_resolves_only_configured_gpt_models() {
fn fast_suffix_resolves_gpt_models() {
use super::super::models::{Config, ModelOptions, OpenAiAuth};
use crate::providers::Provider;
let server = crate::config::Server::default();
Expand All @@ -319,15 +319,17 @@ fn fast_suffix_resolves_only_configured_gpt_models() {
server,
)
.unwrap();
assert_eq!(
provider.synthetic_fast_base("gpt-6-astra-fast"),
Some("gpt-6-astra")
);
for (native, base) in [
("gpt-6-astra-fast", "gpt-6-astra"),
// An unconfigured base still resolves; model tables are not an allowlist.
("gpt-9-fast", "gpt-9"),
] {
assert_eq!(provider.synthetic_fast_base(native), Some(base), "{native}");
}
for native in [
"gpt-5.4-fast", // configured upstream ID stays literal
"gpt-5.4-fast-fast", // the suffix never stacks
"o4-mini-fast", // not a gpt- model
"gpt-9-fast", // base is not configured
"gpt-6-astra",
] {
assert_eq!(provider.synthetic_fast_base(native), None, "{native}");
Expand Down
5 changes: 1 addition & 4 deletions src/providers/openai/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,7 @@ impl OpenAiProvider {
let base = native
.strip_suffix("-fast")
.filter(|b| !b.ends_with("-fast"))?;
(!self.config.models.contains_key(native)
&& base.starts_with("gpt-")
&& self.config.models.contains_key(base))
.then_some(base)
(!self.config.models.contains_key(native) && base.starts_with("gpt-")).then_some(base)
}

fn model(&self, native: &str) -> Model {
Expand Down
14 changes: 3 additions & 11 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3269,7 +3269,7 @@ async fn openai_model_defaults_and_client_overrides_reach_each_endpoint() {
("gpt-5.4", "gpt-5.4", Some("low"), "low"),
("gpt-5.4", "gpt-5.4", None, "xhigh"),
("gpt-5.4-fast", "gpt-5.4", None, "xhigh"),
("gpt-9-fast", "gpt-9-fast", Some("low"), "low"),
("gpt-9-fast", "gpt-9", Some("low"), "low"),
] {
let mut body = if path.ends_with("/responses") {
json!({"input":"hello"})
Expand Down Expand Up @@ -3313,16 +3313,8 @@ async fn openai_model_defaults_and_client_overrides_reach_each_endpoint() {
assert_eq!(response["service_tier"], "default");
}
match native_model {
"gpt-5.4" => assert_eq!(upstream["service_tier"], "priority"),
// An unconfigured base forwards the name literally and keeps the client tier.
"gpt-9-fast" => assert_eq!(
upstream["service_tier"],
if path.starts_with("/anthropic") {
"default"
} else {
"flex"
}
),
// An unconfigured base still resolves, so both take the fast tier.
"gpt-5.4" | "gpt-9" => assert_eq!(upstream["service_tier"], "priority"),
_ => assert!(upstream.get("service_tier").is_none()),
}
}
Expand Down
8 changes: 4 additions & 4 deletions tinyllm.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ type = "Subscription"
# not an allowlist. Unlisted native IDs are forwarded too. Quote IDs containing
# dots or slashes. Model availability depends on the upstream account.
# Clients select the main/small/subagent model; there are no configurable aliases.
# Each configured native ID beginning with gpt- also exposes a generated -fast
# name that sends the base model with priority. Exact configured names stay literal,
# so listing an upstream ID that itself ends in -fast keeps it verbatim; the suffix
# never stacks.
# Any native ID beginning with gpt- also accepts a generated -fast name that sends
# the base model with priority, configured or not; discovery lists it for configured
# IDs only. Exact configured names stay literal, so listing an upstream ID that itself
# ends in -fast keeps it verbatim; the suffix never stacks.
[providers.openai.models."gpt-5.6-sol"]
# Optional fallback when the client omits effort. Client reasoning controls win.
# Accepted values: none, minimal, low, medium, high, xhigh, max. Providers map
Expand Down