mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Add OpenAI GPT-5.6 models (#566)
## Summary - add GPT-5.6 Sol, Terra, and Luna to the built-in OpenAI model catalog with current capabilities, limits, aliases, and pricing - route all three models through the OpenAI Responses API and keep the Codex-safe 272K context policy - make GPT-5.6 Sol the OpenAI default and update the model docs and Ask Fabro API contract ## Testing - cargo nextest run -p fabro-model - cargo nextest run -p fabro-llm builtin_catalog_route_equivalence_table - cargo nextest run -p fabro-server list_models - cargo nextest run -p fabro-server --features test-support run_responses_include_ask_fabro_affordance - cargo +nightly-2026-04-14 fmt --check --all - cargo +nightly-2026-04-14 clippy -p fabro-model -p fabro-llm --all-targets -- -D warnings - git diff --check
This commit is contained in:
parent
96372c5a3c
commit
18d4628291
6 changed files with 110 additions and 15 deletions
|
|
@ -20,6 +20,9 @@ No single model is best at everything. Fabro lets you assign the right model to
|
|||
| `claude-sonnet-4-6` | anthropic | `sonnet`, `claude-sonnet` | 200K | $3.00 / $15.00 | 50 tok/s |
|
||||
| `claude-sonnet-4-5` | anthropic | | 200K | $3.00 / $15.00 | 50 tok/s |
|
||||
| `claude-haiku-4-5` | anthropic | `haiku`, `claude-haiku` | 200K | $0.80 / $4.00 | 100 tok/s |
|
||||
| `gpt-5.6-sol` | openai | `gpt-5.6`, `gpt56-sol` | 272K | $5.00 / $30.00 | n/a |
|
||||
| `gpt-5.6-terra` | openai | `gpt56-terra` | 272K | $2.50 / $15.00 | n/a |
|
||||
| `gpt-5.6-luna` | openai | `gpt56-luna` | 272K | $1.00 / $6.00 | n/a |
|
||||
| `gpt-5.4` | openai | `gpt54`, `gpt5`, `codex` | 272K | $2.50 / $15.00 | 70 tok/s |
|
||||
| `gpt-5.5` | openai | `gpt55` | 272K | $5.00 / $30.00 | 70 tok/s |
|
||||
| `gpt-5.5-pro` | openai | `gpt55-pro` | 1M | $30.00 / $180.00 | 20 tok/s |
|
||||
|
|
@ -169,7 +172,7 @@ When no model or provider is specified, Fabro checks configured provider credent
|
|||
| Provider | Default model |
|
||||
|---|---|
|
||||
| `anthropic` | `claude-sonnet-4-6` |
|
||||
| `openai` | `gpt-5.5` |
|
||||
| `openai` | `gpt-5.6-sol` |
|
||||
| `gemini` | `gemini-3.5-flash` |
|
||||
| `kimi` | `kimi-k2.5` |
|
||||
| `zai` | `glm-4.7` |
|
||||
|
|
|
|||
|
|
@ -100,6 +100,13 @@ fn normalize_attach_json_progress_event(mut event: Value) -> Value {
|
|||
);
|
||||
}
|
||||
}
|
||||
if let Some(model_name) = event.pointer_mut("/properties/settings/run/model/name") {
|
||||
assert!(
|
||||
model_name.is_string(),
|
||||
"default model should serialize as a string"
|
||||
);
|
||||
*model_name = Value::String("[DEFAULT_MODEL]".to_string());
|
||||
}
|
||||
event
|
||||
}
|
||||
|
||||
|
|
@ -991,7 +998,7 @@ fn attach_json_errors_without_prompting_for_human_input() {
|
|||
"speed": null
|
||||
},
|
||||
"fallbacks": [],
|
||||
"name": "gpt-5.5",
|
||||
"name": "[DEFAULT_MODEL]",
|
||||
"provider": "openai"
|
||||
},
|
||||
"notifications": {},
|
||||
|
|
|
|||
|
|
@ -306,6 +306,9 @@ mod tests {
|
|||
("gpt-5.4-pro", "gpt-5.4-pro", T::OpenAi, C::OpenAiResponses, B::OpenAi, P::OpenAi),
|
||||
("gpt-5.5", "gpt-5.5", T::OpenAi, C::OpenAiResponses, B::OpenAi, P::OpenAi),
|
||||
("gpt-5.5-pro", "gpt-5.5-pro", T::OpenAi, C::OpenAiResponses, B::OpenAi, P::OpenAi),
|
||||
("gpt-5.6-luna", "gpt-5.6-luna", T::OpenAi, C::OpenAiResponses, B::OpenAi, P::OpenAi),
|
||||
("gpt-5.6-sol", "gpt-5.6-sol", T::OpenAi, C::OpenAiResponses, B::OpenAi, P::OpenAi),
|
||||
("gpt-5.6-terra", "gpt-5.6-terra", T::OpenAi, C::OpenAiResponses, B::OpenAi, P::OpenAi),
|
||||
("kimi-k2.5", "kimi-k2.5", T::OpenAiCompatible, C::OpenAiCompatible, B::OpenAi, P::OpenAi),
|
||||
("mercury-2", "mercury-2", T::OpenAiCompatible, C::OpenAiCompatible, B::OpenAi, P::OpenAi),
|
||||
("minimax-m2.5", "minimax-m2.5", T::OpenAiCompatible, C::OpenAiCompatible, B::OpenAi, P::OpenAi),
|
||||
|
|
|
|||
|
|
@ -2137,7 +2137,8 @@ enabled = true
|
|||
let m = Catalog::builtin()
|
||||
.default_for_provider(&ProviderId::openai())
|
||||
.unwrap();
|
||||
assert_eq!(m.id, "gpt-5.5");
|
||||
assert_eq!(m.provider, ProviderId::openai());
|
||||
assert!(m.default);
|
||||
|
||||
let m = Catalog::builtin()
|
||||
.default_for_provider(&ProviderId::gemini())
|
||||
|
|
@ -2910,12 +2911,10 @@ probe = false
|
|||
))
|
||||
.expect("sparse built-in model override should build");
|
||||
|
||||
let openai = ProviderId::openai();
|
||||
assert_eq!(
|
||||
catalog
|
||||
.probe_for_provider(&ProviderId::openai())
|
||||
.unwrap()
|
||||
.id,
|
||||
"gpt-5.5"
|
||||
catalog.probe_for_provider(&openai).unwrap().id,
|
||||
catalog.default_for_provider(&openai).unwrap().id
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -3319,12 +3318,10 @@ small_default = false
|
|||
))
|
||||
.expect("sparse built-in model override should build");
|
||||
|
||||
let openai = ProviderId::openai();
|
||||
assert_eq!(
|
||||
catalog
|
||||
.small_default_for_provider(&ProviderId::openai())
|
||||
.unwrap()
|
||||
.id,
|
||||
"gpt-5.5"
|
||||
catalog.small_default_for_provider(&openai).unwrap().id,
|
||||
catalog.default_for_provider(&openai).unwrap().id
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -4447,6 +4444,9 @@ sampling_params = false
|
|||
"gpt-5.4",
|
||||
"gpt-5.4-mini",
|
||||
"gpt-5.5",
|
||||
"gpt-5.6-luna",
|
||||
"gpt-5.6-sol",
|
||||
"gpt-5.6-terra",
|
||||
] {
|
||||
assert_eq!(
|
||||
catalog.get(model).unwrap().context_window(),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,82 @@ priority = 90
|
|||
[providers.openai.auth]
|
||||
credentials = ["env:OPENAI_API_KEY", "vault:OPENAI_API_KEY", "vault:OPENAI_CODEX"]
|
||||
|
||||
[models."gpt-5.6-sol"]
|
||||
provider = "openai"
|
||||
api_id = "gpt-5.6-sol"
|
||||
display_name = "GPT-5.6 Sol"
|
||||
family = "gpt-5"
|
||||
training = "2026-02-16"
|
||||
knowledge_cutoff = "February 16, 2026"
|
||||
default = true
|
||||
aliases = ["gpt56-sol", "gpt-56-sol", "gpt-5.6", "gpt56", "gpt-56"]
|
||||
|
||||
[models."gpt-5.6-sol".limits]
|
||||
context_window = 272000
|
||||
max_output = 128000
|
||||
|
||||
[models."gpt-5.6-sol".features]
|
||||
tools = true
|
||||
vision = true
|
||||
reasoning = true
|
||||
reasoning_effort = "levels"
|
||||
prompt_cache = true
|
||||
|
||||
[models."gpt-5.6-sol".costs]
|
||||
input_cost_per_mtok = 5.0
|
||||
output_cost_per_mtok = 30.0
|
||||
cache_input_cost_per_mtok = 0.5
|
||||
|
||||
[models."gpt-5.6-terra"]
|
||||
provider = "openai"
|
||||
api_id = "gpt-5.6-terra"
|
||||
display_name = "GPT-5.6 Terra"
|
||||
family = "gpt-5"
|
||||
training = "2026-02-16"
|
||||
knowledge_cutoff = "February 16, 2026"
|
||||
aliases = ["gpt56-terra", "gpt-56-terra"]
|
||||
|
||||
[models."gpt-5.6-terra".limits]
|
||||
context_window = 272000
|
||||
max_output = 128000
|
||||
|
||||
[models."gpt-5.6-terra".features]
|
||||
tools = true
|
||||
vision = true
|
||||
reasoning = true
|
||||
reasoning_effort = "levels"
|
||||
prompt_cache = true
|
||||
|
||||
[models."gpt-5.6-terra".costs]
|
||||
input_cost_per_mtok = 2.5
|
||||
output_cost_per_mtok = 15.0
|
||||
cache_input_cost_per_mtok = 0.25
|
||||
|
||||
[models."gpt-5.6-luna"]
|
||||
provider = "openai"
|
||||
api_id = "gpt-5.6-luna"
|
||||
display_name = "GPT-5.6 Luna"
|
||||
family = "gpt-5"
|
||||
training = "2026-02-16"
|
||||
knowledge_cutoff = "February 16, 2026"
|
||||
aliases = ["gpt56-luna", "gpt-56-luna"]
|
||||
|
||||
[models."gpt-5.6-luna".limits]
|
||||
context_window = 272000
|
||||
max_output = 128000
|
||||
|
||||
[models."gpt-5.6-luna".features]
|
||||
tools = true
|
||||
vision = true
|
||||
reasoning = true
|
||||
reasoning_effort = "levels"
|
||||
prompt_cache = true
|
||||
|
||||
[models."gpt-5.6-luna".costs]
|
||||
input_cost_per_mtok = 1.0
|
||||
output_cost_per_mtok = 6.0
|
||||
cache_input_cost_per_mtok = 0.1
|
||||
|
||||
[models."gpt-5.4"]
|
||||
provider = "openai"
|
||||
api_id = "gpt-5.4"
|
||||
|
|
@ -40,7 +116,6 @@ display_name = "GPT-5.5"
|
|||
family = "gpt-5"
|
||||
training = "2025-12-01"
|
||||
knowledge_cutoff = "December 2025"
|
||||
default = true
|
||||
estimated_output_tps = 70
|
||||
aliases = ["gpt55", "gpt-55"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use axum::body::Body;
|
||||
use axum::http::{Request, StatusCode};
|
||||
use fabro_model::{Catalog, ProviderId};
|
||||
use fabro_types::settings::run::EnvironmentProvider;
|
||||
use tower::ServiceExt;
|
||||
|
||||
|
|
@ -160,7 +161,13 @@ _version = 1
|
|||
created["ask_fabro"]["unavailable_reason"],
|
||||
"sandbox_not_ready"
|
||||
);
|
||||
assert_eq!(created["ask_fabro"]["default_model"], "gpt-5.5");
|
||||
let default_openai_model = Catalog::builtin()
|
||||
.default_for_provider(&ProviderId::openai())
|
||||
.expect("the built-in OpenAI provider should have a default model");
|
||||
assert_eq!(
|
||||
created["ask_fabro"]["default_model"].as_str(),
|
||||
Some(default_openai_model.id())
|
||||
);
|
||||
|
||||
let get_request = Request::builder()
|
||||
.method("GET")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue