mirror of
https://github.com/openai/codex.git
synced 2026-11-13 22:47:20 +00:00
Expose available access programs in model discovery (#44893)
## What changed Carry optional `available_access_programs` metadata through model information, presets, caches, and the TUI, and expose it as `availableAccessPrograms` in app-server `model/list` responses. Update the generated JSON schemas, TypeScript types, and Python models. Preserve the distinction between missing metadata and an empty `cyber` list. Ignore unknown cyber program names when reading the catalog so new server programs do not prevent older clients from loading it. Discovery metadata does not grant access; inference still enforces authorization. ## Testing Add coverage for absent, null, empty, and populated metadata, unknown program names, and app-server serialization. Extend cache tests and verify that online refreshes persist changed access metadata even when the catalog ETag stays unchanged. GitOrigin-RevId: b3ef5805c1c61b8d64b9b896c9c0a79120143667
This commit is contained in:
1 parent
4dcce4f0c4
commit
e3a52b87b2
31 files changed
+405
-44
No files matched your search
@@ -188,6 +188,7 @@ fn model_from_preset(preset: &ModelPreset) -> Model {
|
||||
})
|
||||
.collect(),
|
||||
default_service_tier: preset.default_service_tier.clone(),
|
||||
available_access_programs: preset.available_access_programs.clone().map(Into::into),
|
||||
is_default: preset.is_default,
|
||||
}
|
||||
}
|
||||
@@ -275,43 +276,52 @@ async fn list_models_uses_remote_catalog_as_source_of_truth(
|
||||
api_key: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let server = MockServer::start().await;
|
||||
let remote_models = [json!("2030-01-01T00:00:00Z"), serde_json::Value::Null]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(priority, retirement_at)| {
|
||||
serde_json::from_value::<ModelInfo>(json!({
|
||||
"slug": format!("remote-only-{priority}"),
|
||||
"display_name": "Remote Only",
|
||||
"description": "Remote-only model for app-server model/list coverage",
|
||||
"model_specialty": MODEL_SPECIALTY_CYBER,
|
||||
"default_reasoning_level": "max",
|
||||
"supported_reasoning_levels": [
|
||||
{"effort": "max", "description": "Maximum"},
|
||||
{"effort": "low", "description": "Low"},
|
||||
{"effort": "focused", "description": "Focused"}
|
||||
],
|
||||
"shell_type": "shell_command",
|
||||
"visibility": "list",
|
||||
"minimal_client_version": [0, 1, 0],
|
||||
"supported_in_api": true,
|
||||
"priority": priority,
|
||||
"upgrade": {
|
||||
"model": "replacement-model",
|
||||
"migration_markdown": "Use the replacement model.",
|
||||
"retirement_at": retirement_at,
|
||||
},
|
||||
"support_verbosity": false,
|
||||
"default_verbosity": null,
|
||||
"apply_patch_tool_type": null,
|
||||
"truncation_policy": {"mode": "bytes", "limit": 10_000},
|
||||
"supports_image_detail_original": false,
|
||||
"multi_agent_version": "v2",
|
||||
"context_window": 272_000,
|
||||
"max_context_window": 272_000,
|
||||
"experimental_supported_tools": [],
|
||||
}))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let remote_models = [
|
||||
(
|
||||
json!("2030-01-01T00:00:00Z"),
|
||||
json!({ "cyber": ["standard", "daybreak_blue"] }),
|
||||
),
|
||||
(json!(null), json!({ "cyber": ["daybreak_red"] })),
|
||||
(json!(null), json!({ "cyber": [] })),
|
||||
(json!(null), json!(null)),
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(priority, (retirement_at, access_programs))| {
|
||||
serde_json::from_value::<ModelInfo>(json!({
|
||||
"slug": format!("remote-only-{priority}"),
|
||||
"display_name": "Remote Only",
|
||||
"description": "Remote-only model for app-server model/list coverage",
|
||||
"model_specialty": MODEL_SPECIALTY_CYBER,
|
||||
"available_access_programs": access_programs,
|
||||
"default_reasoning_level": "max",
|
||||
"supported_reasoning_levels": [
|
||||
{"effort": "max", "description": "Maximum"},
|
||||
{"effort": "low", "description": "Low"},
|
||||
{"effort": "focused", "description": "Focused"}
|
||||
],
|
||||
"shell_type": "shell_command",
|
||||
"visibility": "list",
|
||||
"minimal_client_version": [0, 1, 0],
|
||||
"supported_in_api": true,
|
||||
"priority": priority,
|
||||
"upgrade": {
|
||||
"model": "replacement-model",
|
||||
"migration_markdown": "Use the replacement model.",
|
||||
"retirement_at": retirement_at,
|
||||
},
|
||||
"support_verbosity": false,
|
||||
"default_verbosity": null,
|
||||
"apply_patch_tool_type": null,
|
||||
"truncation_policy": {"mode": "bytes", "limit": 10_000},
|
||||
"supports_image_detail_original": false,
|
||||
"multi_agent_version": "v2",
|
||||
"context_window": 272_000,
|
||||
"max_context_window": 272_000,
|
||||
"experimental_supported_tools": [],
|
||||
}))
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
// The startup refresh worker and model/list can both fetch before the cache is populated.
|
||||
let _models_mock = Mock::given(method("GET"))
|
||||
.and(path("/v1/models"))
|
||||
@@ -379,6 +389,20 @@ api_key_model_discovery = true
|
||||
response.result["data"][1]["upgradeInfo"]["retirementAt"],
|
||||
serde_json::Value::Null
|
||||
);
|
||||
assert_eq!(
|
||||
response.result["data"]
|
||||
.as_array()
|
||||
.expect("model/list data should be an array")
|
||||
.iter()
|
||||
.map(|model| model["availableAccessPrograms"].clone())
|
||||
.collect::<Vec<_>>(),
|
||||
vec![
|
||||
json!({ "cyber": ["standard", "daybreakBlue"] }),
|
||||
json!({ "cyber": ["daybreakRed"] }),
|
||||
json!({ "cyber": [] }),
|
||||
json!(null),
|
||||
]
|
||||
);
|
||||
let ModelListResponse {
|
||||
data: items,
|
||||
next_cursor,
|
||||
|
||||
Reference in new issue
Block a user