mirror of
https://github.com/openai/codex.git
synced 2026-10-20 00:18:49 +00:00
Retire the personality feature flag and document deprecated settings (#45809)
## What changed - Accept and ignore `features.personality` in user configuration, profiles, and managed requirements. - Remove feature gating from `personality = "none"`, which strips the literal `# Personality` section when preparing model catalog instructions. Preserve explicit base instructions and existing thread instructions. - Document deprecated personality fields in configuration, app-server schemas, and the Python SDK: `friendly` and `pragmatic` no longer select a style, and `supportsPersonality` is always `false`. ## Testing Add regression coverage for ignored legacy flag values and managed requirements, personality opt-out behavior with the flag absent or set to either value, role overrides, and preservation of explicit base instructions, including empty strings. GitOrigin-RevId: 4e12c66b42bfc59d6f151a5b3c28fadc6654ae99
This commit is contained in:
+7
-4
@@ -535,7 +535,7 @@
|
||||
]
|
||||
},
|
||||
"reloadUserConfig": {
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and personality defaults are not reloaded.",
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, and service-tier defaults are not reloaded. The deprecated personality setting is also not reloaded.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
@@ -2335,6 +2335,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -4941,7 +4942,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
@@ -5267,7 +5269,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
@@ -5541,7 +5544,7 @@
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the personality for this turn and subsequent turns."
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"anyOf": [
|
||||
|
||||
@@ -3250,6 +3250,7 @@
|
||||
]
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -5983,7 +5984,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated Reports the saved setting; `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"$ref": "#/definitions/SandboxPolicy"
|
||||
|
||||
+10
-5
@@ -9463,7 +9463,7 @@
|
||||
]
|
||||
},
|
||||
"reloadUserConfig": {
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and personality defaults are not reloaded.",
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, and service-tier defaults are not reloaded. The deprecated personality setting is also not reloaded.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
@@ -15256,6 +15256,7 @@
|
||||
},
|
||||
"supportsPersonality": {
|
||||
"default": false,
|
||||
"description": "@deprecated Always false; models no longer support personality selection.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"upgrade": {
|
||||
@@ -15969,6 +15970,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -23389,7 +23391,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
@@ -23925,7 +23928,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated Reports the saved setting; `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"$ref": "#/definitions/v2/SandboxPolicy"
|
||||
@@ -24108,7 +24112,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
@@ -25258,7 +25263,7 @@
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the personality for this turn and subsequent turns."
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"anyOf": [
|
||||
|
||||
+10
-5
@@ -5343,7 +5343,7 @@
|
||||
]
|
||||
},
|
||||
"reloadUserConfig": {
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and personality defaults are not reloaded.",
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, and service-tier defaults are not reloaded. The deprecated personality setting is also not reloaded.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
@@ -11308,6 +11308,7 @@
|
||||
},
|
||||
"supportsPersonality": {
|
||||
"default": false,
|
||||
"description": "@deprecated Always false; models no longer support personality selection.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"upgrade": {
|
||||
@@ -12021,6 +12022,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -21103,7 +21105,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
@@ -21639,7 +21642,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated Reports the saved setting; `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"$ref": "#/definitions/SandboxPolicy"
|
||||
@@ -21822,7 +21826,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
@@ -22972,7 +22977,7 @@
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the personality for this turn and subsequent turns."
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"anyOf": [
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
]
|
||||
},
|
||||
"reloadUserConfig": {
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and personality defaults are not reloaded.",
|
||||
"description": "When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, and service-tier defaults are not reloaded. The deprecated personality setting is also not reloaded.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -140,6 +140,7 @@
|
||||
},
|
||||
"supportsPersonality": {
|
||||
"default": false,
|
||||
"description": "@deprecated Always false; models no longer support personality selection.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"upgrade": {
|
||||
|
||||
@@ -470,6 +470,7 @@
|
||||
]
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -1545,7 +1546,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
|
||||
+3
-1
@@ -140,6 +140,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -355,7 +356,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated Reports the saved setting; `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"$ref": "#/definitions/SandboxPolicy"
|
||||
|
||||
@@ -220,6 +220,7 @@
|
||||
]
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -373,7 +374,8 @@
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
]
|
||||
],
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"sandbox": {
|
||||
"anyOf": [
|
||||
|
||||
@@ -312,6 +312,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -827,7 +828,7 @@
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"description": "Override the personality for this turn and subsequent turns."
|
||||
"description": "@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
},
|
||||
"sandboxPolicy": {
|
||||
"anyOf": [
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -2,4 +2,7 @@
|
||||
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
/**
|
||||
* Deprecated: `friendly` and `pragmatic` no longer select a style.
|
||||
*/
|
||||
export type Personality = "none" | "friendly" | "pragmatic";
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ export type ConfigBatchWriteParams = { edits: Array<ConfigEdit>,
|
||||
filePath?: string | null, expectedVersion?: string | null,
|
||||
/**
|
||||
* When true, hot-reload updated runtime settings into loaded threads after writing.
|
||||
* Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and
|
||||
* personality defaults are not reloaded.
|
||||
* Session-static model, reasoning-effort, Plan-mode reasoning-effort, and service-tier
|
||||
* defaults are not reloaded. The deprecated personality setting is also not reloaded.
|
||||
*/
|
||||
reloadUserConfig?: boolean, };
|
||||
|
||||
+5
-1
@@ -10,7 +10,11 @@ import type { ModelUpgradeInfo } from "./ModelUpgradeInfo";
|
||||
import type { MultiAgentVersion } from "./MultiAgentVersion";
|
||||
import type { ReasoningEffortOption } from "./ReasoningEffortOption";
|
||||
|
||||
export type Model = { id: string, model: string, upgrade: string | null, upgradeInfo: ModelUpgradeInfo | null, availabilityNux: ModelAvailabilityNux | null, displayName: string, description: string, modelSpecialty: string | null, hidden: boolean, supportedReasoningEfforts: Array<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, inputModalities: Array<InputModality>, supportsPersonality: boolean,
|
||||
export type Model = { id: string, model: string, upgrade: string | null, upgradeInfo: ModelUpgradeInfo | null, availabilityNux: ModelAvailabilityNux | null, displayName: string, description: string, modelSpecialty: string | null, hidden: boolean, supportedReasoningEfforts: Array<ReasoningEffortOption>, defaultReasoningEffort: ReasoningEffort, inputModalities: Array<InputModality>,
|
||||
/**
|
||||
* @deprecated Always false; models no longer support personality selection.
|
||||
*/
|
||||
supportsPersonality: boolean,
|
||||
/**
|
||||
* Multi-agent runtime declared by this model, when available.
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,11 @@ model?: string | null, modelProvider?: string | null, serviceTier?: string | nul
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, /**
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, baseInstructions?: string | null, developerInstructions?: string | null, /**
|
||||
* @deprecated `friendly` and `pragmatic` no longer select a style.
|
||||
* Changing this does not rewrite the thread's existing instructions.
|
||||
*/
|
||||
personality?: Personality | null, /**
|
||||
* When true, return only thread metadata and live-resume state without
|
||||
* populating `thread.turns`. This is useful when the client plans to call
|
||||
* `thread/turns/list` immediately after resuming. Full-history hydration
|
||||
|
||||
@@ -14,4 +14,7 @@ import type { SandboxPolicy } from "./SandboxPolicy";
|
||||
export type ThreadSettings = {/**
|
||||
* Saved list of disabled plugin IDs. Does not yet filter plugin capabilities.
|
||||
*/
|
||||
disabledPluginIds: Array<string>, cwd: AbsolutePathBuf, approvalPolicy: AskForApproval, approvalsReviewer: ApprovalsReviewer, sandboxPolicy: SandboxPolicy, activePermissionProfile: ActivePermissionProfile | null, model: string, modelProvider: string, serviceTier: string | null, effort: ReasoningEffort | null, summary: ReasoningSummary | null, collaborationMode: CollaborationMode, personality: Personality | null};
|
||||
disabledPluginIds: Array<string>, cwd: AbsolutePathBuf, approvalPolicy: AskForApproval, approvalsReviewer: ApprovalsReviewer, sandboxPolicy: SandboxPolicy, activePermissionProfile: ActivePermissionProfile | null, model: string, modelProvider: string, serviceTier: string | null, effort: ReasoningEffort | null, summary: ReasoningSummary | null, collaborationMode: CollaborationMode, /**
|
||||
* @deprecated Reports the saved setting; `friendly` and `pragmatic` no longer select a style.
|
||||
*/
|
||||
personality: Personality | null};
|
||||
|
||||
@@ -13,7 +13,10 @@ export type ThreadStartParams = {model?: string | null, modelProvider?: string |
|
||||
* Override where approval requests are routed for review on this thread
|
||||
* and subsequent turns.
|
||||
*/
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, personality?: Personality | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null, /**
|
||||
approvalsReviewer?: ApprovalsReviewer | null, sandbox?: SandboxMode | null, config?: { [key in string]?: JsonValue } | null, serviceName?: string | null, baseInstructions?: string | null, developerInstructions?: string | null, /**
|
||||
* @deprecated `friendly` and `pragmatic` no longer select a style.
|
||||
*/
|
||||
personality?: Personality | null, ephemeral?: boolean | null, sessionStartSource?: ThreadStartSource | null, /**
|
||||
* Optional client-supplied analytics source classification for this thread.
|
||||
*/
|
||||
threadSource?: ThreadSource | null};
|
||||
|
||||
@@ -50,7 +50,8 @@ effort?: ReasoningEffort | null, /**
|
||||
* Override the reasoning summary for this turn and subsequent turns.
|
||||
*/
|
||||
summary?: ReasoningSummary | null, /**
|
||||
* Override the personality for this turn and subsequent turns.
|
||||
* @deprecated `friendly` and `pragmatic` no longer select a style.
|
||||
* Changing this does not rewrite the thread's existing instructions.
|
||||
*/
|
||||
personality?: Personality | null, /**
|
||||
* Optional JSON Schema used to constrain the final assistant message for
|
||||
|
||||
@@ -1089,8 +1089,8 @@ pub struct ConfigBatchWriteParams {
|
||||
#[ts(optional = nullable)]
|
||||
pub expected_version: Option<String>,
|
||||
/// When true, hot-reload updated runtime settings into loaded threads after writing.
|
||||
/// Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and
|
||||
/// personality defaults are not reloaded.
|
||||
/// Session-static model, reasoning-effort, Plan-mode reasoning-effort, and service-tier
|
||||
/// defaults are not reloaded. The deprecated personality setting is also not reloaded.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub reload_user_config: bool,
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ pub struct Model {
|
||||
pub default_reasoning_effort: ReasoningEffort,
|
||||
#[serde(default = "default_input_modalities")]
|
||||
pub input_modalities: Vec<InputModality>,
|
||||
/// @deprecated Always false; models no longer support personality selection.
|
||||
#[serde(default)]
|
||||
pub supports_personality: bool,
|
||||
/// Multi-agent runtime declared by this model, when available.
|
||||
|
||||
@@ -104,6 +104,7 @@ pub struct ThreadStartParams {
|
||||
pub base_instructions: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub developer_instructions: Option<String>,
|
||||
/// @deprecated `friendly` and `pragmatic` no longer select a style.
|
||||
#[ts(optional = nullable)]
|
||||
pub personality: Option<Personality>,
|
||||
/// @deprecated Ignored. Use Ultra reasoning effort for proactive multi-agent behavior.
|
||||
@@ -286,7 +287,8 @@ pub struct ThreadSettingsUpdateParams {
|
||||
#[experimental("thread/settings/update.multiAgentMode")]
|
||||
#[ts(optional = nullable)]
|
||||
pub multi_agent_mode: Option<MultiAgentMode>,
|
||||
/// Override the personality for subsequent turns.
|
||||
/// @deprecated `friendly` and `pragmatic` no longer select a style.
|
||||
/// Changing this does not rewrite the thread's existing instructions.
|
||||
#[ts(optional = nullable)]
|
||||
pub personality: Option<Personality>,
|
||||
}
|
||||
@@ -318,6 +320,7 @@ pub struct ThreadSettings {
|
||||
#[experimental("thread/settings.multiAgentMode")]
|
||||
#[serde(default)]
|
||||
pub multi_agent_mode: MultiAgentMode,
|
||||
/// @deprecated Reports the saved setting; `friendly` and `pragmatic` no longer select a style.
|
||||
pub personality: Option<Personality>,
|
||||
}
|
||||
|
||||
@@ -409,6 +412,8 @@ pub struct ThreadResumeParams {
|
||||
pub base_instructions: Option<String>,
|
||||
#[ts(optional = nullable)]
|
||||
pub developer_instructions: Option<String>,
|
||||
/// @deprecated `friendly` and `pragmatic` no longer select a style.
|
||||
/// Changing this does not rewrite the thread's existing instructions.
|
||||
#[ts(optional = nullable)]
|
||||
pub personality: Option<Personality>,
|
||||
/// When true, return only thread metadata and live-resume state without
|
||||
|
||||
@@ -248,7 +248,8 @@ pub struct TurnStartParams {
|
||||
/// Override the reasoning summary for this turn and subsequent turns.
|
||||
#[ts(optional = nullable)]
|
||||
pub summary: Option<ReasoningSummary>,
|
||||
/// Override the personality for this turn and subsequent turns.
|
||||
/// @deprecated `friendly` and `pragmatic` no longer select a style.
|
||||
/// Changing this does not rewrite the thread's existing instructions.
|
||||
#[ts(optional = nullable)]
|
||||
pub personality: Option<Personality>,
|
||||
/// Optional JSON Schema used to constrain the final assistant message for
|
||||
|
||||
@@ -231,6 +231,19 @@ Read the selection from `threadSettings.disabledPluginIds` in
|
||||
across resume. Forks restore the selection from the history retained at the
|
||||
requested fork boundary.
|
||||
|
||||
# Deprecated thread personality setting
|
||||
|
||||
`thread/start`, `thread/resume`, `thread/settings/update`, and `turn/start` still
|
||||
accept `personality`, but `friendly` and `pragmatic` no longer select a style.
|
||||
`model/list` returns `supportsPersonality: false` for every model.
|
||||
|
||||
`none` removes the literal `# Personality` section when Codex prepares
|
||||
instructions from the model catalog, for example when starting a thread or
|
||||
switching models. Setting `friendly` or `pragmatic` can replace a previous
|
||||
`none` setting for that purpose. Changing the setting does not rewrite the
|
||||
thread's existing instructions or change explicitly supplied base instructions.
|
||||
The old `features.personality` flag is ignored.
|
||||
|
||||
# MCP server capabilities
|
||||
|
||||
`mcpServerStatus/list` returns `serverCapabilities` for each initialized MCP server
|
||||
|
||||
@@ -1535,7 +1535,7 @@ async fn write_value_rejects_feature_requirement_conflict() {
|
||||
CloudConfigBundleFixture::loader_with_enterprise_requirement(
|
||||
r#"
|
||||
[features]
|
||||
personality = true
|
||||
fast_mode = true
|
||||
"#,
|
||||
),
|
||||
);
|
||||
@@ -1543,7 +1543,7 @@ personality = true
|
||||
let error = service
|
||||
.write_value(ConfigValueWriteParams {
|
||||
file_path: Some(tmp.path().join(CONFIG_TOML_FILE).display().to_string()),
|
||||
key_path: "features.personality".to_string(),
|
||||
key_path: "features.fast_mode".to_string(),
|
||||
value: serde_json::json!(false),
|
||||
merge_strategy: MergeStrategy::Replace,
|
||||
expected_version: None,
|
||||
@@ -1558,7 +1558,7 @@ personality = true
|
||||
assert!(
|
||||
error
|
||||
.to_string()
|
||||
.contains("invalid value for `features`: `features.personality=false`"),
|
||||
.contains("invalid value for `features`: `features.fast_mode=false`"),
|
||||
"{error}"
|
||||
);
|
||||
assert_eq!(
|
||||
|
||||
@@ -11,7 +11,7 @@ fn mock_responses_config_composes_model_provider_features_and_extra_tables() {
|
||||
.with_provider_base_url("http://127.0.0.1:1234/api/codex")
|
||||
.with_approval_policy("on-request")
|
||||
.with_sandbox_mode("workspace-write")
|
||||
.enable_feature(Feature::Personality)
|
||||
.enable_feature(Feature::FastMode)
|
||||
.disable_feature(Feature::ShellSnapshot)
|
||||
.with_root_config("chatgpt_base_url = \"http://127.0.0.1:1234\"")
|
||||
.with_provider_config("requires_openai_auth = true")
|
||||
@@ -28,7 +28,7 @@ fn mock_responses_config_composes_model_provider_features_and_extra_tables() {
|
||||
"chatgpt_base_url = \"http://127.0.0.1:1234\"",
|
||||
"model_provider = \"openai-custom\"",
|
||||
"shell_snapshot = false",
|
||||
"personality = true",
|
||||
"fast_mode = true",
|
||||
"[model_providers.openai-custom]\nname = \"OpenAI\"",
|
||||
"base_url = \"http://127.0.0.1:1234/api/codex\"",
|
||||
"requires_openai_auth = true",
|
||||
@@ -44,10 +44,7 @@ fn legacy_mock_responses_writer_preserves_provider_auth_and_feature_overrides()
|
||||
write_mock_responses_config_toml(
|
||||
home.path(),
|
||||
"http://127.0.0.1:1234",
|
||||
&BTreeMap::from([
|
||||
(Feature::Personality, true),
|
||||
(Feature::ShellSnapshot, false),
|
||||
]),
|
||||
&BTreeMap::from([(Feature::FastMode, true), (Feature::ShellSnapshot, false)]),
|
||||
/*auto_compact_limit*/ 321,
|
||||
Some(true),
|
||||
"openai",
|
||||
@@ -62,7 +59,7 @@ fn legacy_mock_responses_writer_preserves_provider_auth_and_feature_overrides()
|
||||
"model_auto_compact_token_limit = 321",
|
||||
"openai_base_url = \"http://127.0.0.1:1234/v1\"",
|
||||
"shell_snapshot = false",
|
||||
"personality = true",
|
||||
"fast_mode = true",
|
||||
"[model_providers.openai]\nname = \"OpenAI\"",
|
||||
"supports_websockets = false",
|
||||
"requires_openai_auth = true",
|
||||
|
||||
@@ -487,6 +487,5 @@ fn create_config_toml(codex_home: &std::path::Path, server_uri: &str) -> std::io
|
||||
MockResponsesConfig::new(server_uri)
|
||||
.with_model(REQUESTED_MODEL)
|
||||
.disable_feature(Feature::RemoteModels)
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home)
|
||||
}
|
||||
|
||||
@@ -1178,13 +1178,9 @@ stream_max_retries = 0
|
||||
async fn thread_resume_preserves_goal_first_and_fork_approvals_reviewer() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri()).write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.write(codex_home.path())?;
|
||||
|
||||
let (thread_id, fork_thread_id) = {
|
||||
let mut mcp = TestAppServer::builder()
|
||||
@@ -1271,6 +1267,7 @@ async fn thread_resume_preserves_goal_first_and_fork_approvals_reviewer() -> Res
|
||||
(thread.id, fork_thread.id)
|
||||
};
|
||||
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
config_path,
|
||||
@@ -1943,13 +1940,9 @@ fn write_dev_permission_config(
|
||||
async fn thread_goal_get_rejects_unmaterialized_thread() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri()).write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -2244,13 +2237,9 @@ async fn goal_first_live_thread_appears_in_state_db_thread_list() -> Result<()>
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
let codex_home = TempDir::new()?;
|
||||
let codex_home_path = normalized_existing_path(codex_home.path())?;
|
||||
mock_responses_config(&server.uri()).write(&codex_home_path)?;
|
||||
let config_path = codex_home_path.join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.write(&codex_home_path)?;
|
||||
|
||||
let sqlite_home = codex_home_path
|
||||
.as_path()
|
||||
@@ -3000,13 +2989,9 @@ async fn thread_resume_keeps_tool_paused_goal_paused() -> Result<()> {
|
||||
])
|
||||
.await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri()).write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -3088,14 +3073,10 @@ async fn thread_resume_keeps_tool_paused_goal_paused() -> Result<()> {
|
||||
async fn thread_goal_set_enforces_configured_maximum_token_budget() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri()).write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
let config = config.replace("personality = true\n", "personality = true\ngoals = true\n");
|
||||
std::fs::write(
|
||||
config_path,
|
||||
format!("{config}\n[goals]\nmax_goal_token_budget = 200\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.with_extra_config("[goals]\nmax_goal_token_budget = 200")
|
||||
.write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -3185,13 +3166,9 @@ async fn thread_goal_set_enforces_configured_maximum_token_budget() -> Result<()
|
||||
async fn thread_goal_set_preserves_budget_limited_same_objective() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri()).write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -3275,13 +3252,9 @@ async fn thread_goal_set_preserves_budget_limited_same_objective() -> Result<()>
|
||||
async fn thread_goal_set_persists_resumable_stopped_statuses() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri()).write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -3357,13 +3330,9 @@ async fn thread_goal_set_persists_resumable_stopped_statuses() -> Result<()> {
|
||||
async fn thread_goal_set_edits_objective_without_resetting_usage() -> Result<()> {
|
||||
let server = create_mock_responses_server_repeating_assistant("Done").await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri()).write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.write(codex_home.path())?;
|
||||
let thread_id = create_fake_rollout(
|
||||
codex_home.path(),
|
||||
"2025-01-05T12-00-00",
|
||||
@@ -3686,14 +3655,9 @@ async fn thread_goal_lifecycle_emits_analytics_and_clear_deletes_goal() -> Resul
|
||||
.await;
|
||||
let codex_home = TempDir::new()?;
|
||||
mock_responses_config(&server.uri())
|
||||
.enable_feature(Feature::Goals)
|
||||
.with_root_config(&format!(r#"chatgpt_base_url = "{}""#, server.uri()))
|
||||
.write(codex_home.path())?;
|
||||
let config_path = codex_home.path().join("config.toml");
|
||||
let config = std::fs::read_to_string(&config_path)?;
|
||||
std::fs::write(
|
||||
&config_path,
|
||||
config.replace("personality = true\n", "personality = true\ngoals = true\n"),
|
||||
)?;
|
||||
mount_analytics_capture(&server, codex_home.path()).await?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
@@ -6263,9 +6227,7 @@ async fn thread_resume_accepts_deprecated_personality_override() -> Result<()> {
|
||||
}
|
||||
|
||||
fn mock_responses_config(server_uri: &str) -> MockResponsesConfig {
|
||||
MockResponsesConfig::new(server_uri)
|
||||
.with_model("gpt-5.4")
|
||||
.enable_feature(Feature::Personality)
|
||||
MockResponsesConfig::new(server_uri).with_model("gpt-5.4")
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
@@ -842,9 +842,7 @@ async fn turn_start_sends_originator_header() -> Result<()> {
|
||||
let server = create_mock_responses_server_sequence_unchecked(responses).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -911,9 +909,7 @@ async fn turn_start_emits_user_message_item_with_text_elements() -> Result<()> {
|
||||
let server = create_mock_responses_server_sequence_unchecked(responses).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -989,9 +985,7 @@ async fn turn_start_emits_thread_scoped_warning_notification_for_trimmed_skills(
|
||||
let server = create_mock_responses_server_sequence_unchecked(responses).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
write_models_cache(codex_home.path()).await?;
|
||||
let cache_path = codex_home.path().join("models_cache.json");
|
||||
let mut cache: serde_json::Value =
|
||||
@@ -1826,9 +1820,7 @@ async fn turn_start_accepts_text_at_limit_with_mention_item() -> Result<()> {
|
||||
let server = create_mock_responses_server_sequence_unchecked(responses).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -1876,9 +1868,7 @@ async fn turn_start_accepts_text_at_limit_with_mention_item() -> Result<()> {
|
||||
#[tokio::test]
|
||||
async fn turn_start_rejects_combined_oversized_text_input() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new("http://localhost/unused")
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new("http://localhost/unused").write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -1969,9 +1959,7 @@ async fn turn_start_rejects_combined_oversized_text_input() -> Result<()> {
|
||||
#[tokio::test]
|
||||
async fn turn_start_rejects_invalid_permission_selection_before_starting_turn() -> Result<()> {
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new("http://localhost/unused")
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new("http://localhost/unused").write(codex_home.path())?;
|
||||
std::fs::write(
|
||||
codex_home.path().join("managed_config.toml"),
|
||||
"sandbox_mode = \"read-only\"\n",
|
||||
@@ -2403,9 +2391,7 @@ async fn turn_start_emits_notifications_and_accepts_model_override() -> Result<(
|
||||
let server = create_mock_responses_server_sequence_unchecked(responses).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -2679,9 +2665,7 @@ async fn turn_start_accepts_deprecated_personality_override_v2() -> Result<()> {
|
||||
let response_mock = responses::mount_sse_once(&server, body).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -2892,9 +2876,7 @@ async fn turn_start_ignores_personality_change_mid_thread_v2() -> Result<()> {
|
||||
let response_mock = responses::mount_sse_sequence(&server, vec![sse1, sse2]).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
|
||||
let mut mcp = TestAppServer::builder()
|
||||
.with_codex_home(codex_home.path())
|
||||
@@ -5762,9 +5744,7 @@ async fn turn_start_with_elevated_override_does_not_persist_project_trust() -> R
|
||||
let server = create_mock_responses_server_sequence_unchecked(responses).await;
|
||||
|
||||
let codex_home = TempDir::new()?;
|
||||
MockResponsesConfig::new(&server.uri())
|
||||
.enable_feature(Feature::Personality)
|
||||
.write(codex_home.path())?;
|
||||
MockResponsesConfig::new(&server.uri()).write(codex_home.path())?;
|
||||
|
||||
let workspace = TempDir::new()?;
|
||||
|
||||
|
||||
@@ -383,7 +383,7 @@ pub struct ConfigToml {
|
||||
/// Per-thread `config` overrides are accepted but do not reapply this (no-ops).
|
||||
pub model_catalog_json: Option<AbsolutePathBuf>,
|
||||
|
||||
/// Optionally specify a personality for the model
|
||||
/// Deprecated: `friendly` and `pragmatic` no longer select a style.
|
||||
pub personality: Option<Personality>,
|
||||
|
||||
/// Optional explicit service tier request id for new turns (for example
|
||||
|
||||
@@ -39,6 +39,7 @@ pub struct ConfigProfile {
|
||||
pub model_verbosity: Option<Verbosity>,
|
||||
/// Optional path to a JSON model catalog (applied on startup only).
|
||||
pub model_catalog_json: Option<AbsolutePathBuf>,
|
||||
/// Deprecated: `friendly` and `pragmatic` no longer select a style.
|
||||
pub personality: Option<Personality>,
|
||||
pub chatgpt_base_url: Option<String>,
|
||||
/// Optional path to a file containing model instructions.
|
||||
|
||||
@@ -1164,7 +1164,12 @@
|
||||
"type": "string"
|
||||
},
|
||||
"personality": {
|
||||
"$ref": "#/definitions/Personality"
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Personality"
|
||||
}
|
||||
],
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"plan_mode_reasoning_effort": {
|
||||
"$ref": "#/definitions/ReasoningEffort"
|
||||
@@ -3200,6 +3205,7 @@
|
||||
"type": "object"
|
||||
},
|
||||
"Personality": {
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style.",
|
||||
"enum": [
|
||||
"none",
|
||||
"friendly",
|
||||
@@ -7028,7 +7034,7 @@
|
||||
"$ref": "#/definitions/Personality"
|
||||
}
|
||||
],
|
||||
"description": "Optionally specify a personality for the model"
|
||||
"description": "Deprecated: `friendly` and `pragmatic` no longer select a style."
|
||||
},
|
||||
"plan_mode_reasoning_effort": {
|
||||
"$ref": "#/definitions/ReasoningEffort"
|
||||
|
||||
@@ -94,7 +94,6 @@ async fn apply_role_to_config_inner(
|
||||
&& let Some(
|
||||
feature @ (Feature::ShellTool
|
||||
| Feature::Apps
|
||||
| Feature::Personality
|
||||
| Feature::Plugins
|
||||
| Feature::MemoryTool
|
||||
| Feature::RequestPermissionsTool),
|
||||
@@ -222,10 +221,8 @@ mod role_overrides {
|
||||
{
|
||||
next_config.include_skill_instructions = false;
|
||||
}
|
||||
let strips_baked_personality = |config: &Config| {
|
||||
config.features.enabled(Feature::Personality)
|
||||
&& config.personality == Some(Personality::None)
|
||||
};
|
||||
let strips_baked_personality =
|
||||
|config: &Config| config.personality == Some(Personality::None);
|
||||
if strips_baked_personality(config) != strips_baked_personality(&next_config)
|
||||
&& matches!(
|
||||
config.base_instructions_provenance,
|
||||
|
||||
@@ -250,6 +250,22 @@ async fn apply_role_refreshes_model_instructions_only_when_personality_opt_out_c
|
||||
},
|
||||
false,
|
||||
),
|
||||
(
|
||||
"none",
|
||||
"[features]\npersonality = false",
|
||||
BaseInstructionsProvenance::Model {
|
||||
model: "parent-model".to_string(),
|
||||
},
|
||||
false,
|
||||
),
|
||||
(
|
||||
"friendly",
|
||||
"personality = \"none\"\n[features]\npersonality = false",
|
||||
BaseInstructionsProvenance::Model {
|
||||
model: "parent-model".to_string(),
|
||||
},
|
||||
true,
|
||||
),
|
||||
(
|
||||
"friendly",
|
||||
"personality = \"pragmatic\"",
|
||||
|
||||
@@ -11201,7 +11201,7 @@ async fn feature_requirements_normalize_effective_feature_values() -> std::io::R
|
||||
CloudConfigBundleFixture::loader_with_enterprise_requirement(
|
||||
r#"
|
||||
[features]
|
||||
personality = true
|
||||
view_image = true
|
||||
shell_tool = false
|
||||
use_xaa = true
|
||||
"#,
|
||||
@@ -11210,7 +11210,7 @@ use_xaa = true
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
assert!(config.features.enabled(Feature::Personality));
|
||||
assert!(config.features.enabled(Feature::ViewImage));
|
||||
assert!(!config.features.enabled(Feature::ShellTool));
|
||||
assert!(
|
||||
!config
|
||||
@@ -11396,7 +11396,7 @@ async fn explicit_feature_config_is_normalized_by_requirements() -> std::io::Res
|
||||
codex_home.path().join(CONFIG_TOML_FILE),
|
||||
r#"
|
||||
[features]
|
||||
personality = false
|
||||
view_image = false
|
||||
shell_tool = true
|
||||
"#,
|
||||
)?;
|
||||
@@ -11408,7 +11408,7 @@ shell_tool = true
|
||||
CloudConfigBundleFixture::loader_with_enterprise_requirement(
|
||||
r#"
|
||||
[features]
|
||||
personality = true
|
||||
view_image = true
|
||||
shell_tool = false
|
||||
"#,
|
||||
),
|
||||
@@ -11416,7 +11416,7 @@ shell_tool = false
|
||||
.build()
|
||||
.await?;
|
||||
|
||||
assert!(config.features.enabled(Feature::Personality));
|
||||
assert!(config.features.enabled(Feature::ViewImage));
|
||||
assert!(!config.features.enabled(Feature::ShellTool));
|
||||
assert!(
|
||||
!config
|
||||
@@ -11430,6 +11430,55 @@ shell_tool = false
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retired_personality_feature_requirements_do_not_reject_configured_values() -> std::io::Result<()>
|
||||
{
|
||||
for (configured, required) in [(true, false), (false, true)] {
|
||||
let cfg: ConfigToml = toml::from_str(&format!(
|
||||
"[features]\npersonality = {configured}\nshell_tool = false\n"
|
||||
))
|
||||
.expect("valid config");
|
||||
let requirement = Sourced::new(
|
||||
FeatureRequirementsToml {
|
||||
entries: BTreeMap::from([
|
||||
("personality".to_string(), required),
|
||||
("shell_tool".to_string(), false),
|
||||
]),
|
||||
},
|
||||
RequirementSource::EnterpriseManaged {
|
||||
id: "enterprise-id".to_string(),
|
||||
name: "enterprise".to_string(),
|
||||
},
|
||||
);
|
||||
validate_feature_requirements_for_config_toml(&cfg, Some(&requirement))?;
|
||||
|
||||
let configured_features = Features::from_sources(
|
||||
FeatureConfigSource {
|
||||
features: cfg.features.as_ref(),
|
||||
..Default::default()
|
||||
},
|
||||
FeatureConfigSource::default(),
|
||||
FeatureOverrides::default(),
|
||||
);
|
||||
let mut warnings = Vec::new();
|
||||
let features = ManagedFeatures::from_configured_with_warnings(
|
||||
configured_features,
|
||||
Some(requirement),
|
||||
&mut warnings,
|
||||
)?;
|
||||
assert_eq!(
|
||||
(
|
||||
features.enabled(Feature::Personality),
|
||||
features.enabled(Feature::ShellTool),
|
||||
warnings,
|
||||
),
|
||||
(false, false, Vec::new()),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn approvals_reviewer_defaults_to_manual_only_without_guardian_feature() -> std::io::Result<()>
|
||||
{
|
||||
@@ -12327,7 +12376,7 @@ async fn feature_requirements_normalize_runtime_feature_mutations() -> std::io::
|
||||
CloudConfigBundleFixture::loader_with_enterprise_requirement(
|
||||
r#"
|
||||
[features]
|
||||
personality = true
|
||||
view_image = true
|
||||
shell_tool = false
|
||||
"#,
|
||||
),
|
||||
@@ -12337,7 +12386,7 @@ shell_tool = false
|
||||
|
||||
let mut requested = config.features.get().clone();
|
||||
requested
|
||||
.disable(Feature::Personality)
|
||||
.disable(Feature::ViewImage)
|
||||
.enable(Feature::ShellTool);
|
||||
assert!(config.features.can_set(&requested).is_ok());
|
||||
config
|
||||
@@ -12345,7 +12394,7 @@ shell_tool = false
|
||||
.set(requested)
|
||||
.expect("managed feature mutations should normalize successfully");
|
||||
|
||||
assert!(config.features.enabled(Feature::Personality));
|
||||
assert!(config.features.enabled(Feature::ViewImage));
|
||||
assert!(!config.features.enabled(Feature::ShellTool));
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -218,6 +218,9 @@ fn parse_feature_requirements(
|
||||
) -> BTreeMap<Feature, bool> {
|
||||
let mut pinned_features = BTreeMap::new();
|
||||
for (key, enabled) in feature_requirements.entries {
|
||||
if key == Feature::Personality.key() {
|
||||
continue;
|
||||
}
|
||||
if key == "auto_review" {
|
||||
pinned_features.insert(Feature::GuardianApproval, enabled);
|
||||
continue;
|
||||
|
||||
@@ -640,7 +640,7 @@ pub struct Config {
|
||||
/// Info needed to make an API request to the model.
|
||||
pub model_provider: ModelProviderInfo,
|
||||
|
||||
/// Optionally specify the personality of the model
|
||||
/// Deprecated: `friendly` and `pragmatic` no longer select a style.
|
||||
pub personality: Option<Personality>,
|
||||
|
||||
/// Effective permission configuration for shell tool execution.
|
||||
@@ -1622,7 +1622,6 @@ impl Config {
|
||||
Some(BaseInstructionsProvenance::Model { .. })
|
||||
)
|
||||
}),
|
||||
personality_enabled: self.features.enabled(Feature::Personality),
|
||||
personality: self.personality,
|
||||
model_catalog: self.model_catalog.clone(),
|
||||
}
|
||||
@@ -2575,6 +2574,7 @@ pub struct ConfigOverrides {
|
||||
pub default_zsh_path: Option<AbsolutePathBuf>,
|
||||
pub base_instructions: Option<String>,
|
||||
pub developer_instructions: Option<String>,
|
||||
/// Deprecated: `friendly` and `pragmatic` no longer select a style.
|
||||
pub personality: Option<Personality>,
|
||||
pub compact_prompt: Option<String>,
|
||||
pub show_raw_agent_reasoning: Option<bool>,
|
||||
|
||||
@@ -374,7 +374,6 @@ impl Session {
|
||||
&constraints,
|
||||
self.services.models_manager.as_ref(),
|
||||
&overrides,
|
||||
self.features.enabled(Feature::Personality),
|
||||
self.features.enabled(Feature::FastMode),
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -513,10 +513,9 @@ async fn submitted_sparse_updates_preserve_captured_steps_and_ordering() {
|
||||
let model_manager_config = {
|
||||
let state = session.state.lock().await;
|
||||
let configuration = &state.session_configuration;
|
||||
configuration.model_info_overrides.models_manager_config(
|
||||
configuration.step_settings.personality,
|
||||
session.features.enabled(Feature::Personality),
|
||||
)
|
||||
configuration
|
||||
.model_info_overrides
|
||||
.models_manager_config(configuration.step_settings.personality)
|
||||
};
|
||||
let expected_destination = with_config_overrides(expected_destination, &model_manager_config);
|
||||
let desired = desired_step_settings(&session).await;
|
||||
|
||||
@@ -129,7 +129,6 @@ impl ResolvedStepSettings {
|
||||
constraints: &StepSettingsConstraints<'_>,
|
||||
models_manager: &dyn ModelsManager,
|
||||
overrides: &ModelInfoOverrides,
|
||||
personality_enabled: bool,
|
||||
fast_mode_enabled: bool,
|
||||
) -> ConstraintResult<Self> {
|
||||
let selected = self.selected.apply(update, constraints)?;
|
||||
@@ -139,11 +138,7 @@ impl ResolvedStepSettings {
|
||||
{
|
||||
Arc::clone(&self.model_info)
|
||||
} else {
|
||||
Arc::new(
|
||||
selected
|
||||
.resolve_model_info(models_manager, overrides, personality_enabled)
|
||||
.await,
|
||||
)
|
||||
Arc::new(selected.resolve_model_info(models_manager, overrides).await)
|
||||
};
|
||||
let mut next = Self::new(Arc::new(selected), model_info, fast_mode_enabled);
|
||||
next.mcp_approvals_reviewer_override = update
|
||||
@@ -206,7 +201,6 @@ impl ModelInfoOverrides {
|
||||
pub(crate) fn models_manager_config(
|
||||
&self,
|
||||
personality: Option<Personality>,
|
||||
personality_enabled: bool,
|
||||
) -> ModelsManagerConfig {
|
||||
ModelsManagerConfig {
|
||||
model_context_window: self.context_window,
|
||||
@@ -214,7 +208,6 @@ impl ModelInfoOverrides {
|
||||
tool_output_token_limit: self.tool_output_token_limit,
|
||||
base_instructions: self.base_instructions.clone(),
|
||||
personality,
|
||||
personality_enabled,
|
||||
// The models manager already owns its catalog.
|
||||
model_catalog: None,
|
||||
}
|
||||
@@ -254,9 +247,8 @@ impl StepSettings {
|
||||
&self,
|
||||
models_manager: &dyn ModelsManager,
|
||||
overrides: &ModelInfoOverrides,
|
||||
personality_enabled: bool,
|
||||
) -> ModelInfo {
|
||||
let config = overrides.models_manager_config(self.personality, personality_enabled);
|
||||
let config = overrides.models_manager_config(self.personality);
|
||||
models_manager
|
||||
.get_model_info(self.collaboration_mode.model(), &config)
|
||||
.await
|
||||
|
||||
@@ -451,28 +451,14 @@ async fn model_resolution_preserves_startup_overrides_and_instruction_provenance
|
||||
// Capture the same filtered explicit overrides that session startup owns.
|
||||
let overrides = ModelInfoOverrides::from(config.to_models_manager_config());
|
||||
|
||||
for (personality, personality_enabled, catalog_instructions) in [
|
||||
for (personality, catalog_instructions) in [
|
||||
(
|
||||
Personality::Friendly,
|
||||
true,
|
||||
"Catalog B.\n# Personality\nfixed\n# Rules\nKeep the rules.",
|
||||
),
|
||||
(
|
||||
Personality::None,
|
||||
true,
|
||||
"Catalog B.\n# Rules\nKeep the rules.",
|
||||
),
|
||||
(
|
||||
Personality::Friendly,
|
||||
false,
|
||||
"Catalog B.\n# Personality\nfixed\n# Rules\nKeep the rules.",
|
||||
),
|
||||
(Personality::None, "Catalog B.\n# Rules\nKeep the rules."),
|
||||
] {
|
||||
config.personality = Some(personality);
|
||||
config
|
||||
.features
|
||||
.set_enabled(Feature::Personality, personality_enabled)
|
||||
.expect("test config should allow personality changes");
|
||||
let mut settings = configured_settings();
|
||||
settings.collaboration_mode = settings.collaboration_mode.with_updates(
|
||||
Some("model-b".to_string()),
|
||||
@@ -485,11 +471,7 @@ async fn model_resolution_preserves_startup_overrides_and_instruction_provenance
|
||||
.get_model_info("model-b", &config.to_models_manager_config())
|
||||
.await;
|
||||
let resolved = settings
|
||||
.resolve_model_info(
|
||||
&models_manager,
|
||||
&overrides,
|
||||
config.features.enabled(Feature::Personality),
|
||||
)
|
||||
.resolve_model_info(&models_manager, &overrides)
|
||||
.await;
|
||||
assert_eq!(resolved, legacy);
|
||||
assert_eq!(
|
||||
|
||||
@@ -1018,7 +1018,6 @@ impl Session {
|
||||
.resolve_model_info(
|
||||
self.services.models_manager.as_ref(),
|
||||
&session_configuration.model_info_overrides,
|
||||
self.features.enabled(Feature::Personality),
|
||||
)
|
||||
.await;
|
||||
let multi_agent_version = match multi_agent_runtime {
|
||||
|
||||
@@ -181,14 +181,8 @@ async fn first_turn_model_change_appends_model_instructions_developer_message(
|
||||
let server = MockServer::start().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
|
||||
let mut builder = test_codex()
|
||||
.with_model_info_override("gpt-5.6-terra", configure_model_switching_fixture)
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let mut builder =
|
||||
test_codex().with_model_info_override("gpt-5.6-terra", configure_model_switching_fixture);
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
let next_model = "gpt-5.5";
|
||||
|
||||
@@ -401,12 +395,7 @@ async fn model_change_with_legacy_personality_override_only_appends_model_instru
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let mut builder = test_codex().with_model("gpt-5.5");
|
||||
let test = builder.build(&server).await?;
|
||||
let next_model = "exp-codex-personality";
|
||||
|
||||
|
||||
@@ -549,10 +549,6 @@ async fn snapshot_model_visible_layout_resume_with_personality_change() -> Resul
|
||||
.with_config(|config| {
|
||||
config.update_plan_enabled = true;
|
||||
config.model = Some("gpt-5.4".to_string());
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::Pragmatic);
|
||||
});
|
||||
let resumed = resume_builder.restart(&server, &initial).await?;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use codex_config::types::Personality;
|
||||
use codex_core::TurnInputRequest;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::config_types::CollaborationMode;
|
||||
use codex_protocol::config_types::ModeKind;
|
||||
use codex_protocol::config_types::Settings;
|
||||
@@ -64,10 +63,6 @@ async fn config_personality_none_sends_no_personality() -> anyhow::Result<()> {
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::None);
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
@@ -106,8 +101,13 @@ async fn config_personality_none_sends_no_personality() -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test_case(None; "without feature config")]
|
||||
#[test_case(Some(false); "with removed feature disabled")]
|
||||
#[test_case(Some(true); "with removed feature enabled")]
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn config_personality_none_strips_baked_personality_section() -> anyhow::Result<()> {
|
||||
async fn config_personality_none_strips_baked_personality_section(
|
||||
legacy_feature_setting: Option<bool>,
|
||||
) -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = start_mock_server().await;
|
||||
@@ -119,14 +119,14 @@ async fn config_personality_none_strips_baked_personality_section() -> anyhow::R
|
||||
model_messages.instructions_variables = None;
|
||||
}
|
||||
})
|
||||
.with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::None);
|
||||
.with_pre_build_hook(move |home| {
|
||||
let mut config = "personality = \"none\"\n".to_string();
|
||||
if let Some(value) = legacy_feature_setting {
|
||||
config.push_str(&format!("[features]\npersonality = {value}\n"));
|
||||
}
|
||||
std::fs::write(home.join("config.toml"), config).expect("write personality config");
|
||||
});
|
||||
let test = builder.build(&server).await?;
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
|
||||
test.codex
|
||||
.start_or_steer_turn(read_only_text_turn(
|
||||
@@ -152,7 +152,7 @@ async fn config_personality_none_strips_baked_personality_section() -> anyhow::R
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn config_personality_none_preserves_explicit_base_instructions(
|
||||
custom_instructions: &'static str,
|
||||
personality_enabled: bool,
|
||||
legacy_feature_setting: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
@@ -160,12 +160,13 @@ async fn config_personality_none_preserves_explicit_base_instructions(
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex()
|
||||
.with_model("gpt-5.5")
|
||||
.with_pre_build_hook(move |home| {
|
||||
let config = format!(
|
||||
"personality = \"none\"\n[features]\npersonality = {legacy_feature_setting}\n"
|
||||
);
|
||||
std::fs::write(home.join("config.toml"), config).expect("write personality config");
|
||||
})
|
||||
.with_config(move |config| {
|
||||
config
|
||||
.features
|
||||
.set_enabled(Feature::Personality, personality_enabled)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::None);
|
||||
config.base_instructions = Some(custom_instructions.to_string());
|
||||
});
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
@@ -198,12 +199,7 @@ async fn default_instructions_are_friendly_without_config_toml() -> anyhow::Resu
|
||||
|
||||
let server = start_mock_server().await;
|
||||
let resp_mock = mount_sse_once(&server, sse_completed("resp-1")).await;
|
||||
let mut builder = test_codex().with_model("gpt-5.5").with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
});
|
||||
let mut builder = test_codex().with_model("gpt-5.5");
|
||||
let test = builder.build(&server).await?;
|
||||
assert_eq!(test.config.personality, None);
|
||||
|
||||
@@ -245,10 +241,6 @@ async fn fixed_friendly_personality_ignores_pragmatic_update(
|
||||
)
|
||||
.await;
|
||||
let mut builder = test_codex().with_model(model).with_config(|config| {
|
||||
config
|
||||
.features
|
||||
.enable(Feature::Personality)
|
||||
.expect("test config should allow feature update");
|
||||
config.personality = Some(Personality::Friendly);
|
||||
});
|
||||
let test = builder.build_with_auto_env(&server).await?;
|
||||
|
||||
@@ -344,7 +344,7 @@ pub enum Feature {
|
||||
AuthElicitation,
|
||||
/// Offer Amazon Bedrock setup during TUI sign-in onboarding.
|
||||
BedrockSetupWizard,
|
||||
/// Enable personality selection in the TUI.
|
||||
/// Removed compatibility flag retained as a no-op.
|
||||
Personality,
|
||||
/// Enable native artifact tools.
|
||||
Artifact,
|
||||
@@ -610,7 +610,7 @@ impl Features {
|
||||
"image_detail_original" | "resize_all_images" | "item_ids" => {
|
||||
continue;
|
||||
}
|
||||
"plugin_hooks" => {
|
||||
"personality" | "plugin_hooks" => {
|
||||
continue;
|
||||
}
|
||||
"skill_env_var_dependency_prompt" => {
|
||||
@@ -1688,8 +1688,8 @@ pub const FEATURES: &[FeatureSpec] = &[
|
||||
FeatureSpec {
|
||||
id: Feature::Personality,
|
||||
key: "personality",
|
||||
stage: Stage::Stable,
|
||||
default_enabled: true,
|
||||
stage: Stage::Removed,
|
||||
default_enabled: false,
|
||||
},
|
||||
FeatureSpec {
|
||||
id: Feature::Artifact,
|
||||
|
||||
@@ -645,6 +645,35 @@ fn from_sources_ignores_removed_apply_patch_freeform_feature_key() {
|
||||
assert_eq!(features, Features::with_defaults());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sources_accepts_and_ignores_removed_personality_feature_values() {
|
||||
for enabled in [false, true] {
|
||||
let features_toml: FeaturesToml = toml::from_str(&format!("personality = {enabled}"))
|
||||
.expect("legacy personality feature should deserialize");
|
||||
let source = FeatureConfigSource {
|
||||
features: Some(&features_toml),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
Features::from_sources(
|
||||
source,
|
||||
FeatureConfigSource::default(),
|
||||
FeatureOverrides::default(),
|
||||
),
|
||||
Features::with_defaults()
|
||||
);
|
||||
assert_eq!(
|
||||
Features::from_sources(
|
||||
FeatureConfigSource::default(),
|
||||
source,
|
||||
FeatureOverrides::default(),
|
||||
),
|
||||
Features::with_defaults()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_sources_ignores_removed_plugin_hooks_feature_key() {
|
||||
let features_toml = FeaturesToml::from(BTreeMap::from([("plugin_hooks".to_string(), true)]));
|
||||
@@ -796,7 +825,7 @@ fn unstable_warning_event_only_mentions_enabled_under_development_features() {
|
||||
"apply_patch_streaming_events".to_string(),
|
||||
TomlValue::Boolean(true),
|
||||
);
|
||||
configured_features.insert("personality".to_string(), TomlValue::Boolean(true));
|
||||
configured_features.insert("fast_mode".to_string(), TomlValue::Boolean(true));
|
||||
configured_features.insert("unknown".to_string(), TomlValue::Boolean(true));
|
||||
|
||||
let mut features = Features::with_defaults();
|
||||
@@ -814,7 +843,7 @@ fn unstable_warning_event_only_mentions_enabled_under_development_features() {
|
||||
panic!("expected warning event");
|
||||
};
|
||||
assert!(message.contains("apply_patch_streaming_events"));
|
||||
assert!(!message.contains("personality"));
|
||||
assert!(!message.contains("fast_mode"));
|
||||
assert!(message.contains("/tmp/config.toml"));
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ pub struct ModelsManagerConfig {
|
||||
pub model_auto_compact_token_limit: Option<i64>,
|
||||
pub tool_output_token_limit: Option<usize>,
|
||||
pub base_instructions: Option<String>,
|
||||
pub personality_enabled: bool,
|
||||
pub personality: Option<Personality>,
|
||||
pub model_catalog: Option<ModelsResponse>,
|
||||
}
|
||||
|
||||
@@ -60,8 +60,7 @@ pub fn with_config_overrides(mut model: ModelInfo, config: &ModelsManagerConfig)
|
||||
});
|
||||
model_messages.instructions_template = Some(base_instructions.clone());
|
||||
model_messages.instructions_variables = None;
|
||||
} else if config.personality_enabled
|
||||
&& config.personality == Some(Personality::None)
|
||||
} else if config.personality == Some(Personality::None)
|
||||
&& let Some(instructions_template) = model
|
||||
.model_messages
|
||||
.as_mut()
|
||||
|
||||
@@ -18,7 +18,6 @@ use pretty_assertions::assert_eq;
|
||||
|
||||
fn config_with_personality(personality: Option<Personality>) -> ModelsManagerConfig {
|
||||
ModelsManagerConfig {
|
||||
personality_enabled: true,
|
||||
personality,
|
||||
..Default::default()
|
||||
}
|
||||
@@ -26,7 +25,7 @@ fn config_with_personality(personality: Option<Personality>) -> ModelsManagerCon
|
||||
|
||||
#[test]
|
||||
fn base_instruction_override_is_literal_and_preserves_catalog_messages() {
|
||||
let override_instructions = "override {{ personality }}";
|
||||
let override_instructions = "override {{ personality }}\n# Personality\nKeep me";
|
||||
let persistent_instructions = "Follow up on the active task.";
|
||||
let async_message_description = "Catalog async message description.";
|
||||
let mut model = model_info_from_slug("unknown-model");
|
||||
@@ -104,6 +103,7 @@ fn base_instruction_override_is_literal_and_preserves_catalog_messages() {
|
||||
});
|
||||
let config = ModelsManagerConfig {
|
||||
base_instructions: Some(override_instructions.to_string()),
|
||||
personality: Some(Personality::None),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
@@ -131,7 +131,7 @@ fn base_instruction_override_is_literal_and_preserves_catalog_messages() {
|
||||
})
|
||||
);
|
||||
assert_eq!(
|
||||
updated.get_model_instructions(/*personality*/ None),
|
||||
updated.get_model_instructions(Some(Personality::None)),
|
||||
override_instructions
|
||||
);
|
||||
}
|
||||
@@ -193,16 +193,12 @@ fn personality_none_strips_catalog_instruction_sources_through_the_next_h1() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn baked_personality_section_is_preserved_without_enabled_explicit_none() {
|
||||
fn baked_personality_section_is_preserved_without_explicit_none() {
|
||||
let instructions = "Intro\n# Personality\nKeep me\n# General\nKeep me too";
|
||||
let configs = [
|
||||
config_with_personality(/*personality*/ None),
|
||||
config_with_personality(Some(Personality::Friendly)),
|
||||
config_with_personality(Some(Personality::Pragmatic)),
|
||||
ModelsManagerConfig {
|
||||
personality: Some(Personality::None),
|
||||
..Default::default()
|
||||
},
|
||||
];
|
||||
|
||||
for config in configs {
|
||||
@@ -220,6 +216,32 @@ fn baked_personality_section_is_preserved_without_enabled_explicit_none() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn explicit_empty_base_instructions_stay_empty_with_personality_none() {
|
||||
let mut model = model_info_from_slug("unknown-model");
|
||||
model
|
||||
.model_messages
|
||||
.as_mut()
|
||||
.expect("fallback model messages")
|
||||
.instructions_template = Some("Intro\n# Personality\nRemove me".to_string());
|
||||
let config = ModelsManagerConfig {
|
||||
base_instructions: Some(String::new()),
|
||||
personality: Some(Personality::None),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let updated = with_config_overrides(model, &config);
|
||||
|
||||
assert_eq!(
|
||||
updated
|
||||
.model_messages
|
||||
.as_ref()
|
||||
.and_then(|messages| messages.instructions_template.as_deref()),
|
||||
Some("")
|
||||
);
|
||||
assert_eq!(updated.get_model_instructions(config.personality), "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_model_uses_builtin_instruction_template() {
|
||||
let model = model_info_from_slug("unknown-model");
|
||||
|
||||
@@ -311,6 +311,7 @@ pub enum WindowsSandboxProxySettingsMode {
|
||||
Preserve,
|
||||
}
|
||||
|
||||
/// Deprecated: `friendly` and `pragmatic` no longer select a style.
|
||||
#[derive(
|
||||
Debug,
|
||||
Serialize,
|
||||
|
||||
@@ -40,6 +40,7 @@ from openai_codex.types import (
|
||||
CancelLoginAccountStatus,
|
||||
GetAccountResponse,
|
||||
InitializeResponse,
|
||||
Personality,
|
||||
ThreadItem,
|
||||
ThreadTokenUsage,
|
||||
TurnError,
|
||||
@@ -88,6 +89,27 @@ server's default behavior. This does not remove history from the model's
|
||||
context. Both methods return a thread handle; use `thread.read(include_turns=True)`
|
||||
to retrieve its history.
|
||||
|
||||
### Deprecated personality selection
|
||||
|
||||
`thread_start(...)`, `thread_resume(...)`, and the thread's `run(...)` and
|
||||
`turn(...)` still accept `personality` for compatibility. The current app-server
|
||||
accepts `Personality.friendly` and `Personality.pragmatic`, but they no longer
|
||||
select a style; model instructions define the tone.
|
||||
|
||||
Python `None` or omitting the option leaves it unset. Explicit `Personality.none`
|
||||
(wire value `"none"`) strips the literal `# Personality` section the next time
|
||||
Codex prepares instructions from the model catalog, such as when starting a
|
||||
thread or switching models. It does not change explicitly supplied base
|
||||
instructions or rewrite an existing thread's instructions when resuming or
|
||||
starting a turn. Either legacy value can replace a previous `Personality.none`
|
||||
setting for future model instructions. The old `features.personality` flag is
|
||||
ignored.
|
||||
|
||||
Models returned by `models(...)` still expose `supports_personality` for
|
||||
compatibility. This field is deprecated and always `False` on the current
|
||||
app-server; it describes selectable personality, not the separate
|
||||
`Personality.none` opt-out.
|
||||
|
||||
## AsyncCodex (async parity)
|
||||
|
||||
```python
|
||||
@@ -121,6 +143,9 @@ Properties/methods:
|
||||
- `thread_unarchive(thread_id: str) -> Awaitable[AsyncThread]`
|
||||
- `models(*, include_hidden: bool = False) -> Awaitable[ModelListResponse]`
|
||||
|
||||
The [deprecated personality selection](#deprecated-personality-selection)
|
||||
notes also apply to the async methods and model results.
|
||||
|
||||
Async context manager:
|
||||
|
||||
```python
|
||||
@@ -198,6 +223,7 @@ These options have the same behavior on sync and async `run(...)` and `turn(...)
|
||||
|
||||
| Option | Behavior |
|
||||
| --- | --- |
|
||||
| `personality: Personality \| None = None` | `Personality.friendly` and `Personality.pragmatic` are deprecated and no longer select a style. See [deprecated personality selection](#deprecated-personality-selection). |
|
||||
| `service_tier: str | None = None` | Sets the thread's service tier for this and subsequent turns. |
|
||||
| `turn_service_tier: str | None = None` | Overrides the tier for a newly started turn only. `None` inherits the thread setting; `"default"` selects standard speed. Does not change the thread default and is ignored when input joins an active turn. |
|
||||
| `source: str | None = None` | Labels the caller that initiated a new turn, such as `"review_ui"`. This is metadata; it does not schedule work or grant authority. Ignored when input joins an active turn. |
|
||||
|
||||
@@ -297,7 +297,11 @@ class Codex:
|
||||
# END GENERATED: Codex.flat_methods
|
||||
|
||||
def models(self, *, include_hidden: bool = False) -> ModelListResponse:
|
||||
"""List available models reported by Codex."""
|
||||
"""List available models reported by Codex.
|
||||
|
||||
The deprecated ``Model.supports_personality`` field is always ``False``
|
||||
on the current app-server.
|
||||
"""
|
||||
return self._client.model_list(include_hidden=include_hidden)
|
||||
|
||||
|
||||
@@ -557,6 +561,11 @@ class AsyncCodex:
|
||||
# END GENERATED: AsyncCodex.flat_methods
|
||||
|
||||
async def models(self, *, include_hidden: bool = False) -> ModelListResponse:
|
||||
"""List available models reported by Codex.
|
||||
|
||||
The deprecated ``Model.supports_personality`` field is always ``False``
|
||||
on the current app-server.
|
||||
"""
|
||||
await self._ensure_initialized()
|
||||
return await self._client.model_list(include_hidden=include_hidden)
|
||||
|
||||
|
||||
@@ -5834,7 +5834,12 @@ class ThreadResumeParams(BaseModel):
|
||||
str | None, Field(description="Configuration overrides for the resumed thread, if any.")
|
||||
] = None
|
||||
model_provider: Annotated[str | None, Field(alias="modelProvider")] = None
|
||||
personality: Personality | None = None
|
||||
personality: Annotated[
|
||||
Personality | None,
|
||||
Field(
|
||||
description="@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
),
|
||||
] = None
|
||||
sandbox: SandboxMode | None = None
|
||||
service_tier: Annotated[str | None, Field(alias="serviceTier")] = None
|
||||
thread_id: Annotated[str, Field(alias="threadId")]
|
||||
@@ -8521,7 +8526,13 @@ class Model(BaseModel):
|
||||
supported_reasoning_efforts: Annotated[
|
||||
list[ReasoningEffortOption], Field(alias="supportedReasoningEfforts")
|
||||
]
|
||||
supports_personality: Annotated[bool | None, Field(alias="supportsPersonality")] = False
|
||||
supports_personality: Annotated[
|
||||
bool | None,
|
||||
Field(
|
||||
alias="supportsPersonality",
|
||||
description="@deprecated Always false; models no longer support personality selection.",
|
||||
),
|
||||
] = False
|
||||
upgrade: str | None = None
|
||||
upgrade_info: Annotated[ModelUpgradeInfo | None, Field(alias="upgradeInfo")] = None
|
||||
|
||||
@@ -9971,7 +9982,12 @@ class ThreadSettings(BaseModel):
|
||||
effort: ReasoningEffort | None = None
|
||||
model: str
|
||||
model_provider: Annotated[str, Field(alias="modelProvider")]
|
||||
personality: Personality | None = None
|
||||
personality: Annotated[
|
||||
Personality | None,
|
||||
Field(
|
||||
description="@deprecated Reports the saved setting; `friendly` and `pragmatic` no longer select a style."
|
||||
),
|
||||
] = None
|
||||
sandbox_policy: Annotated[SandboxPolicy, Field(alias="sandboxPolicy")]
|
||||
service_tier: Annotated[str | None, Field(alias="serviceTier")] = None
|
||||
summary: ReasoningSummary | None = None
|
||||
@@ -10004,7 +10020,10 @@ class ThreadStartParams(BaseModel):
|
||||
ephemeral: bool | None = None
|
||||
model: str | None = None
|
||||
model_provider: Annotated[str | None, Field(alias="modelProvider")] = None
|
||||
personality: Personality | None = None
|
||||
personality: Annotated[
|
||||
Personality | None,
|
||||
Field(description="@deprecated `friendly` and `pragmatic` no longer select a style."),
|
||||
] = None
|
||||
sandbox: SandboxMode | None = None
|
||||
service_name: Annotated[str | None, Field(alias="serviceName")] = None
|
||||
service_tier: Annotated[str | None, Field(alias="serviceTier")] = None
|
||||
@@ -10424,7 +10443,7 @@ class ConfigBatchWriteParams(BaseModel):
|
||||
bool | None,
|
||||
Field(
|
||||
alias="reloadUserConfig",
|
||||
description="When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, service-tier, and personality defaults are not reloaded.",
|
||||
description="When true, hot-reload updated runtime settings into loaded threads after writing. Session-static model, reasoning-effort, Plan-mode reasoning-effort, and service-tier defaults are not reloaded. The deprecated personality setting is also not reloaded.",
|
||||
),
|
||||
] = None
|
||||
|
||||
@@ -12141,7 +12160,9 @@ class TurnStartParams(BaseModel):
|
||||
] = None
|
||||
personality: Annotated[
|
||||
Personality | None,
|
||||
Field(description="Override the personality for this turn and subsequent turns."),
|
||||
Field(
|
||||
description="@deprecated `friendly` and `pragmatic` no longer select a style. Changing this does not rewrite the thread's existing instructions."
|
||||
),
|
||||
] = None
|
||||
sandbox_policy: Annotated[
|
||||
SandboxPolicy | None,
|
||||
|
||||
Reference in New Issue
Block a user