mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
Add model provider discovery to the app server (#58845)
## What changed - Add `modelProvider/list` to return OpenAI and explicitly configured providers, provider-specific settings, and the selected default provider. - Report `canEdit` and `canChangeDefault` based on configuration requirements, layer precedence, and whether user configuration is enabled. - Describe gateway authentication without resolving credentials, and omit endpoint URLs that are unsuitable for display. - Document the API and update generated JSON schemas, TypeScript types, and Python models. ## Testing Add app-server tests for provider discovery, authentication modes, unsafe URL suppression, and configuration editability, plus a Python wire-format round-trip test. GitOrigin-RevId: 8ba26637cd6bdd075e0e815e88aeeb04c53a2364
This commit is contained in:
@@ -1800,6 +1800,37 @@ class FuzzyFileSearchSessionUpdatedNotification(BaseModel):
|
||||
session_id: Annotated[str, Field(alias="sessionId")]
|
||||
|
||||
|
||||
class NoneGatewayAuth(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
mode: Annotated[Literal["none"], Field(title="NoneGatewayAuthMode")]
|
||||
|
||||
|
||||
class EnvironmentVariableGatewayAuth(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
env_key: Annotated[str, Field(alias="envKey")]
|
||||
mode: Annotated[
|
||||
Literal["environmentVariable"], Field(title="EnvironmentVariableGatewayAuthMode")
|
||||
]
|
||||
|
||||
|
||||
class ExternallyConfiguredGatewayAuth(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
env_key: Annotated[str | None, Field(alias="envKey")] = None
|
||||
mode: Annotated[Literal["externallyConfigured"], Field(title="ModeGatewayAuthMode")]
|
||||
|
||||
|
||||
class GatewayAuth(
|
||||
RootModel[NoneGatewayAuth | EnvironmentVariableGatewayAuth | ExternallyConfiguredGatewayAuth]
|
||||
):
|
||||
root: NoneGatewayAuth | EnvironmentVariableGatewayAuth | ExternallyConfiguredGatewayAuth
|
||||
|
||||
|
||||
class GatewayOAuthCancelResponse(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -2854,6 +2885,12 @@ class ModelProviderError(
|
||||
]
|
||||
|
||||
|
||||
class ModelProviderListParams(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
|
||||
|
||||
class ModelRerouteReason(RootModel[Literal["highRiskCyberActivity"]]):
|
||||
root: Literal["highRiskCyberActivity"]
|
||||
|
||||
@@ -3686,6 +3723,62 @@ class ProjectSortKey(Enum):
|
||||
recency_at = "recencyAt"
|
||||
|
||||
|
||||
class OpenaiProviderSettings(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
type: Annotated[Literal["openai"], Field(title="OpenaiProviderSettingsType")]
|
||||
|
||||
|
||||
class CustomGatewayProviderSettings(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
auth: GatewayAuth
|
||||
type: Annotated[Literal["customGateway"], Field(title="CustomGatewayProviderSettingsType")]
|
||||
|
||||
|
||||
class BedrockProviderSettings(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
profile: str | None = None
|
||||
region: str | None = None
|
||||
type: Annotated[Literal["bedrock"], Field(title="BedrockProviderSettingsType")]
|
||||
|
||||
|
||||
class GcpProviderSettings(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
credential_file: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
alias="credentialFile",
|
||||
description="Path on the app-server host, without credential-file contents.",
|
||||
),
|
||||
] = None
|
||||
location: str | None = None
|
||||
project_id: Annotated[str | None, Field(alias="projectId")] = None
|
||||
type: Annotated[Literal["gcp"], Field(title="GcpProviderSettingsType")]
|
||||
|
||||
|
||||
class ProviderSettings(
|
||||
RootModel[
|
||||
OpenaiProviderSettings
|
||||
| CustomGatewayProviderSettings
|
||||
| BedrockProviderSettings
|
||||
| GcpProviderSettings
|
||||
]
|
||||
):
|
||||
root: (
|
||||
OpenaiProviderSettings
|
||||
| CustomGatewayProviderSettings
|
||||
| BedrockProviderSettings
|
||||
| GcpProviderSettings
|
||||
)
|
||||
|
||||
|
||||
class RateLimitReachedType(Enum):
|
||||
rate_limit_reached = "rate_limit_reached"
|
||||
workspace_owner_credits_depleted = "workspace_owner_credits_depleted"
|
||||
@@ -7800,6 +7893,15 @@ class AccountGatewayOAuthCancelRequest(BaseModel):
|
||||
params: Annotated[None, Field(None)] = None
|
||||
|
||||
|
||||
class ModelProviderListRequest(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
id: RequestId
|
||||
method: Annotated[Literal["modelProvider/list"], Field(title="ModelProvider/listRequestMethod")]
|
||||
params: ModelProviderListParams
|
||||
|
||||
|
||||
class ModelProviderCapabilitiesReadRequest(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -9234,6 +9336,29 @@ class ModelListResponse(BaseModel):
|
||||
] = None
|
||||
|
||||
|
||||
class ModelProviderSummary(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
base_url: Annotated[
|
||||
str | None,
|
||||
Field(
|
||||
alias="baseUrl",
|
||||
description="Null when the endpoint is absent or cannot be safely displayed.",
|
||||
),
|
||||
] = None
|
||||
can_edit: Annotated[
|
||||
bool,
|
||||
Field(
|
||||
alias="canEdit",
|
||||
description="Whether a supported configuration field can be edited in the active user layer.",
|
||||
),
|
||||
]
|
||||
id: str
|
||||
name: str
|
||||
settings: ProviderSettings
|
||||
|
||||
|
||||
class NewThreadModelDefaults(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -11649,6 +11774,15 @@ class ListMcpServerStatusResponse(BaseModel):
|
||||
] = None
|
||||
|
||||
|
||||
class ModelProviderListResponse(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
)
|
||||
can_change_default: Annotated[bool, Field(alias="canChangeDefault")]
|
||||
data: list[ModelProviderSummary]
|
||||
default_provider_id: Annotated[str, Field(alias="defaultProviderId")]
|
||||
|
||||
|
||||
class ModelsRequirements(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
populate_by_name=True,
|
||||
@@ -13354,6 +13488,7 @@ class ClientRequest(
|
||||
| AccountGatewayOAuthReadRequest
|
||||
| AccountGatewayOAuthLoginRequest
|
||||
| AccountGatewayOAuthCancelRequest
|
||||
| ModelProviderListRequest
|
||||
| ModelProviderCapabilitiesReadRequest
|
||||
| ExperimentalFeatureListRequest
|
||||
| PermissionProfileListRequest
|
||||
@@ -13463,6 +13598,7 @@ class ClientRequest(
|
||||
| AccountGatewayOAuthReadRequest
|
||||
| AccountGatewayOAuthLoginRequest
|
||||
| AccountGatewayOAuthCancelRequest
|
||||
| ModelProviderListRequest
|
||||
| ModelProviderCapabilitiesReadRequest
|
||||
| ExperimentalFeatureListRequest
|
||||
| PermissionProfileListRequest
|
||||
|
||||
@@ -20,6 +20,7 @@ from openai_codex.generated.v2_all import (
|
||||
AuthRecoveryNotification,
|
||||
CommandGuardianApprovalReviewAction,
|
||||
GetAccountResponse,
|
||||
ModelProviderListResponse,
|
||||
PlanType,
|
||||
ReasoningEffort,
|
||||
ReasoningEffortOption,
|
||||
@@ -41,6 +42,57 @@ from openai_codex.types import ThreadSource
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def test_model_provider_list_preserves_wire_fields_for_each_auth_mode() -> None:
|
||||
wire = {
|
||||
"data": [
|
||||
{
|
||||
"id": "openai",
|
||||
"name": "OpenAI",
|
||||
"canEdit": False,
|
||||
"baseUrl": None,
|
||||
"settings": {"type": "openai"},
|
||||
},
|
||||
{
|
||||
"id": "amazon-bedrock",
|
||||
"name": "Amazon Bedrock Mantle",
|
||||
"canEdit": True,
|
||||
"baseUrl": None,
|
||||
"settings": {"type": "bedrock", "profile": "work", "region": "us-east-1"},
|
||||
},
|
||||
{
|
||||
"id": "gcp",
|
||||
"name": "Google Cloud Vertex AI",
|
||||
"canEdit": True,
|
||||
"baseUrl": None,
|
||||
"settings": {
|
||||
"type": "gcp",
|
||||
"projectId": "test-project",
|
||||
"location": "global",
|
||||
"credentialFile": "/host/adc.json",
|
||||
},
|
||||
},
|
||||
*[
|
||||
{
|
||||
"id": auth["mode"],
|
||||
"name": "Gateway",
|
||||
"canEdit": True,
|
||||
"baseUrl": "https://gateway.example.test",
|
||||
"settings": {"type": "customGateway", "auth": auth},
|
||||
}
|
||||
for auth in [
|
||||
{"mode": "none"},
|
||||
{"mode": "environmentVariable", "envKey": "GATEWAY_KEY"},
|
||||
{"mode": "externallyConfigured", "envKey": "EXTERNAL_KEY"},
|
||||
]
|
||||
],
|
||||
],
|
||||
"defaultProviderId": "gcp",
|
||||
"canChangeDefault": True,
|
||||
}
|
||||
response = ModelProviderListResponse.model_validate(wire)
|
||||
assert response.model_dump(mode="json", by_alias=True) == wire
|
||||
|
||||
|
||||
def test_inline_review_delivery_round_trips_as_an_enum() -> None:
|
||||
wire = {"threadId": "thread-1", "target": {"type": "uncommittedChanges"}, "delivery": "inline"}
|
||||
params = ReviewStartParams.model_validate(wire)
|
||||
|
||||
Reference in New Issue
Block a user