mirror of
https://github.com/openai/codex.git
synced 2026-11-02 00:18:52 +00:00
app-server: drop legacy profile config surface (#24067)
## Why Legacy `[profiles.<name>]` config tables and the legacy `profile` selector are being retired in favor of profile files selected with `--profile <name>`. After #23886 removed the CLI-side legacy profile plumbing, the app-server config surface still exposed those fields and still carried conversion code for the old protocol shape. ## What changed - Remove `profile`, `profiles`, and `ProfileV2` from the app-server config protocol/schema output so `config/read` no longer returns legacy profile config. - Drop the old v1 `UserSavedConfig` profile conversion path from `config`. - Reject new app-server config writes under `profiles.*` with the same migration direction used for `profile`, while still allowing callers to clear existing legacy profile tables. - Refresh app-server config coverage and the experimental API README example around the remaining `Config` nesting path. ## Verification - Added config-manager coverage that `config/read` omits legacy profile config, `profiles.*` writes are rejected, and existing legacy profile tables can still be cleared. - Updated the v2 config RPC test to cover the rejected `profiles.*` batch-write path.
This commit is contained in:
@@ -6546,4 +6546,4 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "ServerNotification"
|
"title": "ServerNotification"
|
||||||
}
|
}
|
||||||
-114
@@ -7361,19 +7361,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"profile": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"profiles": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"$ref": "#/definitions/v2/ProfileV2"
|
|
||||||
},
|
|
||||||
"default": {},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"review_model": {
|
"review_model": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
@@ -13170,107 +13157,6 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"ProfileV2": {
|
|
||||||
"additionalProperties": true,
|
|
||||||
"properties": {
|
|
||||||
"approval_policy": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/v2/AskForApproval"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"approvals_reviewer": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/v2/ApprovalsReviewer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "[UNSTABLE] Optional profile-level override for where approval requests are routed for review. If omitted, the enclosing config default is used."
|
|
||||||
},
|
|
||||||
"chatgpt_base_url": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_provider": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_reasoning_effort": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/v2/ReasoningEffort"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_reasoning_summary": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/v2/ReasoningSummary"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_verbosity": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/v2/Verbosity"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"service_tier": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tools": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/v2/ToolsV2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"web_search": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/v2/WebSearchMode"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"RateLimitReachedType": {
|
"RateLimitReachedType": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"rate_limit_reached",
|
"rate_limit_reached",
|
||||||
|
|||||||
-114
@@ -3730,19 +3730,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"profile": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"profiles": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"$ref": "#/definitions/ProfileV2"
|
|
||||||
},
|
|
||||||
"default": {},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"review_model": {
|
"review_model": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
@@ -9699,107 +9686,6 @@
|
|||||||
],
|
],
|
||||||
"type": "object"
|
"type": "object"
|
||||||
},
|
},
|
||||||
"ProfileV2": {
|
|
||||||
"additionalProperties": true,
|
|
||||||
"properties": {
|
|
||||||
"approval_policy": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/AskForApproval"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"approvals_reviewer": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ApprovalsReviewer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "[UNSTABLE] Optional profile-level override for where approval requests are routed for review. If omitted, the enclosing config default is used."
|
|
||||||
},
|
|
||||||
"chatgpt_base_url": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_provider": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_reasoning_effort": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ReasoningEffort"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_reasoning_summary": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ReasoningSummary"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_verbosity": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/Verbosity"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"service_tier": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tools": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ToolsV2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"web_search": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/WebSearchMode"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"RateLimitReachedType": {
|
"RateLimitReachedType": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"rate_limit_reached",
|
"rate_limit_reached",
|
||||||
|
|||||||
@@ -352,19 +352,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"profile": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"profiles": {
|
|
||||||
"additionalProperties": {
|
|
||||||
"$ref": "#/definitions/ProfileV2"
|
|
||||||
},
|
|
||||||
"default": {},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"review_model": {
|
"review_model": {
|
||||||
"type": [
|
"type": [
|
||||||
"string",
|
"string",
|
||||||
@@ -642,107 +629,6 @@
|
|||||||
],
|
],
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"ProfileV2": {
|
|
||||||
"additionalProperties": true,
|
|
||||||
"properties": {
|
|
||||||
"approval_policy": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/AskForApproval"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"approvals_reviewer": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ApprovalsReviewer"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "[UNSTABLE] Optional profile-level override for where approval requests are routed for review. If omitted, the enclosing config default is used."
|
|
||||||
},
|
|
||||||
"chatgpt_base_url": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_provider": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_reasoning_effort": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ReasoningEffort"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_reasoning_summary": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ReasoningSummary"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"model_verbosity": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/Verbosity"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"service_tier": {
|
|
||||||
"type": [
|
|
||||||
"string",
|
|
||||||
"null"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tools": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/ToolsV2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"web_search": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"$ref": "#/definitions/WebSearchMode"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"ReasoningEffort": {
|
"ReasoningEffort": {
|
||||||
"description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning",
|
"description": "See https://platform.openai.com/docs/guides/reasoning?api-mode=responses#get-started-with-reasoning",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|||||||
+1
-2
@@ -12,7 +12,6 @@ import type { AnalyticsConfig } from "./AnalyticsConfig";
|
|||||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
||||||
import type { AskForApproval } from "./AskForApproval";
|
import type { AskForApproval } from "./AskForApproval";
|
||||||
import type { ForcedChatgptWorkspaceIds } from "./ForcedChatgptWorkspaceIds";
|
import type { ForcedChatgptWorkspaceIds } from "./ForcedChatgptWorkspaceIds";
|
||||||
import type { ProfileV2 } from "./ProfileV2";
|
|
||||||
import type { SandboxMode } from "./SandboxMode";
|
import type { SandboxMode } from "./SandboxMode";
|
||||||
import type { SandboxWorkspaceWrite } from "./SandboxWorkspaceWrite";
|
import type { SandboxWorkspaceWrite } from "./SandboxWorkspaceWrite";
|
||||||
import type { ToolsV2 } from "./ToolsV2";
|
import type { ToolsV2 } from "./ToolsV2";
|
||||||
@@ -21,4 +20,4 @@ export type Config = {model: string | null, review_model: string | null, model_c
|
|||||||
* [UNSTABLE] Optional default for where approval requests are routed for
|
* [UNSTABLE] Optional default for where approval requests are routed for
|
||||||
* review.
|
* review.
|
||||||
*/
|
*/
|
||||||
approvals_reviewer: ApprovalsReviewer | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: ForcedChatgptWorkspaceIds | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, profile: string | null, profiles: { [key in string]?: ProfileV2 }, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: string | null, analytics: AnalyticsConfig | null, desktop: { [key in string]?: JsonValue } | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
|
approvals_reviewer: ApprovalsReviewer | null, sandbox_mode: SandboxMode | null, sandbox_workspace_write: SandboxWorkspaceWrite | null, forced_chatgpt_workspace_id: ForcedChatgptWorkspaceIds | null, forced_login_method: ForcedLoginMethod | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, instructions: string | null, developer_instructions: string | null, compact_prompt: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, service_tier: string | null, analytics: AnalyticsConfig | null, desktop: { [key in string]?: JsonValue } | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
// 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.
|
|
||||||
import type { ReasoningEffort } from "../ReasoningEffort";
|
|
||||||
import type { ReasoningSummary } from "../ReasoningSummary";
|
|
||||||
import type { Verbosity } from "../Verbosity";
|
|
||||||
import type { WebSearchMode } from "../WebSearchMode";
|
|
||||||
import type { JsonValue } from "../serde_json/JsonValue";
|
|
||||||
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
|
|
||||||
import type { AskForApproval } from "./AskForApproval";
|
|
||||||
import type { ToolsV2 } from "./ToolsV2";
|
|
||||||
|
|
||||||
export type ProfileV2 = {model: string | null, model_provider: string | null, approval_policy: AskForApproval | null, /**
|
|
||||||
* [UNSTABLE] Optional profile-level override for where approval requests
|
|
||||||
* are routed for review. If omitted, the enclosing config default is
|
|
||||||
* used.
|
|
||||||
*/
|
|
||||||
approvals_reviewer: ApprovalsReviewer | null, service_tier: string | null, model_reasoning_effort: ReasoningEffort | null, model_reasoning_summary: ReasoningSummary | null, model_verbosity: Verbosity | null, web_search: WebSearchMode | null, tools: ToolsV2 | null, chatgpt_base_url: string | null} & ({ [key in string]?: number | string | boolean | Array<JsonValue> | { [key in string]?: JsonValue } | null });
|
|
||||||
@@ -308,7 +308,6 @@ export type { ProcessExitedNotification } from "./ProcessExitedNotification";
|
|||||||
export type { ProcessOutputDeltaNotification } from "./ProcessOutputDeltaNotification";
|
export type { ProcessOutputDeltaNotification } from "./ProcessOutputDeltaNotification";
|
||||||
export type { ProcessOutputStream } from "./ProcessOutputStream";
|
export type { ProcessOutputStream } from "./ProcessOutputStream";
|
||||||
export type { ProcessTerminalSize } from "./ProcessTerminalSize";
|
export type { ProcessTerminalSize } from "./ProcessTerminalSize";
|
||||||
export type { ProfileV2 } from "./ProfileV2";
|
|
||||||
export type { RateLimitReachedType } from "./RateLimitReachedType";
|
export type { RateLimitReachedType } from "./RateLimitReachedType";
|
||||||
export type { RateLimitSnapshot } from "./RateLimitSnapshot";
|
export type { RateLimitSnapshot } from "./RateLimitSnapshot";
|
||||||
export type { RateLimitWindow } from "./RateLimitWindow";
|
export type { RateLimitWindow } from "./RateLimitWindow";
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ pub use protocol::v1::InitializeParams;
|
|||||||
pub use protocol::v1::InitializeResponse;
|
pub use protocol::v1::InitializeResponse;
|
||||||
pub use protocol::v1::InterruptConversationResponse;
|
pub use protocol::v1::InterruptConversationResponse;
|
||||||
pub use protocol::v1::LoginApiKeyParams;
|
pub use protocol::v1::LoginApiKeyParams;
|
||||||
pub use protocol::v1::Profile;
|
|
||||||
pub use protocol::v1::SandboxSettings;
|
pub use protocol::v1::SandboxSettings;
|
||||||
pub use protocol::v1::Tools;
|
pub use protocol::v1::Tools;
|
||||||
pub use protocol::v1::UserSavedConfig;
|
pub use protocol::v1::UserSavedConfig;
|
||||||
|
|||||||
@@ -209,20 +209,6 @@ pub struct UserSavedConfig {
|
|||||||
pub model_reasoning_summary: Option<ReasoningSummary>,
|
pub model_reasoning_summary: Option<ReasoningSummary>,
|
||||||
pub model_verbosity: Option<Verbosity>,
|
pub model_verbosity: Option<Verbosity>,
|
||||||
pub tools: Option<Tools>,
|
pub tools: Option<Tools>,
|
||||||
pub profile: Option<String>,
|
|
||||||
pub profiles: HashMap<String, Profile>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, JsonSchema, TS)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
pub struct Profile {
|
|
||||||
pub model: Option<String>,
|
|
||||||
pub model_provider: Option<String>,
|
|
||||||
pub approval_policy: Option<AskForApproval>,
|
|
||||||
pub model_reasoning_effort: Option<ReasoningEffort>,
|
|
||||||
pub model_reasoning_summary: Option<ReasoningSummary>,
|
|
||||||
pub model_verbosity: Option<Verbosity>,
|
|
||||||
pub chatgpt_base_url: Option<String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, JsonSchema, TS)]
|
#[derive(Deserialize, Debug, Clone, PartialEq, Serialize, JsonSchema, TS)]
|
||||||
|
|||||||
@@ -133,30 +133,6 @@ pub struct ToolsV2 {
|
|||||||
pub web_search: Option<WebSearchToolConfig>,
|
pub web_search: Option<WebSearchToolConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[ts(export_to = "v2/")]
|
|
||||||
pub struct ProfileV2 {
|
|
||||||
pub model: Option<String>,
|
|
||||||
pub model_provider: Option<String>,
|
|
||||||
#[experimental(nested)]
|
|
||||||
pub approval_policy: Option<AskForApproval>,
|
|
||||||
/// [UNSTABLE] Optional profile-level override for where approval requests
|
|
||||||
/// are routed for review. If omitted, the enclosing config default is
|
|
||||||
/// used.
|
|
||||||
#[experimental("config/read.approvalsReviewer")]
|
|
||||||
pub approvals_reviewer: Option<ApprovalsReviewer>,
|
|
||||||
pub service_tier: Option<String>,
|
|
||||||
pub model_reasoning_effort: Option<ReasoningEffort>,
|
|
||||||
pub model_reasoning_summary: Option<ReasoningSummary>,
|
|
||||||
pub model_verbosity: Option<Verbosity>,
|
|
||||||
pub web_search: Option<WebSearchMode>,
|
|
||||||
pub tools: Option<ToolsV2>,
|
|
||||||
pub chatgpt_base_url: Option<String>,
|
|
||||||
#[serde(default, flatten)]
|
|
||||||
pub additional: HashMap<String, JsonValue>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[ts(export_to = "v2/")]
|
#[ts(export_to = "v2/")]
|
||||||
@@ -266,10 +242,6 @@ pub struct Config {
|
|||||||
pub forced_login_method: Option<ForcedLoginMethod>,
|
pub forced_login_method: Option<ForcedLoginMethod>,
|
||||||
pub web_search: Option<WebSearchMode>,
|
pub web_search: Option<WebSearchMode>,
|
||||||
pub tools: Option<ToolsV2>,
|
pub tools: Option<ToolsV2>,
|
||||||
pub profile: Option<String>,
|
|
||||||
#[experimental(nested)]
|
|
||||||
#[serde(default)]
|
|
||||||
pub profiles: HashMap<String, ProfileV2>,
|
|
||||||
pub instructions: Option<String>,
|
pub instructions: Option<String>,
|
||||||
pub developer_instructions: Option<String>,
|
pub developer_instructions: Option<String>,
|
||||||
pub compact_prompt: Option<String>,
|
pub compact_prompt: Option<String>,
|
||||||
|
|||||||
@@ -1505,32 +1505,6 @@ fn ask_for_approval_granular_is_marked_experimental() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn profile_v2_granular_approval_policy_is_marked_experimental() {
|
|
||||||
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&ProfileV2 {
|
|
||||||
model: None,
|
|
||||||
model_provider: None,
|
|
||||||
approval_policy: Some(AskForApproval::Granular {
|
|
||||||
sandbox_approval: true,
|
|
||||||
rules: false,
|
|
||||||
skill_approval: false,
|
|
||||||
request_permissions: true,
|
|
||||||
mcp_elicitations: false,
|
|
||||||
}),
|
|
||||||
approvals_reviewer: None,
|
|
||||||
service_tier: None,
|
|
||||||
model_reasoning_effort: None,
|
|
||||||
model_reasoning_summary: None,
|
|
||||||
model_verbosity: None,
|
|
||||||
web_search: None,
|
|
||||||
tools: None,
|
|
||||||
chatgpt_base_url: None,
|
|
||||||
additional: HashMap::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(reason, Some("askForApproval.granular"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn config_granular_approval_policy_is_marked_experimental() {
|
fn config_granular_approval_policy_is_marked_experimental() {
|
||||||
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&Config {
|
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&Config {
|
||||||
@@ -1554,8 +1528,6 @@ fn config_granular_approval_policy_is_marked_experimental() {
|
|||||||
forced_login_method: None,
|
forced_login_method: None,
|
||||||
web_search: None,
|
web_search: None,
|
||||||
tools: None,
|
tools: None,
|
||||||
profile: None,
|
|
||||||
profiles: HashMap::new(),
|
|
||||||
instructions: None,
|
instructions: None,
|
||||||
developer_instructions: None,
|
developer_instructions: None,
|
||||||
compact_prompt: None,
|
compact_prompt: None,
|
||||||
@@ -1589,116 +1561,6 @@ fn config_approvals_reviewer_is_marked_experimental() {
|
|||||||
forced_login_method: None,
|
forced_login_method: None,
|
||||||
web_search: None,
|
web_search: None,
|
||||||
tools: None,
|
tools: None,
|
||||||
profile: None,
|
|
||||||
profiles: HashMap::new(),
|
|
||||||
instructions: None,
|
|
||||||
developer_instructions: None,
|
|
||||||
compact_prompt: None,
|
|
||||||
model_reasoning_effort: None,
|
|
||||||
model_reasoning_summary: None,
|
|
||||||
model_verbosity: None,
|
|
||||||
service_tier: None,
|
|
||||||
analytics: None,
|
|
||||||
apps: None,
|
|
||||||
desktop: None,
|
|
||||||
additional: HashMap::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(reason, Some("config/read.approvalsReviewer"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn config_nested_profile_granular_approval_policy_is_marked_experimental() {
|
|
||||||
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&Config {
|
|
||||||
model: None,
|
|
||||||
review_model: None,
|
|
||||||
model_context_window: None,
|
|
||||||
model_auto_compact_token_limit: None,
|
|
||||||
model_auto_compact_token_limit_scope: None,
|
|
||||||
model_provider: None,
|
|
||||||
approval_policy: None,
|
|
||||||
approvals_reviewer: None,
|
|
||||||
sandbox_mode: None,
|
|
||||||
sandbox_workspace_write: None,
|
|
||||||
forced_chatgpt_workspace_id: None,
|
|
||||||
forced_login_method: None,
|
|
||||||
web_search: None,
|
|
||||||
tools: None,
|
|
||||||
profile: None,
|
|
||||||
profiles: HashMap::from([(
|
|
||||||
"default".to_string(),
|
|
||||||
ProfileV2 {
|
|
||||||
model: None,
|
|
||||||
model_provider: None,
|
|
||||||
approval_policy: Some(AskForApproval::Granular {
|
|
||||||
sandbox_approval: true,
|
|
||||||
rules: false,
|
|
||||||
skill_approval: false,
|
|
||||||
request_permissions: false,
|
|
||||||
mcp_elicitations: true,
|
|
||||||
}),
|
|
||||||
approvals_reviewer: None,
|
|
||||||
service_tier: None,
|
|
||||||
model_reasoning_effort: None,
|
|
||||||
model_reasoning_summary: None,
|
|
||||||
model_verbosity: None,
|
|
||||||
web_search: None,
|
|
||||||
tools: None,
|
|
||||||
chatgpt_base_url: None,
|
|
||||||
additional: HashMap::new(),
|
|
||||||
},
|
|
||||||
)]),
|
|
||||||
instructions: None,
|
|
||||||
developer_instructions: None,
|
|
||||||
compact_prompt: None,
|
|
||||||
model_reasoning_effort: None,
|
|
||||||
model_reasoning_summary: None,
|
|
||||||
model_verbosity: None,
|
|
||||||
service_tier: None,
|
|
||||||
analytics: None,
|
|
||||||
apps: None,
|
|
||||||
desktop: None,
|
|
||||||
additional: HashMap::new(),
|
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(reason, Some("askForApproval.granular"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn config_nested_profile_approvals_reviewer_is_marked_experimental() {
|
|
||||||
let reason = crate::experimental_api::ExperimentalApi::experimental_reason(&Config {
|
|
||||||
model: None,
|
|
||||||
review_model: None,
|
|
||||||
model_context_window: None,
|
|
||||||
model_auto_compact_token_limit: None,
|
|
||||||
model_auto_compact_token_limit_scope: None,
|
|
||||||
model_provider: None,
|
|
||||||
approval_policy: None,
|
|
||||||
approvals_reviewer: None,
|
|
||||||
sandbox_mode: None,
|
|
||||||
sandbox_workspace_write: None,
|
|
||||||
forced_chatgpt_workspace_id: None,
|
|
||||||
forced_login_method: None,
|
|
||||||
web_search: None,
|
|
||||||
tools: None,
|
|
||||||
profile: None,
|
|
||||||
profiles: HashMap::from([(
|
|
||||||
"default".to_string(),
|
|
||||||
ProfileV2 {
|
|
||||||
model: None,
|
|
||||||
model_provider: None,
|
|
||||||
approval_policy: None,
|
|
||||||
approvals_reviewer: Some(ApprovalsReviewer::AutoReview),
|
|
||||||
service_tier: None,
|
|
||||||
model_reasoning_effort: None,
|
|
||||||
model_reasoning_summary: None,
|
|
||||||
model_verbosity: None,
|
|
||||||
web_search: None,
|
|
||||||
tools: None,
|
|
||||||
chatgpt_base_url: None,
|
|
||||||
additional: HashMap::new(),
|
|
||||||
},
|
|
||||||
)]),
|
|
||||||
instructions: None,
|
instructions: None,
|
||||||
developer_instructions: None,
|
developer_instructions: None,
|
||||||
compact_prompt: None,
|
compact_prompt: None,
|
||||||
|
|||||||
@@ -1931,7 +1931,7 @@ reason up through the containing type:
|
|||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[derive(ExperimentalApi)]
|
#[derive(ExperimentalApi)]
|
||||||
struct ProfileV2 {
|
struct Config {
|
||||||
#[experimental(nested)]
|
#[experimental(nested)]
|
||||||
approval_policy: Option<AskForApproval>,
|
approval_policy: Option<AskForApproval>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ impl ConfigManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let effective = layers.effective_config();
|
let effective = layers.effective_config();
|
||||||
|
|
||||||
let effective_config_toml: ConfigToml = effective
|
let effective_config_toml: ConfigToml = effective
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(|err| ConfigManagerError::toml("invalid configuration", err))?;
|
.map_err(|err| ConfigManagerError::toml("invalid configuration", err))?;
|
||||||
@@ -238,12 +237,22 @@ impl ConfigManager {
|
|||||||
let segments = parse_key_path(&key_path).map_err(|message| {
|
let segments = parse_key_path(&key_path).map_err(|message| {
|
||||||
ConfigManagerError::write(ConfigWriteErrorCode::ConfigValidationError, message)
|
ConfigManagerError::write(ConfigWriteErrorCode::ConfigValidationError, message)
|
||||||
})?;
|
})?;
|
||||||
if matches!(segments.as_slice(), [segment] if segment == "profile") && !value.is_null()
|
if !value.is_null() {
|
||||||
{
|
match segments.as_slice() {
|
||||||
return Err(ConfigManagerError::write(
|
[segment] if segment == "profile" => {
|
||||||
ConfigWriteErrorCode::ConfigValidationError,
|
return Err(ConfigManagerError::write(
|
||||||
"`profile` is a legacy config selector and can no longer be written; use `--profile <name>` with `<name>.config.toml` instead",
|
ConfigWriteErrorCode::ConfigValidationError,
|
||||||
));
|
"`profile` is a legacy config selector and can no longer be written; use `--profile <name>` with `<name>.config.toml` instead",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
[segment, ..] if segment == "profiles" => {
|
||||||
|
return Err(ConfigManagerError::write(
|
||||||
|
ConfigWriteErrorCode::ConfigValidationError,
|
||||||
|
"`profiles` contains legacy config profile tables and can no longer be written; use `--profile <name>` with `<name>.config.toml` instead",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let original_value = value_at_path(&user_config, &segments).cloned();
|
let original_value = value_at_path(&user_config, &segments).cloned();
|
||||||
let parsed_value = parse_value(value).map_err(|message| {
|
let parsed_value = parse_value(value).map_err(|message| {
|
||||||
|
|||||||
@@ -162,6 +162,38 @@ async fn write_value_rejects_legacy_profile_selector() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn write_value_rejects_legacy_profile_table() -> Result<()> {
|
||||||
|
let tmp = tempdir().expect("tempdir");
|
||||||
|
let path = tmp.path().join(CONFIG_TOML_FILE);
|
||||||
|
std::fs::write(&path, "")?;
|
||||||
|
|
||||||
|
let service = ConfigManager::without_managed_config_for_tests(tmp.path().to_path_buf());
|
||||||
|
let error = service
|
||||||
|
.write_value(ConfigValueWriteParams {
|
||||||
|
file_path: Some(path.display().to_string()),
|
||||||
|
key_path: "profiles.work.model".to_string(),
|
||||||
|
value: serde_json::json!("gpt-work"),
|
||||||
|
merge_strategy: MergeStrategy::Replace,
|
||||||
|
expected_version: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect_err("legacy profile table write should fail");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
error.write_error_code(),
|
||||||
|
Some(ConfigWriteErrorCode::ConfigValidationError)
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
error
|
||||||
|
.to_string()
|
||||||
|
.contains("`profiles` contains legacy config profile tables"),
|
||||||
|
"{error}"
|
||||||
|
);
|
||||||
|
assert_eq!(std::fs::read_to_string(&path)?, "");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn batch_write_rejects_legacy_profile_selector() -> Result<()> {
|
async fn batch_write_rejects_legacy_profile_selector() -> Result<()> {
|
||||||
let tmp = tempdir().expect("tempdir");
|
let tmp = tempdir().expect("tempdir");
|
||||||
@@ -712,52 +744,6 @@ async fn write_value_rejects_feature_requirement_conflict() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn write_value_rejects_profile_feature_requirement_conflict() {
|
|
||||||
let tmp = tempdir().expect("tempdir");
|
|
||||||
std::fs::write(tmp.path().join(CONFIG_TOML_FILE), "").unwrap();
|
|
||||||
|
|
||||||
let service = ConfigManager::new_for_tests(
|
|
||||||
tmp.path().to_path_buf(),
|
|
||||||
vec![],
|
|
||||||
LoaderOverrides::without_managed_config_for_tests(),
|
|
||||||
CloudRequirementsLoader::new(async {
|
|
||||||
Ok(Some(ConfigRequirementsToml {
|
|
||||||
feature_requirements: Some(FeatureRequirementsToml {
|
|
||||||
entries: BTreeMap::from([("personality".to_string(), true)]),
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
}))
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
let error = service
|
|
||||||
.write_value(ConfigValueWriteParams {
|
|
||||||
file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()),
|
|
||||||
key_path: "profiles.enterprise.features.personality".to_string(),
|
|
||||||
value: serde_json::json!(false),
|
|
||||||
merge_strategy: MergeStrategy::Replace,
|
|
||||||
expected_version: None,
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.expect_err("conflicting profile feature write should fail");
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
error.write_error_code(),
|
|
||||||
Some(ConfigWriteErrorCode::ConfigValidationError)
|
|
||||||
);
|
|
||||||
assert!(
|
|
||||||
error.to_string().contains(
|
|
||||||
"invalid value for `features`: `profiles.enterprise.features.personality=false`"
|
|
||||||
),
|
|
||||||
"{error}"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
std::fs::read_to_string(tmp.path().join(CONFIG_TOML_FILE)).unwrap(),
|
|
||||||
""
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn read_reports_managed_overrides_user_and_session_flags() {
|
async fn read_reports_managed_overrides_user_and_session_flags() {
|
||||||
let tmp = tempdir().expect("tempdir");
|
let tmp = tempdir().expect("tempdir");
|
||||||
|
|||||||
@@ -894,19 +894,14 @@ async fn config_batch_write_applies_multiple_edits() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn config_batch_write_preserves_dotted_profile_names() -> Result<()> {
|
async fn config_batch_write_rejects_legacy_profile_tables() -> Result<()> {
|
||||||
let tmp_dir = TempDir::new()?;
|
let tmp_dir = TempDir::new()?;
|
||||||
let codex_home = tmp_dir.path().canonicalize()?;
|
let codex_home = tmp_dir.path().canonicalize()?;
|
||||||
write_config(
|
write_config(
|
||||||
&tmp_dir,
|
&tmp_dir,
|
||||||
r#"
|
r#"
|
||||||
profile = "team.prod"
|
|
||||||
|
|
||||||
[profiles."team.prod"]
|
[profiles."team.prod"]
|
||||||
model = "gpt-5.3-spark"
|
model = "gpt-5.3-spark"
|
||||||
|
|
||||||
[profiles.team.prod]
|
|
||||||
model = "should-stay-put"
|
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -932,28 +927,30 @@ model = "should-stay-put"
|
|||||||
reload_user_config: false,
|
reload_user_config: false,
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
let batch_resp: JSONRPCResponse = timeout(
|
let err: JSONRPCError = timeout(
|
||||||
DEFAULT_READ_TIMEOUT,
|
DEFAULT_READ_TIMEOUT,
|
||||||
mcp.read_stream_until_response_message(RequestId::Integer(batch_id)),
|
mcp.read_stream_until_error_message(RequestId::Integer(batch_id)),
|
||||||
)
|
)
|
||||||
.await??;
|
.await??;
|
||||||
let batch_write: ConfigWriteResponse = to_response(batch_resp)?;
|
let code = err
|
||||||
assert_eq!(batch_write.status, WriteStatus::Ok);
|
.error
|
||||||
|
.data
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|data| data.get("config_write_error_code"))
|
||||||
|
.and_then(|value| value.as_str());
|
||||||
|
assert_eq!(code, Some("configValidationError"));
|
||||||
|
assert!(
|
||||||
|
err.error.message.contains("`profiles`"),
|
||||||
|
"unexpected error: {err:?}"
|
||||||
|
);
|
||||||
|
|
||||||
let config: toml::Value =
|
let config: toml::Value =
|
||||||
toml::from_str(&std::fs::read_to_string(codex_home.join("config.toml"))?)?;
|
toml::from_str(&std::fs::read_to_string(codex_home.join("config.toml"))?)?;
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
config["profiles"]["team.prod"]["model"].as_str(),
|
config["profiles"]["team.prod"]["model"].as_str(),
|
||||||
Some("gpt-5.5")
|
Some("gpt-5.3-spark")
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
config["profiles"]["team"]["prod"]["model"].as_str(),
|
|
||||||
Some("should-stay-put")
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
config["items"]["sample@catalog"]["enabled"].as_bool(),
|
|
||||||
Some(true)
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(config.get("items"), None);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,6 @@ use crate::types::ToolSuggestConfig;
|
|||||||
use crate::types::Tui;
|
use crate::types::Tui;
|
||||||
use crate::types::UriBasedFileOpener;
|
use crate::types::UriBasedFileOpener;
|
||||||
use crate::types::WindowsToml;
|
use crate::types::WindowsToml;
|
||||||
use codex_app_server_protocol::ForcedChatgptWorkspaceIds as ApiForcedChatgptWorkspaceIds;
|
|
||||||
use codex_app_server_protocol::Tools;
|
|
||||||
use codex_app_server_protocol::UserSavedConfig;
|
|
||||||
use codex_features::FeaturesToml;
|
use codex_features::FeaturesToml;
|
||||||
use codex_model_provider_info::AMAZON_BEDROCK_PROVIDER_ID;
|
use codex_model_provider_info::AMAZON_BEDROCK_PROVIDER_ID;
|
||||||
use codex_model_provider_info::LEGACY_OLLAMA_CHAT_PROVIDER_ID;
|
use codex_model_provider_info::LEGACY_OLLAMA_CHAT_PROVIDER_ID;
|
||||||
@@ -105,13 +102,6 @@ impl ForcedChatgptWorkspaceIds {
|
|||||||
Self::Multiple(values) => values,
|
Self::Multiple(values) => values,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_api(self) -> ApiForcedChatgptWorkspaceIds {
|
|
||||||
match self {
|
|
||||||
Self::Single(value) => ApiForcedChatgptWorkspaceIds::Single(value),
|
|
||||||
Self::Multiple(values) => ApiForcedChatgptWorkspaceIds::Multiple(values),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> Deserialize<'de> for ForcedChatgptWorkspaceIds {
|
impl<'de> Deserialize<'de> for ForcedChatgptWorkspaceIds {
|
||||||
@@ -553,33 +543,6 @@ pub struct AutoReviewToml {
|
|||||||
pub policy: Option<String>,
|
pub policy: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConfigToml> for UserSavedConfig {
|
|
||||||
fn from(config_toml: ConfigToml) -> Self {
|
|
||||||
let profiles = config_toml
|
|
||||||
.profiles
|
|
||||||
.into_iter()
|
|
||||||
.map(|(k, v)| (k, v.into()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Self {
|
|
||||||
approval_policy: config_toml.approval_policy,
|
|
||||||
sandbox_mode: config_toml.sandbox_mode,
|
|
||||||
sandbox_settings: config_toml.sandbox_workspace_write.map(From::from),
|
|
||||||
forced_chatgpt_workspace_id: config_toml
|
|
||||||
.forced_chatgpt_workspace_id
|
|
||||||
.map(ForcedChatgptWorkspaceIds::into_api),
|
|
||||||
forced_login_method: config_toml.forced_login_method,
|
|
||||||
model: config_toml.model,
|
|
||||||
model_reasoning_effort: config_toml.model_reasoning_effort,
|
|
||||||
model_reasoning_summary: config_toml.model_reasoning_summary,
|
|
||||||
model_verbosity: config_toml.model_verbosity,
|
|
||||||
tools: config_toml.tools.map(From::from),
|
|
||||||
profile: config_toml.profile,
|
|
||||||
profiles,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema)]
|
||||||
#[schemars(deny_unknown_fields)]
|
#[schemars(deny_unknown_fields)]
|
||||||
pub struct ProjectConfig {
|
pub struct ProjectConfig {
|
||||||
@@ -730,14 +693,6 @@ pub struct AgentRoleToml {
|
|||||||
pub nickname_candidates: Option<Vec<String>>,
|
pub nickname_candidates: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ToolsToml> for Tools {
|
|
||||||
fn from(tools_toml: ToolsToml) -> Self {
|
|
||||||
Self {
|
|
||||||
web_search: tools_toml.web_search.is_some().then_some(true),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq, Eq, JsonSchema)]
|
||||||
#[schemars(deny_unknown_fields)]
|
#[schemars(deny_unknown_fields)]
|
||||||
pub struct GhostSnapshotToml {
|
pub struct GhostSnapshotToml {
|
||||||
|
|||||||
@@ -81,17 +81,3 @@ pub struct ProfileTui {
|
|||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub session_picker_view: Option<SessionPickerViewMode>,
|
pub session_picker_view: Option<SessionPickerViewMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ConfigProfile> for codex_app_server_protocol::Profile {
|
|
||||||
fn from(config_profile: ConfigProfile) -> Self {
|
|
||||||
Self {
|
|
||||||
model: config_profile.model,
|
|
||||||
model_provider: config_profile.model_provider,
|
|
||||||
approval_policy: config_profile.approval_policy,
|
|
||||||
model_reasoning_effort: config_profile.model_reasoning_effort,
|
|
||||||
model_reasoning_summary: config_profile.model_reasoning_summary,
|
|
||||||
model_verbosity: config_profile.model_verbosity,
|
|
||||||
chatgpt_base_url: config_profile.chatgpt_base_url,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user