mirror of
https://github.com/openai/codex.git
synced 2026-10-29 19:08:43 +00:00
## Why Existing chats retain their provider configuration when the selected provider changes. Reject resume and input until the configured provider matches the chat, while keeping history readable and allowing recovery after configuration is restored. ## What changed - Validate saved providers before applying resume overrides, preserving the provider when only model or reasoning settings change. - Check the current provider selection, including profiles and launch overrides, before accepting input. Reject input when configuration cannot be loaded. - Return structured `ModelProviderError` data for provider mismatches, missing definitions, and policy conflicts, with generated JSON Schema, TypeScript, and Python types. ## Testing Add coverage for override bypass prevention, provider restoration, readable history after rejection, and blocked requests sending no inference traffic. Verify schema fields and Python round trips match the error wire format. GitOrigin-RevId: 051f97c3815c547d8411c71b770df30eae969f68
71 lines
2.8 KiB
Rust
71 lines
2.8 KiB
Rust
//! Recoverable provider failures shared by resume and inference admission.
|
||
|
||
use crate::JsonSchema;
|
||
use crate::TS;
|
||
use serde::Deserialize;
|
||
use serde::Serialize;
|
||
|
||
/// Structured JSON-RPC error data. Unknown errors must retain the client's normal fallback.
|
||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema, TS)]
|
||
#[serde(
|
||
tag = "type",
|
||
rename_all = "camelCase",
|
||
rename_all_fields = "camelCase"
|
||
)]
|
||
#[ts(
|
||
tag = "type",
|
||
rename_all = "camelCase",
|
||
rename_all_fields = "camelCase",
|
||
export_to = "v2/"
|
||
)]
|
||
pub enum ModelProviderError {
|
||
ModelProviderMismatch {
|
||
#[schemars(rename = "modelProvider")]
|
||
model_provider: String,
|
||
#[schemars(rename = "currentModelProvider")]
|
||
current_model_provider: String,
|
||
},
|
||
ModelProviderNotConfigured {
|
||
#[schemars(rename = "modelProvider")]
|
||
model_provider: String,
|
||
},
|
||
ModelProviderPolicyConflict {
|
||
#[schemars(rename = "modelProvider")]
|
||
model_provider: String,
|
||
#[schemars(rename = "requiredModelProvider")]
|
||
required_model_provider: String,
|
||
},
|
||
}
|
||
|
||
impl ModelProviderError {
|
||
pub fn title(&self) -> &'static str {
|
||
match self {
|
||
Self::ModelProviderMismatch { .. } => "Model provider mismatch",
|
||
Self::ModelProviderNotConfigured { .. } => "Model provider unavailable",
|
||
Self::ModelProviderPolicyConflict { .. } => "Model provider blocked by policy",
|
||
}
|
||
}
|
||
}
|
||
|
||
impl std::fmt::Display for ModelProviderError {
|
||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||
match self {
|
||
Self::ModelProviderMismatch { model_provider, current_model_provider } => write!(f,
|
||
"This chat uses {model_provider}, but your current provider is {current_model_provider}. Switch to {model_provider} to continue."),
|
||
Self::ModelProviderNotConfigured { model_provider } => write!(f,
|
||
"This chat uses model provider “{model_provider}”, which is no longer configured. Restore this provider’s configuration to continue."),
|
||
Self::ModelProviderPolicyConflict { model_provider, required_model_provider }
|
||
if model_provider != required_model_provider => write!(f,
|
||
"This chat uses model provider “{model_provider}”, but your organization requires “{required_model_provider}”. Contact your administrator or start a new chat using the required provider."),
|
||
Self::ModelProviderPolicyConflict { .. } => f.write_str(
|
||
"This chat’s model provider settings no longer match your organization’s requirements. Contact your administrator or start a new chat using the current provider settings."),
|
||
}
|
||
}
|
||
}
|
||
|
||
impl std::error::Error for ModelProviderError {}
|
||
|
||
#[cfg(test)]
|
||
#[path = "model_provider_error_tests.rs"]
|
||
mod tests;
|