mirror of
https://github.com/openai/codex.git
synced 2026-11-07 20:30:33 +00:00
Add model provider configuration writes to the app-server (#58876)
## What changed Add `modelProvider/config/write` to create custom gateways and patch existing custom gateway, Bedrock, and GCP settings. Return the saved provider using the same safe summary as `modelProvider/list`. Omitted fields retain their values; explicit `null` clears nullable user overrides. Apply patches through the shared configuration queue with last-write-wins semantics, enforce field editability and validation, and preserve unexposed authentication settings. Saving leaves provider selection and authentication unchanged. Saving the provider used by `model/list` invalidates its catalog for the next access. Include documentation and generated JSON, TypeScript, and Python protocol types. ## Testing Add coverage for gateway creation and ID allocation, patch and null semantics, configuration policy enforcement, authentication preservation, and catalog refresh after active-provider edits. Extend Python protocol tests to verify wire round trips and reject mismatched provider IDs or fields. GitOrigin-RevId: 850fe2c48ef5274944400efb5a859d720179c923
This commit is contained in:
@@ -5,6 +5,7 @@ from pathlib import Path
|
||||
from typing import get_type_hints
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from openai_codex._runtime_requirements import CheckoutCapabilities
|
||||
from openai_codex.client import CodexClient, _params_dict
|
||||
@@ -20,6 +21,8 @@ from openai_codex.generated.v2_all import (
|
||||
AuthRecoveryNotification,
|
||||
CommandGuardianApprovalReviewAction,
|
||||
GetAccountResponse,
|
||||
ModelProviderConfigWriteParams,
|
||||
ModelProviderConfigWriteResponse,
|
||||
ModelProviderListResponse,
|
||||
PlanType,
|
||||
ReasoningEffort,
|
||||
@@ -42,7 +45,7 @@ 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:
|
||||
def test_model_provider_responses_preserve_wire_fields_for_each_auth_mode() -> None:
|
||||
wire = {
|
||||
"data": [
|
||||
{
|
||||
@@ -91,6 +94,37 @@ def test_model_provider_list_preserves_wire_fields_for_each_auth_mode() -> None:
|
||||
}
|
||||
response = ModelProviderListResponse.model_validate(wire)
|
||||
assert response.model_dump(mode="json", by_alias=True) == wire
|
||||
for provider in wire["data"]:
|
||||
saved = ModelProviderConfigWriteResponse.model_validate({"provider": provider})
|
||||
assert saved.model_dump(mode="json", by_alias=True) == {"provider": provider}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"settings",
|
||||
[
|
||||
{"type": "customGateway", "name": "Gateway", "baseUrl": "https://example.test"},
|
||||
{"type": "customGateway", "providerId": "team", "envKey": None},
|
||||
{"type": "bedrock", "providerId": "amazon-bedrock", "region": None},
|
||||
{"type": "bedrock", "providerId": "amazon-bedrock-runtime", "profile": "work"},
|
||||
{"type": "gcp", "providerId": "gcp", "credentialFile": None, "location": "global"},
|
||||
],
|
||||
)
|
||||
def test_provider_patch_preserves_explicit_null_and_omitted_fields(settings: dict) -> None:
|
||||
wire = {"settings": settings}
|
||||
params = ModelProviderConfigWriteParams.model_validate(wire)
|
||||
assert params.model_dump(mode="json", by_alias=True, exclude_unset=True) == wire
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"settings",
|
||||
[
|
||||
{"type": "bedrock", "providerId": "gcp", "region": "us-east-1"},
|
||||
{"type": "gcp", "providerId": "gcp", "region": "us-east-1"},
|
||||
],
|
||||
)
|
||||
def test_provider_patch_rejects_mismatched_id_or_fields(settings: dict) -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
ModelProviderConfigWriteParams.model_validate({"settings": settings})
|
||||
|
||||
|
||||
def test_inline_review_delivery_round_trips_as_an_enum() -> None:
|
||||
|
||||
Reference in New Issue
Block a user