diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index aac567aa6c..110d274118 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -2566,6 +2566,18 @@ ], "type": "object" }, + "ModelProviderDefaultSetParams": { + "properties": { + "providerId": { + "description": "Configured provider to use by default for new threads and unscoped model lists.", + "type": "string" + } + }, + "required": [ + "providerId" + ], + "type": "object" + }, "ModelProviderListParams": { "type": "object" }, @@ -8384,6 +8396,30 @@ "title": "ModelProvider/config/writeRequest", "type": "object" }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "modelProvider/default/set" + ], + "title": "ModelProvider/default/setRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/ModelProviderDefaultSetParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "ModelProvider/default/setRequest", + "type": "object" + }, { "properties": { "id": { diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 8fa3f62282..c3dd12e050 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -1968,6 +1968,30 @@ "title": "ModelProvider/config/writeRequest", "type": "object" }, + { + "properties": { + "id": { + "$ref": "#/definitions/v2/RequestId" + }, + "method": { + "enum": [ + "modelProvider/default/set" + ], + "title": "ModelProvider/default/setRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/v2/ModelProviderDefaultSetParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "ModelProvider/default/setRequest", + "type": "object" + }, { "properties": { "id": { @@ -16820,6 +16844,20 @@ "title": "ModelProviderConfigWriteResponse", "type": "object" }, + "ModelProviderDefaultSetParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "providerId": { + "description": "Configured provider to use by default for new threads and unscoped model lists.", + "type": "string" + } + }, + "required": [ + "providerId" + ], + "title": "ModelProviderDefaultSetParams", + "type": "object" + }, "ModelProviderError": { "$schema": "http://json-schema.org/draft-07/schema#", "description": "Structured JSON-RPC error data. Unknown errors must retain the client's normal fallback.", diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json index d3964185e0..4951cb455f 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.v2.schemas.json @@ -3956,6 +3956,30 @@ "title": "ModelProvider/config/writeRequest", "type": "object" }, + { + "properties": { + "id": { + "$ref": "#/definitions/RequestId" + }, + "method": { + "enum": [ + "modelProvider/default/set" + ], + "title": "ModelProvider/default/setRequestMethod", + "type": "string" + }, + "params": { + "$ref": "#/definitions/ModelProviderDefaultSetParams" + } + }, + "required": [ + "id", + "method", + "params" + ], + "title": "ModelProvider/default/setRequest", + "type": "object" + }, { "properties": { "id": { @@ -12774,6 +12798,20 @@ "title": "ModelProviderConfigWriteResponse", "type": "object" }, + "ModelProviderDefaultSetParams": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "providerId": { + "description": "Configured provider to use by default for new threads and unscoped model lists.", + "type": "string" + } + }, + "required": [ + "providerId" + ], + "title": "ModelProviderDefaultSetParams", + "type": "object" + }, "ModelProviderError": { "$schema": "http://json-schema.org/draft-07/schema#", "description": "Structured JSON-RPC error data. Unknown errors must retain the client's normal fallback.", diff --git a/codex-rs/app-server-protocol/schema/json/v2/ModelProviderDefaultSetParams.json b/codex-rs/app-server-protocol/schema/json/v2/ModelProviderDefaultSetParams.json new file mode 100644 index 0000000000..eb6f5255d3 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/json/v2/ModelProviderDefaultSetParams.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "providerId": { + "description": "Configured provider to use by default for new threads and unscoped model lists.", + "type": "string" + } + }, + "required": [ + "providerId" + ], + "title": "ModelProviderDefaultSetParams", + "type": "object" +} \ No newline at end of file diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst index 23499c4ca4..33a8250602 100644 Binary files a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst and b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-experimental.json.zst differ diff --git a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst index 7adf228b1a..a64fb047f4 100644 Binary files a/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst and b/codex-rs/app-server-protocol/schema/precomputed/app-server-exports-stable.json.zst differ diff --git a/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts b/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts index de12ebd404..7573b9afbf 100644 --- a/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts +++ b/codex-rs/app-server-protocol/schema/typescript/ClientRequest.ts @@ -52,6 +52,7 @@ import type { McpServerToolCallParams } from "./v2/McpServerToolCallParams"; import type { ModelListParams } from "./v2/ModelListParams"; import type { ModelProviderCapabilitiesReadParams } from "./v2/ModelProviderCapabilitiesReadParams"; import type { ModelProviderConfigWriteParams } from "./v2/ModelProviderConfigWriteParams"; +import type { ModelProviderDefaultSetParams } from "./v2/ModelProviderDefaultSetParams"; import type { ModelProviderListParams } from "./v2/ModelProviderListParams"; import type { PermissionProfileListParams } from "./v2/PermissionProfileListParams"; import type { PluginInstallParams } from "./v2/PluginInstallParams"; @@ -110,4 +111,4 @@ import type { WindowsSandboxSetupStartParams } from "./v2/WindowsSandboxSetupSta /** * Request from the client to the server. */ -export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/delete", id: RequestId, params: ThreadDeleteParams, } | { "method": "thread/unsubscribe", id: RequestId, params: ThreadUnsubscribeParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/goal/set", id: RequestId, params: ThreadGoalSetParams, } | { "method": "thread/goal/get", id: RequestId, params: ThreadGoalGetParams, } | { "method": "thread/goal/clear", id: RequestId, params: ThreadGoalClearParams, } | { "method": "thread/metadata/update", id: RequestId, params: ThreadMetadataUpdateParams, } | { "method": "thread/attachment/add", id: RequestId, params: ThreadAttachmentAddParams, } | { "method": "thread/attachment/list", id: RequestId, params: ThreadAttachmentListParams, } | { "method": "thread/attachmentOwner/list", id: RequestId, params: ThreadAttachmentOwnerListParams, } | { "method": "thread/attachment/remove", id: RequestId, params: ThreadAttachmentRemoveParams, } | { "method": "thread/section/move", id: RequestId, params: ThreadSectionMoveParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/shellCommand", id: RequestId, params: ThreadShellCommandParams, } | { "method": "thread/approveGuardianDeniedAction", id: RequestId, params: ThreadApproveGuardianDeniedActionParams, } | { "method": "thread/revert", id: RequestId, params: ThreadRevertParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "threadSection/list", id: RequestId, params: ThreadSectionListParams, } | { "method": "threadSection/create", id: RequestId, params: ThreadSectionCreateParams, } | { "method": "threadSection/update", id: RequestId, params: ThreadSectionUpdateParams, } | { "method": "threadSection/delete", id: RequestId, params: ThreadSectionDeleteParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "thread/turns/list", id: RequestId, params: ThreadTurnsListParams, } | { "method": "thread/items/list", id: RequestId, params: ThreadItemsListParams, } | { "method": "thread/inject_items", id: RequestId, params: ThreadInjectItemsParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "skills/extraRoots/set", id: RequestId, params: SkillsExtraRootsSetParams, } | { "method": "hooks/list", id: RequestId, params: HooksListParams, } | { "method": "marketplace/add", id: RequestId, params: MarketplaceAddParams, } | { "method": "marketplace/remove", id: RequestId, params: MarketplaceRemoveParams, } | { "method": "marketplace/upgrade", id: RequestId, params: MarketplaceUpgradeParams, } | { "method": "plugin/list", id: RequestId, params: PluginListParams, } | { "method": "plugin/installed", id: RequestId, params: PluginInstalledParams, } | { "method": "plugin/reconcile", id: RequestId, params: PluginReconcileParams, } | { "method": "plugin/read", id: RequestId, params: PluginReadParams, } | { "method": "plugin/skill/read", id: RequestId, params: PluginSkillReadParams, } | { "method": "plugin/share/save", id: RequestId, params: PluginShareSaveParams, } | { "method": "plugin/share/updateTargets", id: RequestId, params: PluginShareUpdateTargetsParams, } | { "method": "plugin/share/list", id: RequestId, params: PluginShareListParams, } | { "method": "plugin/share/checkout", id: RequestId, params: PluginShareCheckoutParams, } | { "method": "plugin/share/delete", id: RequestId, params: PluginShareDeleteParams, } | { "method": "app/read", id: RequestId, params: AppsReadParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "app/installed", id: RequestId, params: AppsInstalledParams, } | { "method": "fs/readFile", id: RequestId, params: FsReadFileParams, } | { "method": "fs/writeFile", id: RequestId, params: FsWriteFileParams, } | { "method": "fs/createDirectory", id: RequestId, params: FsCreateDirectoryParams, } | { "method": "fs/getMetadata", id: RequestId, params: FsGetMetadataParams, } | { "method": "fs/readDirectory", id: RequestId, params: FsReadDirectoryParams, } | { "method": "fs/remove", id: RequestId, params: FsRemoveParams, } | { "method": "fs/copy", id: RequestId, params: FsCopyParams, } | { "method": "fs/watch", id: RequestId, params: FsWatchParams, } | { "method": "fs/unwatch", id: RequestId, params: FsUnwatchParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "plugin/install", id: RequestId, params: PluginInstallParams, } | { "method": "plugin/uninstall", id: RequestId, params: PluginUninstallParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "account/gatewayOAuth/read", id: RequestId, params?: GatewayOAuthReadParams | null | undefined, } | { "method": "account/gatewayOAuth/login", id: RequestId, params?: GatewayOAuthLoginParams | null | undefined, } | { "method": "account/gatewayOAuth/cancel", id: RequestId, params: undefined, } | { "method": "modelProvider/list", id: RequestId, params: ModelProviderListParams, } | { "method": "modelProvider/config/write", id: RequestId, params: ModelProviderConfigWriteParams, } | { "method": "modelProvider/capabilities/read", id: RequestId, params: ModelProviderCapabilitiesReadParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "permissionProfile/list", id: RequestId, params: PermissionProfileListParams, } | { "method": "experimentalFeature/enablement/set", id: RequestId, params: ExperimentalFeatureEnablementSetParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mcpServer/reload", id: RequestId, params: undefined, } | { "method": "mcpServerStatus/list", id: RequestId, params: ListMcpServerStatusParams, } | { "method": "mcpServer/resource/read", id: RequestId, params: McpResourceReadParams, } | { "method": "mcpServer/tool/call", id: RequestId, params: McpServerToolCallParams, } | { "method": "windowsSandbox/setupStart", id: RequestId, params: WindowsSandboxSetupStartParams, } | { "method": "windowsSandbox/readiness", id: RequestId, params: undefined, } | { "method": "account/login/start", id: RequestId, params: LoginAccountParams, } | { "method": "account/login/cancel", id: RequestId, params: CancelLoginAccountParams, } | { "method": "account/logout", id: RequestId, params: undefined, } | { "method": "account/securitySetup/read", id: RequestId, params: undefined, } | { "method": "account/rateLimits/read", id: RequestId, params?: GetAccountRateLimitsParams | undefined, } | { "method": "account/rateLimitResetCredit/consume", id: RequestId, params: ConsumeAccountRateLimitResetCreditParams, } | { "method": "account/usage/read", id: RequestId, params?: GetAccountTokenUsageParams | undefined, } | { "method": "account/workspaceMessages/read", id: RequestId, params: undefined, } | { "method": "account/sendAddCreditsNudgeEmail", id: RequestId, params: SendAddCreditsNudgeEmailParams, } | { "method": "feedback/upload", id: RequestId, params: FeedbackUploadParams, } | { "method": "feedback/save", id: RequestId, params: FeedbackSaveParams, } | { "method": "command/exec", id: RequestId, params: CommandExecParams, } | { "method": "command/exec/write", id: RequestId, params: CommandExecWriteParams, } | { "method": "command/exec/terminate", id: RequestId, params: CommandExecTerminateParams, } | { "method": "command/exec/resize", id: RequestId, params: CommandExecResizeParams, } | { "method": "config/read", id: RequestId, params: ConfigReadParams, } | { "method": "externalAgentConfig/detect", id: RequestId, params: ExternalAgentConfigDetectParams, } | { "method": "externalAgentConfig/import", id: RequestId, params: ExternalAgentConfigImportParams, } | { "method": "externalAgentConfig/import/recordHistory", id: RequestId, params: ExternalAgentConfigImportHistoryRecordParams, } | { "method": "externalAgentConfig/import/readHistories", id: RequestId, params: undefined, } | { "method": "config/value/write", id: RequestId, params: ConfigValueWriteParams, } | { "method": "config/batchWrite", id: RequestId, params: ConfigBatchWriteParams, } | { "method": "configRequirements/read", id: RequestId, params: undefined, } | { "method": "account/read", id: RequestId, params: GetAccountParams, } | { "method": "getConversationSummary", id: RequestId, params: GetConversationSummaryParams, } | { "method": "gitDiffToRemote", id: RequestId, params: GitDiffToRemoteParams, } | { "method": "getAuthStatus", id: RequestId, params: GetAuthStatusParams, } | { "method": "fuzzyFileSearch", id: RequestId, params: FuzzyFileSearchParams, }; +export type ClientRequest ={ "method": "initialize", id: RequestId, params: InitializeParams, } | { "method": "thread/start", id: RequestId, params: ThreadStartParams, } | { "method": "thread/resume", id: RequestId, params: ThreadResumeParams, } | { "method": "thread/fork", id: RequestId, params: ThreadForkParams, } | { "method": "thread/archive", id: RequestId, params: ThreadArchiveParams, } | { "method": "thread/delete", id: RequestId, params: ThreadDeleteParams, } | { "method": "thread/unsubscribe", id: RequestId, params: ThreadUnsubscribeParams, } | { "method": "thread/name/set", id: RequestId, params: ThreadSetNameParams, } | { "method": "thread/goal/set", id: RequestId, params: ThreadGoalSetParams, } | { "method": "thread/goal/get", id: RequestId, params: ThreadGoalGetParams, } | { "method": "thread/goal/clear", id: RequestId, params: ThreadGoalClearParams, } | { "method": "thread/metadata/update", id: RequestId, params: ThreadMetadataUpdateParams, } | { "method": "thread/attachment/add", id: RequestId, params: ThreadAttachmentAddParams, } | { "method": "thread/attachment/list", id: RequestId, params: ThreadAttachmentListParams, } | { "method": "thread/attachmentOwner/list", id: RequestId, params: ThreadAttachmentOwnerListParams, } | { "method": "thread/attachment/remove", id: RequestId, params: ThreadAttachmentRemoveParams, } | { "method": "thread/section/move", id: RequestId, params: ThreadSectionMoveParams, } | { "method": "thread/unarchive", id: RequestId, params: ThreadUnarchiveParams, } | { "method": "thread/compact/start", id: RequestId, params: ThreadCompactStartParams, } | { "method": "thread/shellCommand", id: RequestId, params: ThreadShellCommandParams, } | { "method": "thread/approveGuardianDeniedAction", id: RequestId, params: ThreadApproveGuardianDeniedActionParams, } | { "method": "thread/revert", id: RequestId, params: ThreadRevertParams, } | { "method": "thread/list", id: RequestId, params: ThreadListParams, } | { "method": "threadSection/list", id: RequestId, params: ThreadSectionListParams, } | { "method": "threadSection/create", id: RequestId, params: ThreadSectionCreateParams, } | { "method": "threadSection/update", id: RequestId, params: ThreadSectionUpdateParams, } | { "method": "threadSection/delete", id: RequestId, params: ThreadSectionDeleteParams, } | { "method": "thread/loaded/list", id: RequestId, params: ThreadLoadedListParams, } | { "method": "thread/read", id: RequestId, params: ThreadReadParams, } | { "method": "thread/turns/list", id: RequestId, params: ThreadTurnsListParams, } | { "method": "thread/items/list", id: RequestId, params: ThreadItemsListParams, } | { "method": "thread/inject_items", id: RequestId, params: ThreadInjectItemsParams, } | { "method": "skills/list", id: RequestId, params: SkillsListParams, } | { "method": "skills/extraRoots/set", id: RequestId, params: SkillsExtraRootsSetParams, } | { "method": "hooks/list", id: RequestId, params: HooksListParams, } | { "method": "marketplace/add", id: RequestId, params: MarketplaceAddParams, } | { "method": "marketplace/remove", id: RequestId, params: MarketplaceRemoveParams, } | { "method": "marketplace/upgrade", id: RequestId, params: MarketplaceUpgradeParams, } | { "method": "plugin/list", id: RequestId, params: PluginListParams, } | { "method": "plugin/installed", id: RequestId, params: PluginInstalledParams, } | { "method": "plugin/reconcile", id: RequestId, params: PluginReconcileParams, } | { "method": "plugin/read", id: RequestId, params: PluginReadParams, } | { "method": "plugin/skill/read", id: RequestId, params: PluginSkillReadParams, } | { "method": "plugin/share/save", id: RequestId, params: PluginShareSaveParams, } | { "method": "plugin/share/updateTargets", id: RequestId, params: PluginShareUpdateTargetsParams, } | { "method": "plugin/share/list", id: RequestId, params: PluginShareListParams, } | { "method": "plugin/share/checkout", id: RequestId, params: PluginShareCheckoutParams, } | { "method": "plugin/share/delete", id: RequestId, params: PluginShareDeleteParams, } | { "method": "app/read", id: RequestId, params: AppsReadParams, } | { "method": "app/list", id: RequestId, params: AppsListParams, } | { "method": "app/installed", id: RequestId, params: AppsInstalledParams, } | { "method": "fs/readFile", id: RequestId, params: FsReadFileParams, } | { "method": "fs/writeFile", id: RequestId, params: FsWriteFileParams, } | { "method": "fs/createDirectory", id: RequestId, params: FsCreateDirectoryParams, } | { "method": "fs/getMetadata", id: RequestId, params: FsGetMetadataParams, } | { "method": "fs/readDirectory", id: RequestId, params: FsReadDirectoryParams, } | { "method": "fs/remove", id: RequestId, params: FsRemoveParams, } | { "method": "fs/copy", id: RequestId, params: FsCopyParams, } | { "method": "fs/watch", id: RequestId, params: FsWatchParams, } | { "method": "fs/unwatch", id: RequestId, params: FsUnwatchParams, } | { "method": "skills/config/write", id: RequestId, params: SkillsConfigWriteParams, } | { "method": "plugin/install", id: RequestId, params: PluginInstallParams, } | { "method": "plugin/uninstall", id: RequestId, params: PluginUninstallParams, } | { "method": "turn/start", id: RequestId, params: TurnStartParams, } | { "method": "turn/steer", id: RequestId, params: TurnSteerParams, } | { "method": "turn/interrupt", id: RequestId, params: TurnInterruptParams, } | { "method": "review/start", id: RequestId, params: ReviewStartParams, } | { "method": "model/list", id: RequestId, params: ModelListParams, } | { "method": "account/gatewayOAuth/read", id: RequestId, params?: GatewayOAuthReadParams | null | undefined, } | { "method": "account/gatewayOAuth/login", id: RequestId, params?: GatewayOAuthLoginParams | null | undefined, } | { "method": "account/gatewayOAuth/cancel", id: RequestId, params: undefined, } | { "method": "modelProvider/list", id: RequestId, params: ModelProviderListParams, } | { "method": "modelProvider/config/write", id: RequestId, params: ModelProviderConfigWriteParams, } | { "method": "modelProvider/default/set", id: RequestId, params: ModelProviderDefaultSetParams, } | { "method": "modelProvider/capabilities/read", id: RequestId, params: ModelProviderCapabilitiesReadParams, } | { "method": "experimentalFeature/list", id: RequestId, params: ExperimentalFeatureListParams, } | { "method": "permissionProfile/list", id: RequestId, params: PermissionProfileListParams, } | { "method": "experimentalFeature/enablement/set", id: RequestId, params: ExperimentalFeatureEnablementSetParams, } | { "method": "mcpServer/oauth/login", id: RequestId, params: McpServerOauthLoginParams, } | { "method": "config/mcpServer/reload", id: RequestId, params: undefined, } | { "method": "mcpServerStatus/list", id: RequestId, params: ListMcpServerStatusParams, } | { "method": "mcpServer/resource/read", id: RequestId, params: McpResourceReadParams, } | { "method": "mcpServer/tool/call", id: RequestId, params: McpServerToolCallParams, } | { "method": "windowsSandbox/setupStart", id: RequestId, params: WindowsSandboxSetupStartParams, } | { "method": "windowsSandbox/readiness", id: RequestId, params: undefined, } | { "method": "account/login/start", id: RequestId, params: LoginAccountParams, } | { "method": "account/login/cancel", id: RequestId, params: CancelLoginAccountParams, } | { "method": "account/logout", id: RequestId, params: undefined, } | { "method": "account/securitySetup/read", id: RequestId, params: undefined, } | { "method": "account/rateLimits/read", id: RequestId, params?: GetAccountRateLimitsParams | undefined, } | { "method": "account/rateLimitResetCredit/consume", id: RequestId, params: ConsumeAccountRateLimitResetCreditParams, } | { "method": "account/usage/read", id: RequestId, params?: GetAccountTokenUsageParams | undefined, } | { "method": "account/workspaceMessages/read", id: RequestId, params: undefined, } | { "method": "account/sendAddCreditsNudgeEmail", id: RequestId, params: SendAddCreditsNudgeEmailParams, } | { "method": "feedback/upload", id: RequestId, params: FeedbackUploadParams, } | { "method": "feedback/save", id: RequestId, params: FeedbackSaveParams, } | { "method": "command/exec", id: RequestId, params: CommandExecParams, } | { "method": "command/exec/write", id: RequestId, params: CommandExecWriteParams, } | { "method": "command/exec/terminate", id: RequestId, params: CommandExecTerminateParams, } | { "method": "command/exec/resize", id: RequestId, params: CommandExecResizeParams, } | { "method": "config/read", id: RequestId, params: ConfigReadParams, } | { "method": "externalAgentConfig/detect", id: RequestId, params: ExternalAgentConfigDetectParams, } | { "method": "externalAgentConfig/import", id: RequestId, params: ExternalAgentConfigImportParams, } | { "method": "externalAgentConfig/import/recordHistory", id: RequestId, params: ExternalAgentConfigImportHistoryRecordParams, } | { "method": "externalAgentConfig/import/readHistories", id: RequestId, params: undefined, } | { "method": "config/value/write", id: RequestId, params: ConfigValueWriteParams, } | { "method": "config/batchWrite", id: RequestId, params: ConfigBatchWriteParams, } | { "method": "configRequirements/read", id: RequestId, params: undefined, } | { "method": "account/read", id: RequestId, params: GetAccountParams, } | { "method": "getConversationSummary", id: RequestId, params: GetConversationSummaryParams, } | { "method": "gitDiffToRemote", id: RequestId, params: GitDiffToRemoteParams, } | { "method": "getAuthStatus", id: RequestId, params: GetAuthStatusParams, } | { "method": "fuzzyFileSearch", id: RequestId, params: FuzzyFileSearchParams, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/ModelProviderDefaultSetParams.ts b/codex-rs/app-server-protocol/schema/typescript/v2/ModelProviderDefaultSetParams.ts new file mode 100644 index 0000000000..c06837c8b6 --- /dev/null +++ b/codex-rs/app-server-protocol/schema/typescript/v2/ModelProviderDefaultSetParams.ts @@ -0,0 +1,9 @@ +// GENERATED CODE! DO NOT MODIFY BY HAND! + +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +export type ModelProviderDefaultSetParams = { +/** + * Configured provider to use by default for new threads and unscoped model lists. + */ +providerId: string, }; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts index c3e0d64de9..e3f53d94cb 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/index.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/index.ts @@ -349,6 +349,7 @@ export type { ModelProviderCapabilitiesReadParams } from "./ModelProviderCapabil export type { ModelProviderCapabilitiesReadResponse } from "./ModelProviderCapabilitiesReadResponse"; export type { ModelProviderConfigWriteParams } from "./ModelProviderConfigWriteParams"; export type { ModelProviderConfigWriteResponse } from "./ModelProviderConfigWriteResponse"; +export type { ModelProviderDefaultSetParams } from "./ModelProviderDefaultSetParams"; export type { ModelProviderError } from "./ModelProviderError"; export type { ModelProviderListParams } from "./ModelProviderListParams"; export type { ModelProviderListResponse } from "./ModelProviderListResponse"; diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index be2fc3f0e9..358a8c17fd 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -1212,6 +1212,12 @@ client_request_definitions! { serialization: global("config"), response: v2::ModelProviderConfigWriteResponse, }, + ModelProviderDefaultSet => "modelProvider/default/set" { + params: v2::ModelProviderDefaultSetParams, + serialization: global("config"), + manual_payload_conversion: manual, + response: v2::ConfigWriteResponse, + }, ModelProviderCapabilitiesRead => "modelProvider/capabilities/read" { params: v2::ModelProviderCapabilitiesReadParams, serialization: None, diff --git a/codex-rs/app-server-protocol/src/protocol/v2/model_provider.rs b/codex-rs/app-server-protocol/src/protocol/v2/model_provider.rs index 85d360c1fd..0e92cda7ee 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2/model_provider.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2/model_provider.rs @@ -248,3 +248,11 @@ pub struct ModelProviderConfigWriteParams { pub struct ModelProviderConfigWriteResponse { pub provider: ModelProviderSummary, } + +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema, TS)] +#[serde(rename_all = "camelCase")] +#[ts(export_to = "v2/")] +pub struct ModelProviderDefaultSetParams { + /// Configured provider to use by default for new threads and unscoped model lists. + pub provider_id: String, +} diff --git a/codex-rs/app-server/README.md b/codex-rs/app-server/README.md index 6876405c7d..dc55818bff 100644 --- a/codex-rs/app-server/README.md +++ b/codex-rs/app-server/README.md @@ -121,15 +121,17 @@ denial limit, and interrupted status; neither emits a separate `Error` event. # Model catalog provider requirements -`model/list` accepts an optional `modelProvider` to list models for a configured provider -other than the startup default. For example, `{"modelProvider": "my_gateway"}` returns that -provider's models after the user's default changes. Omit it to retain the startup provider -and caching behavior. Explicit selections use the provider definitions loaded at startup. Restart the server -to pick up edits to those definitions. An unknown selector returns JSON-RPC error +`modelProvider/default/set` selects a configured provider for new threads and unscoped model lists. +Send `{"providerId": "my_gateway"}`. The response uses the same `ConfigWriteResponse` as other config writes. +An effective selection refreshes the catalog on its next read. Editing the active provider through +`modelProvider/config/write` also refreshes that snapshot. + +`model/list` uses the current default when `modelProvider` is omitted. Pass a provider ID to list +models for a chat that retained its provider after a default change. An unknown selector returns JSON-RPC error `-32600` with `data.type = "modelProviderNotConfigured"` and the requested `modelProvider`. `model/list` checks its selected provider, and periodic model catalog refreshes check the -startup provider, against current managed provider requirements. If that provider no longer +current default provider, against current managed provider requirements. If that provider no longer complies, `model/list` returns JSON-RPC error `-32600` asking the client to restart Codex, and background refreshes skip the old endpoint. Requirement load failures also block these operations. Checks apply even when the catalog is cached. diff --git a/codex-rs/app-server/src/config_manager_service.rs b/codex-rs/app-server/src/config_manager_service.rs index 25d51ed2e0..1615d1430e 100644 --- a/codex-rs/app-server/src/config_manager_service.rs +++ b/codex-rs/app-server/src/config_manager_service.rs @@ -347,13 +347,24 @@ impl ConfigManager { )); } + self.persist_user_edits(&layers, &user_layer, provided_path, edits) + .await + } + + async fn persist_user_edits( + &self, + layers: &ConfigLayerStack, + user_layer: &ConfigLayerEntry, + provided_path: AbsolutePathBuf, + edits: Vec<(String, JsonValue, MergeStrategy)>, + ) -> Result { let mut user_config = user_layer.config.clone(); let mut credential_provider_edits = CredentialProviderEdits::new(&user_config); let mut parsed_segments = Vec::new(); let mut config_edits = Vec::new(); for (key_path, value, strategy) in edits.into_iter() { - let mut segments = writable_key_path(&layers, &key_path)?; + let mut segments = writable_key_path(layers, &key_path)?; if (value.is_null() || matches!(strategy, MergeStrategy::Upsert)) && let Some(pattern) = shell_environment_filter_entry(&user_config, &segments) .map(|(pattern, _)| pattern.clone()) diff --git a/codex-rs/app-server/src/config_manager_service_model_providers.rs b/codex-rs/app-server/src/config_manager_service_model_providers.rs index 2418513b86..2a2b85b443 100644 --- a/codex-rs/app-server/src/config_manager_service_model_providers.rs +++ b/codex-rs/app-server/src/config_manager_service_model_providers.rs @@ -3,7 +3,11 @@ use super::ConfigManager; use super::ConfigManagerError; use super::TomlValue; +use codex_app_server_protocol::ConfigWriteErrorCode; +use codex_app_server_protocol::ConfigWriteResponse; use codex_app_server_protocol::GatewayAuth; +use codex_app_server_protocol::MergeStrategy; +use codex_app_server_protocol::ModelProviderDefaultSetParams; use codex_app_server_protocol::ModelProviderListParams; use codex_app_server_protocol::ModelProviderListResponse; use codex_app_server_protocol::ModelProviderSummary; @@ -62,6 +66,50 @@ pub(super) fn valid_endpoint(value: &str) -> bool { } impl ConfigManager { + pub(crate) async fn model_provider_default_set( + &self, + params: ModelProviderDefaultSetParams, + ) -> Result { + let layers = self + .load_thread_agnostic_config() + .await + .map_err(|err| ConfigManagerError::io("failed to read providers", err))?; + let user_layer = + writable_user_layer(&layers, self.loader_overrides()).ok_or_else(|| { + ConfigManagerError::write( + ConfigWriteErrorCode::ConfigLayerReadonly, + "The user configuration is not writable.", + ) + })?; + let provider_id = params.provider_id; + if !built_in_model_providers(/*openai_base_url*/ None).contains_key(&provider_id) + && layers + .effective_config() + .get("model_providers") + .and_then(|providers| providers.get(&provider_id)) + .is_none() + { + return Err(ConfigManagerError::write( + ConfigWriteErrorCode::ConfigValidationError, + format!("Model provider `{provider_id}` is not configured."), + )); + } + let user_path = self + .user_config_path() + .map_err(|err| ConfigManagerError::io("failed to resolve user config path", err))?; + self.persist_user_edits( + &layers, + user_layer, + user_path, + vec![( + "model_provider".into(), + provider_id.into(), + MergeStrategy::Replace, + )], + ) + .await + } + pub(crate) async fn model_provider_list( &self, _params: ModelProviderListParams, diff --git a/codex-rs/app-server/src/config_manager_service_tests.rs b/codex-rs/app-server/src/config_manager_service_tests.rs index e663d2ef64..b0bcb63699 100644 --- a/codex-rs/app-server/src/config_manager_service_tests.rs +++ b/codex-rs/app-server/src/config_manager_service_tests.rs @@ -3454,6 +3454,29 @@ async fn cloud_desktop_storage_requirements_control_reads_and_writes() { .expect("unmanaged desktop settings stay writable"); } +#[tokio::test] +async fn model_provider_default_set_reports_a_cli_override() -> Result<()> { + let tmp = tempdir()?; + std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "")?; + let service = ConfigManager::new_for_tests( + tmp.path().to_path_buf(), + vec![("model_provider".into(), TomlValue::String("openai".into()))], + LoaderOverrides::without_managed_config_for_tests(), + CloudConfigBundleLoader::default(), + ); + let result = service + .model_provider_default_set(codex_app_server_protocol::ModelProviderDefaultSetParams { + provider_id: "amazon-bedrock".into(), + }) + .await?; + assert_eq!(result.status, WriteStatus::OkOverridden); + assert_eq!( + result.overridden_metadata.unwrap().effective_value, + serde_json::json!("openai") + ); + Ok(()) +} + #[tokio::test] async fn model_provider_list_allows_user_overrides_of_system_defaults() -> Result<()> { use codex_app_server_protocol::ModelProviderListParams; @@ -3550,6 +3573,20 @@ async fn model_provider_list_allows_user_overrides_of_system_defaults() -> Resul .model_provider_list(ModelProviderListParams {}) .await?; assert_eq!(response.can_change_default, can_change_default); + if ignore_user_config { + let error = service + .model_provider_default_set( + codex_app_server_protocol::ModelProviderDefaultSetParams { + provider_id: "openai".into(), + }, + ) + .await + .unwrap_err(); + assert_eq!( + error.write_error_code(), + Some(ConfigWriteErrorCode::ConfigLayerReadonly) + ); + } assert_eq!(response.default_provider_id, "team"); assert_eq!( serde_json::to_value(response.data)?, diff --git a/codex-rs/app-server/src/message_processor.rs b/codex-rs/app-server/src/message_processor.rs index 70938064bf..fd89626e02 100644 --- a/codex-rs/app-server/src/message_processor.rs +++ b/codex-rs/app-server/src/message_processor.rs @@ -1353,6 +1353,11 @@ impl MessageProcessor { .model_provider_config_write(params) .await .map(|r| Some(r.into())), + ClientRequest::ModelProviderDefaultSet { params, .. } => self + .config_processor + .model_provider_default_set(params) + .await + .map(Some), ClientRequest::ModelProviderCapabilitiesRead { .. } => self .config_processor .model_provider_capabilities_read() diff --git a/codex-rs/app-server/src/model_catalog.rs b/codex-rs/app-server/src/model_catalog.rs index c2c54db108..cba5524f7e 100644 --- a/codex-rs/app-server/src/model_catalog.rs +++ b/codex-rs/app-server/src/model_catalog.rs @@ -63,7 +63,7 @@ impl ModelCatalog { self.config_manager.load_config_layers(cwd).await } - /// Marks catalog configuration stale after an account transition. + /// Reloads catalog configuration on the next read. pub(crate) async fn invalidate(&self) { self.state.lock().await.needs_reload = true; } diff --git a/codex-rs/app-server/src/request_processors/catalog_processor.rs b/codex-rs/app-server/src/request_processors/catalog_processor.rs index ca7d5c498c..b403311524 100644 --- a/codex-rs/app-server/src/request_processors/catalog_processor.rs +++ b/codex-rs/app-server/src/request_processors/catalog_processor.rs @@ -187,12 +187,10 @@ impl CatalogRequestProcessor { let (config, models_manager) = match params.model_provider.as_deref() { None => (active_config, active_models_manager), Some(provider_id) => { - let config = config_for_provider(&self.config, provider_id)?; - if provider_id == active_config.model_provider_id - && config.model_provider == active_config.model_provider - { + if provider_id == active_config.model_provider_id { (active_config, active_models_manager) } else { + let config = config_for_provider(&active_config, provider_id)?; // Temporary catalogs must not replace the active provider's disk cache. let manager = self.thread_manager.temporary_models_manager_for_config( &config, diff --git a/codex-rs/app-server/src/request_processors/config_processor.rs b/codex-rs/app-server/src/request_processors/config_processor.rs index 79453deeae..1e7663e6f7 100644 --- a/codex-rs/app-server/src/request_processors/config_processor.rs +++ b/codex-rs/app-server/src/request_processors/config_processor.rs @@ -240,6 +240,25 @@ impl ConfigRequestProcessor { Ok(response) } + pub(crate) fn model_provider_default_set( + &self, + params: codex_app_server_protocol::ModelProviderDefaultSetParams, + ) -> futures::future::BoxFuture<'_, Result> { + // Keep provider config resolution off the shared request dispatcher stack. + Box::pin(async move { + let result = self + .config_manager + .model_provider_default_set(params) + .await + .map_err(map_error); + let response = self.handle_config_mutation_result(result).await?; + if response.status == codex_app_server_protocol::WriteStatus::Ok { + self.model_catalog.invalidate().await; + } + Ok(ClientResponsePayload::ModelProviderDefaultSet(response)) + }) + } + pub(crate) async fn model_provider_capabilities_read( &self, ) -> Result { diff --git a/codex-rs/app-server/tests/suite/v2/config_model_provider_requirements_tests.rs b/codex-rs/app-server/tests/suite/v2/config_model_provider_requirements_tests.rs index 4533129262..f7ca0914c5 100644 --- a/codex-rs/app-server/tests/suite/v2/config_model_provider_requirements_tests.rs +++ b/codex-rs/app-server/tests/suite/v2/config_model_provider_requirements_tests.rs @@ -96,6 +96,20 @@ X-Local = "no" timeout(Duration::from_secs(/*secs*/ 60), server.read_response(id)).await??; assert_eq!(started.model_provider, "gateway"); + let id = server + .send_request( + "modelProvider/default/set", + Some(json!({"providerId": "openai"})), + ) + .await?; + let rejected = server + .read_stream_until_error_message(RequestId::Integer(id)) + .await?; + assert_eq!( + rejected.error.data, + Some(json!({"config_write_error_code": "configRequirementReadonly"})) + ); + for (key, value) in [ ("model_provider", json!("openai")), ( diff --git a/codex-rs/app-server/tests/suite/v2/model_list_requirements_tests.rs b/codex-rs/app-server/tests/suite/v2/model_list_requirements_tests.rs index c5647915f2..f86c0895ea 100644 --- a/codex-rs/app-server/tests/suite/v2/model_list_requirements_tests.rs +++ b/codex-rs/app-server/tests/suite/v2/model_list_requirements_tests.rs @@ -5,12 +5,14 @@ use app_test_support::ChatGptAuthFixture; use app_test_support::TestAppServer; use app_test_support::write_chatgpt_auth; use codex_app_server_protocol::ClientRequest; +use codex_app_server_protocol::ConfigWriteResponse; use codex_app_server_protocol::LoginAccountResponse; use codex_app_server_protocol::LogoutAccountResponse; use codex_app_server_protocol::ModelListParams; use codex_app_server_protocol::ModelListResponse; use codex_app_server_protocol::ModelProviderConfigWriteResponse; use codex_app_server_protocol::RequestId; +use codex_app_server_protocol::WriteStatus; use codex_config::types::AuthCredentialsStoreMode; use codex_protocol::openai_models::ModelInfo; use codex_protocol::openai_models::ModelsResponse; @@ -307,7 +309,20 @@ name = 'Other' ) .await?; let _: ModelProviderConfigWriteResponse = server.read_response(id).await?; - assert_eq!(list_models(&mut server).await?.data[0].id, "saved-model"); + let saved = list_models(&mut server).await?; + assert_eq!(saved.data[0].id, "saved-model"); + let id = server + .send_request( + "modelProvider/default/set", + Some(json!({"providerId": "other"})), + ) + .await?; + let _: ConfigWriteResponse = server.read_response(id).await?; + let id = server + .send_request("model/list", Some(json!({"modelProvider": "gateway"}))) + .await?; + let retained: ModelListResponse = server.read_response(id).await?; + assert_eq!(retained, saved); Ok(()) } @@ -455,6 +470,39 @@ requires_openai_auth = true let disk_catalog: ModelsResponse = serde_json::from_slice(&std::fs::read(&cache_path)?)?; assert_eq!(disk_catalog, initial_cache); assert_eq!(list_models(&mut server).await?, initial); + + let id = server + .send_request( + "modelProvider/default/set", + Some(json!({"providerId": "second"})), + ) + .await?; + let saved: ConfigWriteResponse = server.read_response(id).await?; + assert_eq!(saved.status, WriteStatus::Ok); + assert_eq!(list_models(&mut server).await?, selected); + + let id = server + .send_request( + "modelProvider/default/set", + Some(json!({"providerId": "missing"})), + ) + .await?; + let rejected = server + .read_stream_until_error_message(RequestId::Integer(id)) + .await?; + assert_eq!( + rejected.error.data, + Some(json!({"config_write_error_code": "configValidationError"})) + ); + assert_eq!(list_models(&mut server).await?, selected); + let id = server + .send_request( + "modelProvider/default/set", + Some(json!({"providerId": "first"})), + ) + .await?; + let _: ConfigWriteResponse = server.read_response(id).await?; + assert_eq!(list_models(&mut server).await?, initial); Ok(()) } diff --git a/sdk/python/src/openai_codex/generated/v2_all.py b/sdk/python/src/openai_codex/generated/v2_all.py index 55e776a26b..6f8b9607f5 100644 --- a/sdk/python/src/openai_codex/generated/v2_all.py +++ b/sdk/python/src/openai_codex/generated/v2_all.py @@ -2977,6 +2977,19 @@ class ModelProviderCapabilitiesReadResponse(BaseModel): web_search: Annotated[bool, Field(alias="webSearch")] +class ModelProviderDefaultSetParams(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + provider_id: Annotated[ + str, + Field( + alias="providerId", + description="Configured provider to use by default for new threads and unscoped model lists.", + ), + ] + + class ModelProviderMismatchModelProviderError(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -8171,6 +8184,17 @@ class ModelProviderListRequest(BaseModel): params: ModelProviderListParams +class ModelProviderDefaultSetRequest(BaseModel): + model_config = ConfigDict( + populate_by_name=True, + ) + id: RequestId + method: Annotated[ + Literal["modelProvider/default/set"], Field(title="ModelProvider/default/setRequestMethod") + ] + params: ModelProviderDefaultSetParams + + class ModelProviderCapabilitiesReadRequest(BaseModel): model_config = ConfigDict( populate_by_name=True, @@ -13922,6 +13946,7 @@ class ClientRequest( | AccountGatewayOAuthCancelRequest | ModelProviderListRequest | ModelProviderConfigWriteRequest + | ModelProviderDefaultSetRequest | ModelProviderCapabilitiesReadRequest | ExperimentalFeatureListRequest | PermissionProfileListRequest @@ -14034,6 +14059,7 @@ class ClientRequest( | AccountGatewayOAuthCancelRequest | ModelProviderListRequest | ModelProviderConfigWriteRequest + | ModelProviderDefaultSetRequest | ModelProviderCapabilitiesReadRequest | ExperimentalFeatureListRequest | PermissionProfileListRequest