diff --git a/codex-rs/app-server-protocol/schema/json/ClientRequest.json b/codex-rs/app-server-protocol/schema/json/ClientRequest.json index 1e8ffa9dd8..5450963f90 100644 --- a/codex-rs/app-server-protocol/schema/json/ClientRequest.json +++ b/codex-rs/app-server-protocol/schema/json/ClientRequest.json @@ -69,13 +69,46 @@ "type": "object" }, "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "AskForApproval2": { "description": "Determines the conditions under which the user is consulted to approve running the command proposed by Codex.", @@ -101,6 +134,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval2", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/EventMsg.json b/codex-rs/app-server-protocol/schema/json/EventMsg.json index 5ec61285ca..2193ae7e67 100644 --- a/codex-rs/app-server-protocol/schema/json/EventMsg.json +++ b/codex-rs/app-server-protocol/schema/json/EventMsg.json @@ -117,6 +117,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/ServerNotification.json b/codex-rs/app-server-protocol/schema/json/ServerNotification.json index 540e037563..bc87e0e3a6 100644 --- a/codex-rs/app-server-protocol/schema/json/ServerNotification.json +++ b/codex-rs/app-server-protocol/schema/json/ServerNotification.json @@ -454,6 +454,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json index 82f5c3b7dc..9b61d17447 100644 --- a/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json +++ b/codex-rs/app-server-protocol/schema/json/codex_app_server_protocol.schemas.json @@ -221,6 +221,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ @@ -10667,13 +10700,46 @@ "type": "object" }, "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "AuthMode": { "description": "Authentication mode for OpenAI-backed providers.", diff --git a/codex-rs/app-server-protocol/schema/json/v1/ForkConversationParams.json b/codex-rs/app-server-protocol/schema/json/v1/ForkConversationParams.json index cd52a492e5..1c04298ea7 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/ForkConversationParams.json +++ b/codex-rs/app-server-protocol/schema/json/v1/ForkConversationParams.json @@ -25,6 +25,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v1/ForkConversationResponse.json b/codex-rs/app-server-protocol/schema/json/v1/ForkConversationResponse.json index a73c550f69..58db5e77db 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/ForkConversationResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v1/ForkConversationResponse.json @@ -117,6 +117,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v1/GetUserSavedConfigResponse.json b/codex-rs/app-server-protocol/schema/json/v1/GetUserSavedConfigResponse.json index beec3a22cc..3450fdcb4a 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/GetUserSavedConfigResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v1/GetUserSavedConfigResponse.json @@ -29,6 +29,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v1/NewConversationParams.json b/codex-rs/app-server-protocol/schema/json/v1/NewConversationParams.json index 327ecd23b2..8a0a56a733 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/NewConversationParams.json +++ b/codex-rs/app-server-protocol/schema/json/v1/NewConversationParams.json @@ -25,6 +25,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationParams.json b/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationParams.json index 9f14c22084..6999dc08ec 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationParams.json +++ b/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationParams.json @@ -25,6 +25,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationResponse.json b/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationResponse.json index 6dc02934d3..c4a506033a 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v1/ResumeConversationResponse.json @@ -117,6 +117,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v1/SendUserTurnParams.json b/codex-rs/app-server-protocol/schema/json/v1/SendUserTurnParams.json index aa112e7319..6d8485e12e 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/SendUserTurnParams.json +++ b/codex-rs/app-server-protocol/schema/json/v1/SendUserTurnParams.json @@ -29,6 +29,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v1/SessionConfiguredNotification.json b/codex-rs/app-server-protocol/schema/json/v1/SessionConfiguredNotification.json index 69967e6853..af71b8f3ec 100644 --- a/codex-rs/app-server-protocol/schema/json/v1/SessionConfiguredNotification.json +++ b/codex-rs/app-server-protocol/schema/json/v1/SessionConfiguredNotification.json @@ -117,6 +117,39 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v2/ConfigReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ConfigReadResponse.json index d934df7f58..293fe7dc31 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ConfigReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ConfigReadResponse.json @@ -47,13 +47,46 @@ "type": "object" }, "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "Config": { "additionalProperties": true, diff --git a/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json index 3ba96a852a..4d8a967375 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ConfigRequirementsReadResponse.json @@ -2,13 +2,46 @@ "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "ConfigRequirements": { "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json index 5638468a4c..2b832d5bf1 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkParams.json @@ -2,13 +2,46 @@ "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "SandboxMode": { "enum": [ diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json index de1823e9de..47428c2c14 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadForkResponse.json @@ -6,13 +6,46 @@ "type": "string" }, "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "ByteRange": { "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json index fc6593b186..29d6fbc6d7 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeParams.json @@ -2,13 +2,46 @@ "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "ContentItem": { "oneOf": [ diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json index 4385565f96..aba2a13b9d 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadResumeResponse.json @@ -6,13 +6,46 @@ "type": "string" }, "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "ByteRange": { "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json index 1574c0710e..6b9c1568f0 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartParams.json @@ -2,13 +2,46 @@ "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "DynamicToolSpec": { "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json index fd75b56a28..fb09a7a14b 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json +++ b/codex-rs/app-server-protocol/schema/json/v2/ThreadStartResponse.json @@ -6,13 +6,46 @@ "type": "string" }, "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "ByteRange": { "properties": { diff --git a/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json b/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json index a1363f97d7..bc15473cc0 100644 --- a/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json +++ b/codex-rs/app-server-protocol/schema/json/v2/TurnStartParams.json @@ -6,13 +6,46 @@ "type": "string" }, "AskForApproval": { - "enum": [ - "untrusted", - "on-failure", - "on-request", - "never" - ], - "type": "string" + "oneOf": [ + { + "enum": [ + "untrusted", + "on-failure", + "on-request", + "never" + ], + "type": "string" + }, + { + "additionalProperties": false, + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "type": "boolean" + }, + "rules": { + "type": "boolean" + }, + "sandbox_approval": { + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "title": "RejectAskForApproval", + "type": "object" + } + ] }, "ByteRange": { "properties": { diff --git a/codex-rs/app-server-protocol/schema/typescript/AskForApproval.ts b/codex-rs/app-server-protocol/schema/typescript/AskForApproval.ts index b21e86fd70..2ea9c64e5b 100644 --- a/codex-rs/app-server-protocol/schema/typescript/AskForApproval.ts +++ b/codex-rs/app-server-protocol/schema/typescript/AskForApproval.ts @@ -6,4 +6,16 @@ * Determines the conditions under which the user is consulted to approve * running the command proposed by Codex. */ -export type AskForApproval = "untrusted" | "on-failure" | "on-request" | "never"; +export type AskForApproval = "untrusted" | "on-failure" | "on-request" | { "reject": { +/** + * Reject approval prompts related to sandbox escalation. + */ +sandbox_approval: boolean, +/** + * Reject prompts triggered by execpolicy `prompt` rules. + */ +rules: boolean, +/** + * Reject MCP elicitation prompts. + */ +mcp_elicitations: boolean, } } | "never"; diff --git a/codex-rs/app-server-protocol/schema/typescript/v2/AskForApproval.ts b/codex-rs/app-server-protocol/schema/typescript/v2/AskForApproval.ts index d3c3e77e39..b5f1bacdfa 100644 --- a/codex-rs/app-server-protocol/schema/typescript/v2/AskForApproval.ts +++ b/codex-rs/app-server-protocol/schema/typescript/v2/AskForApproval.ts @@ -2,4 +2,4 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. -export type AskForApproval = "untrusted" | "on-failure" | "on-request" | "never"; +export type AskForApproval = "untrusted" | "on-failure" | "on-request" | { "reject": { sandbox_approval: boolean, rules: boolean, mcp_elicitations: boolean, } } | "never"; diff --git a/codex-rs/app-server-protocol/src/protocol/v2.rs b/codex-rs/app-server-protocol/src/protocol/v2.rs index 96c14ef5f1..c8531ab55f 100644 --- a/codex-rs/app-server-protocol/src/protocol/v2.rs +++ b/codex-rs/app-server-protocol/src/protocol/v2.rs @@ -161,6 +161,11 @@ pub enum AskForApproval { UnlessTrusted, OnFailure, OnRequest, + Reject { + sandbox_approval: bool, + rules: bool, + mcp_elicitations: bool, + }, Never, } @@ -170,6 +175,15 @@ impl AskForApproval { AskForApproval::UnlessTrusted => CoreAskForApproval::UnlessTrusted, AskForApproval::OnFailure => CoreAskForApproval::OnFailure, AskForApproval::OnRequest => CoreAskForApproval::OnRequest, + AskForApproval::Reject { + sandbox_approval, + rules, + mcp_elicitations, + } => CoreAskForApproval::Reject { + sandbox_approval, + rules, + mcp_elicitations, + }, AskForApproval::Never => CoreAskForApproval::Never, } } @@ -181,6 +195,15 @@ impl From for AskForApproval { CoreAskForApproval::UnlessTrusted => AskForApproval::UnlessTrusted, CoreAskForApproval::OnFailure => AskForApproval::OnFailure, CoreAskForApproval::OnRequest => AskForApproval::OnRequest, + CoreAskForApproval::Reject { + sandbox_approval, + rules, + mcp_elicitations, + } => AskForApproval::Reject { + sandbox_approval, + rules, + mcp_elicitations, + }, CoreAskForApproval::Never => AskForApproval::Never, } } diff --git a/codex-rs/core/config.schema.json b/codex-rs/core/config.schema.json index e3f7456c95..b470d0c8c1 100644 --- a/codex-rs/core/config.schema.json +++ b/codex-rs/core/config.schema.json @@ -133,6 +133,77 @@ ], "type": "string" }, + { + "additionalProperties": false, + "description": "Fine-grained rejection controls for approval prompts.\n\nWhen a field is `true`, prompts of that category are automatically rejected instead of shown to the user.", + "properties": { + "reject": { + "properties": { + "mcp_elicitations": { + "description": "Reject MCP elicitation prompts.", + "type": "boolean" + }, + "rules": { + "description": "Reject prompts triggered by execpolicy `prompt` rules.", + "type": "boolean" + }, + "sandbox_approval": { + "description": "Reject approval prompts related to sandbox escalation.", + "type": "boolean" + } + }, + "required": [ + "mcp_elicitations", + "rules", + "sandbox_approval" + ], + "type": "object" + } + }, + "required": [ + "reject" + ], + "type": "object" + }, + { + "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", + "enum": [ + "never" + ], + "type": "string" + } + ] + }, + "AskForApprovalToml": { + "oneOf": [ + { + "description": "Under this policy, only \"known safe\" commands—those matching `is_safe_command()` and performing read-only file operations—are auto-approved. Everything else will ask the user to approve.", + "enum": [ + "untrusted" + ], + "type": "string" + }, + { + "description": "DEPRECATED: *All* commands are auto-approved, but they are expected to run inside a sandbox where network access is disabled and writes are confined to a specific set of paths. If the command fails, it will be escalated to the user to approve execution without a sandbox. Prefer `OnRequest` for interactive runs or `Never` for non-interactive runs.", + "enum": [ + "on-failure" + ], + "type": "string" + }, + { + "description": "The model decides when to ask the user for approval.", + "enum": [ + "on-request" + ], + "type": "string" + }, + { + "description": "Reject sandbox escalation approvals by default, while still allowing rule-driven prompts and MCP elicitations.", + "enum": [ + "reject" + ], + "type": "string" + }, { "description": "Never ask the user to approve commands. Failures are immediately returned to the model, and never escalated to the user for approval.", "enum": [ @@ -1280,7 +1351,7 @@ "approval_policy": { "allOf": [ { - "$ref": "#/definitions/AskForApproval" + "$ref": "#/definitions/AskForApprovalToml" } ], "description": "Default approval policy for executing commands." diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index 6fa5ae3b80..2a6fbefe03 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -1380,10 +1380,9 @@ impl Session { required_mcp_servers.sort(); let cancel_token = sess.mcp_startup_cancellation_token().await; - sess.services - .mcp_connection_manager - .write() - .await + let mut mcp_connection_manager = sess.services.mcp_connection_manager.write().await; + mcp_connection_manager.set_approval_policy(&session_configuration.approval_policy); + mcp_connection_manager .initialize( &mcp_servers, config.mcp_oauth_credentials_store_mode, @@ -1393,6 +1392,7 @@ impl Session { sandbox_state, ) .await; + drop(mcp_connection_manager); if !required_mcp_servers.is_empty() { let failures = sess .services @@ -1828,6 +1828,11 @@ impl Session { sandbox_policy_changed: bool, ) -> Arc { let per_turn_config = Self::build_per_turn_config(&session_configuration); + self.services + .mcp_connection_manager + .read() + .await + .set_approval_policy(&session_configuration.approval_policy); if sandbox_policy_changed { let sandbox_state = SandboxState { diff --git a/codex-rs/core/src/config/mod.rs b/codex-rs/core/src/config/mod.rs index 9874cc2774..93846bb80b 100644 --- a/codex-rs/core/src/config/mod.rs +++ b/codex-rs/core/src/config/mod.rs @@ -893,7 +893,7 @@ pub struct ConfigToml { pub model_auto_compact_token_limit: Option, /// Default approval policy for executing commands. - pub approval_policy: Option, + pub approval_policy: Option, #[serde(default)] pub shell_environment_policy: ShellEnvironmentPolicyToml, @@ -1113,7 +1113,7 @@ impl From for UserSavedConfig { .collect(); Self { - approval_policy: config_toml.approval_policy, + approval_policy: config_toml.approval_policy.map(Into::into), 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, @@ -1129,6 +1129,48 @@ impl From for UserSavedConfig { } } +/// Version of [AskForApproval] that is deserializable from config.toml. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "kebab-case")] +pub enum AskForApprovalToml { + #[serde(rename = "untrusted")] + UnlessTrusted, + OnFailure, + OnRequest, + Reject, + Never, +} + +impl AskForApprovalToml { + pub fn to_core(self) -> AskForApproval { + match self { + AskForApprovalToml::UnlessTrusted => AskForApproval::UnlessTrusted, + AskForApprovalToml::OnFailure => AskForApproval::OnFailure, + AskForApprovalToml::OnRequest => AskForApproval::OnRequest, + AskForApprovalToml::Reject => AskForApproval::reject_defaults(), + AskForApprovalToml::Never => AskForApproval::Never, + } + } +} + +impl From for AskForApprovalToml { + fn from(value: AskForApproval) -> Self { + match value { + AskForApproval::UnlessTrusted => AskForApprovalToml::UnlessTrusted, + AskForApproval::OnFailure => AskForApprovalToml::OnFailure, + AskForApproval::OnRequest => AskForApprovalToml::OnRequest, + AskForApproval::Reject { .. } => AskForApprovalToml::Reject, + AskForApproval::Never => AskForApprovalToml::Never, + } + } +} + +impl From for AskForApproval { + fn from(value: AskForApprovalToml) -> Self { + value.to_core() + } +} + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema)] #[schemars(deny_unknown_fields)] pub struct ProjectConfig { @@ -1571,7 +1613,7 @@ impl Config { || cfg.approval_policy.is_some(); let mut approval_policy = approval_policy_override .or(config_profile.approval_policy) - .or(cfg.approval_policy) + .or(cfg.approval_policy.map(Into::into)) .unwrap_or_else(|| { if active_project.is_trusted() { AskForApproval::OnRequest diff --git a/codex-rs/core/src/exec_policy.rs b/codex-rs/core/src/exec_policy.rs index 62ebdde43d..1a831bf53e 100644 --- a/codex-rs/core/src/exec_policy.rs +++ b/codex-rs/core/src/exec_policy.rs @@ -32,6 +32,10 @@ use shlex::try_join as shlex_try_join; const PROMPT_CONFLICT_REASON: &str = "approval required by policy, but AskForApproval is set to Never"; +const REJECT_SANDBOX_APPROVAL_REASON: &str = + "approval required by policy, but AskForApproval::Reject.sandbox_approval is set"; +const REJECT_RULES_APPROVAL_REASON: &str = + "approval required by policy rule, but AskForApproval::Reject.rules is set"; const RULES_DIR_NAME: &str = "rules"; const RULE_EXTENSION: &str = "rules"; const DEFAULT_POLICY_FILE: &str = "default.rules"; @@ -91,6 +95,30 @@ fn is_policy_match(rule_match: &RuleMatch) -> bool { } } +fn prompt_is_from_policy_rule(evaluation: &Evaluation) -> bool { + evaluation + .matched_rules + .iter() + .any(|rule_match| is_policy_match(rule_match) && rule_match.decision() == Decision::Prompt) +} + +fn prompt_is_rejected_by_policy( + approval_policy: AskForApproval, + prompt_is_rule: bool, +) -> Option<&'static str> { + match approval_policy { + AskForApproval::Never => Some(PROMPT_CONFLICT_REASON), + AskForApproval::Reject { rules: true, .. } if prompt_is_rule => { + Some(REJECT_RULES_APPROVAL_REASON) + } + AskForApproval::Reject { + sandbox_approval: true, + .. + } if !prompt_is_rule => Some(REJECT_SANDBOX_APPROVAL_REASON), + _ => None, + } +} + #[derive(Debug, Error)] pub enum ExecPolicyError { #[error("failed to read rules files from {dir}: {source}")] @@ -196,9 +224,11 @@ impl ExecPolicyManager { reason: derive_forbidden_reason(command, &evaluation), }, Decision::Prompt => { - if matches!(approval_policy, AskForApproval::Never) { + let prompt_is_rule = prompt_is_from_policy_rule(&evaluation); + if let Some(reason) = prompt_is_rejected_by_policy(approval_policy, prompt_is_rule) + { ExecApprovalRequirement::Forbidden { - reason: PROMPT_CONFLICT_REASON.to_string(), + reason: reason.to_string(), } } else { ExecApprovalRequirement::NeedsApproval { @@ -465,6 +495,20 @@ pub fn render_decision_for_unmatched_command( } } } + AskForApproval::Reject { .. } => match sandbox_policy { + SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. } => { + // Mirror on-request behavior for unmatched commands; prompt-vs-reject is handled + // by `prompt_is_rejected_by_policy`. + Decision::Allow + } + SandboxPolicy::ReadOnly { .. } | SandboxPolicy::WorkspaceWrite { .. } => { + if sandbox_permissions.requires_escalated_permissions() { + Decision::Prompt + } else { + Decision::Allow + } + } + }, } } diff --git a/codex-rs/core/src/mcp_connection_manager.rs b/codex-rs/core/src/mcp_connection_manager.rs index 589be7aac2..bbfaa145fd 100644 --- a/codex-rs/core/src/mcp_connection_manager.rs +++ b/codex-rs/core/src/mcp_connection_manager.rs @@ -28,6 +28,7 @@ use codex_async_utils::OrCancelExt; use codex_protocol::approvals::ElicitationRequestEvent; use codex_protocol::mcp::CallToolResult; use codex_protocol::mcp::RequestId as ProtocolRequestId; +use codex_protocol::protocol::AskForApproval; use codex_protocol::protocol::Event; use codex_protocol::protocol::EventMsg; use codex_protocol::protocol::McpStartupCompleteEvent; @@ -44,6 +45,7 @@ use futures::future::FutureExt; use futures::future::Shared; use rmcp::model::ClientCapabilities; use rmcp::model::CreateElicitationRequestParams; +use rmcp::model::ElicitationAction; use rmcp::model::ElicitationCapability; use rmcp::model::FormElicitationCapability; use rmcp::model::Implementation; @@ -71,6 +73,7 @@ use tracing::instrument; use tracing::warn; use crate::codex::INITIAL_SUBMIT_ID; +use crate::config::Constrained; use crate::config::types::McpServerConfig; use crate::config::types::McpServerTransportConfig; @@ -182,9 +185,19 @@ static CODEX_APPS_TOOLS_CACHE: LazyLock>> type ResponderMap = HashMap<(String, RequestId), oneshot::Sender>; -#[derive(Clone, Default)] +#[derive(Clone)] struct ElicitationRequestManager { requests: Arc>, + approval_policy: Arc>, +} + +impl Default for ElicitationRequestManager { + fn default() -> Self { + Self { + requests: Arc::new(Mutex::new(HashMap::new())), + approval_policy: Arc::new(StdMutex::new(AskForApproval::default())), + } + } } impl ElicitationRequestManager { @@ -205,11 +218,23 @@ impl ElicitationRequestManager { fn make_sender(&self, server_name: String, tx_event: Sender) -> SendElicitation { let elicitation_requests = self.requests.clone(); + let approval_policy = self.approval_policy.clone(); Box::new(move |id, elicitation| { let elicitation_requests = elicitation_requests.clone(); let tx_event = tx_event.clone(); let server_name = server_name.clone(); + let approval_policy = approval_policy.clone(); async move { + if approval_policy + .lock() + .is_ok_and(|policy| policy.rejects_mcp_elicitations()) + { + return Ok(ElicitationResponse { + action: ElicitationAction::Decline, + content: None, + }); + } + let (tx, rx) = oneshot::channel(); { let mut lock = elicitation_requests.lock().await; @@ -357,6 +382,12 @@ impl McpConnectionManager { !self.clients.is_empty() } + pub(crate) fn set_approval_policy(&self, approval_policy: &Constrained) { + if let Ok(mut policy) = self.elicitation_requests.approval_policy.lock() { + *policy = approval_policy.value(); + } + } + pub async fn initialize( &mut self, mcp_servers: &HashMap, @@ -371,7 +402,15 @@ impl McpConnectionManager { } let mut clients = HashMap::new(); let mut join_set = JoinSet::new(); + let approval_policy = self + .elicitation_requests + .approval_policy + .lock() + .map_or_else(|_| AskForApproval::default(), |policy| *policy); let elicitation_requests = ElicitationRequestManager::default(); + if let Ok(mut policy) = elicitation_requests.approval_policy.lock() { + *policy = approval_policy; + } let mcp_servers = mcp_servers.clone(); for (server_name, cfg) in mcp_servers.into_iter().filter(|(_, cfg)| cfg.enabled) { let cancel_token = cancel_token.child_token(); diff --git a/codex-rs/core/src/safety.rs b/codex-rs/core/src/safety.rs index b0d359b7e1..ce09e9fa0d 100644 --- a/codex-rs/core/src/safety.rs +++ b/codex-rs/core/src/safety.rs @@ -38,7 +38,10 @@ pub fn assess_patch_safety( } match policy { - AskForApproval::OnFailure | AskForApproval::Never | AskForApproval::OnRequest => { + AskForApproval::OnFailure + | AskForApproval::Never + | AskForApproval::OnRequest + | AskForApproval::Reject { .. } => { // Continue to see if this can be auto-approved. } // TODO(ragona): I'm not sure this is actually correct? I believe in this case @@ -52,7 +55,10 @@ pub fn assess_patch_safety( // possible that paths in the patch are hard links to files outside the // writable roots, so we should still run `apply_patch` in a sandbox in that case. if is_write_patch_constrained_to_writable_paths(action, sandbox_policy, cwd) - || policy == AskForApproval::OnFailure + || matches!( + policy, + AskForApproval::OnFailure | AskForApproval::Reject { .. } + ) { if matches!( sandbox_policy, @@ -75,7 +81,14 @@ pub fn assess_patch_safety( None => SafetyCheck::AskUser, } } - } else if policy == AskForApproval::Never { + } else if matches!( + policy, + AskForApproval::Never + | AskForApproval::Reject { + sandbox_approval: true, + .. + } + ) { SafetyCheck::Reject { reason: "writing outside of the project; rejected by user approval settings" .to_string(), diff --git a/codex-rs/core/src/tools/sandboxing.rs b/codex-rs/core/src/tools/sandboxing.rs index 04dc10c3e1..132b677aea 100644 --- a/codex-rs/core/src/tools/sandboxing.rs +++ b/codex-rs/core/src/tools/sandboxing.rs @@ -156,6 +156,8 @@ impl ExecApprovalRequirement { /// - Never, OnFailure: do not ask /// - OnRequest: ask unless sandbox policy is DangerFullAccess +/// - Reject: ask unless sandbox policy is DangerFullAccess, but auto-reject +/// when `sandbox_approval` rejection is enabled. /// - UnlessTrusted: always ask pub(crate) fn default_exec_approval_requirement( policy: AskForApproval, @@ -163,14 +165,18 @@ pub(crate) fn default_exec_approval_requirement( ) -> ExecApprovalRequirement { let needs_approval = match policy { AskForApproval::Never | AskForApproval::OnFailure => false, - AskForApproval::OnRequest => !matches!( + AskForApproval::OnRequest | AskForApproval::Reject { .. } => !matches!( sandbox_policy, SandboxPolicy::DangerFullAccess | SandboxPolicy::ExternalSandbox { .. } ), AskForApproval::UnlessTrusted => true, }; - if needs_approval { + if needs_approval && policy.rejects_sandbox_approval() { + ExecApprovalRequirement::Forbidden { + reason: "approval policy rejected sandbox approval prompt".to_string(), + } + } else if needs_approval { ExecApprovalRequirement::NeedsApproval { reason: None, proposed_execpolicy_amendment: None, @@ -224,7 +230,15 @@ pub(crate) trait Approvable { /// Decide we can request an approval for no-sandbox execution. fn wants_no_sandbox_approval(&self, policy: AskForApproval) -> bool { - !matches!(policy, AskForApproval::Never | AskForApproval::OnRequest) + match policy { + AskForApproval::OnFailure => true, + AskForApproval::UnlessTrusted => true, + AskForApproval::Never => false, + AskForApproval::OnRequest => false, + AskForApproval::Reject { + sandbox_approval, .. + } => !sandbox_approval, + } } fn start_approval_async<'a>( diff --git a/codex-rs/protocol/src/models.rs b/codex-rs/protocol/src/models.rs index 3a98aa5398..e1b5447811 100644 --- a/codex-rs/protocol/src/models.rs +++ b/codex-rs/protocol/src/models.rs @@ -255,6 +255,19 @@ impl DeveloperInstructions { None => APPROVAL_POLICY_ON_REQUEST_RULE.to_string(), } } + AskForApproval::Reject { + sandbox_approval, + rules, + mcp_elicitations, + } => { + format!( + "Approval policy is `reject`.\n\ + - `sandbox_approval`: {sandbox_approval}\n\ + - `rules`: {rules}\n\ + - `mcp_elicitations`: {mcp_elicitations}\n\ + When a category is `true`, requests in that category are auto-rejected instead of prompting the user." + ) + } }; DeveloperInstructions::new(text) diff --git a/codex-rs/protocol/src/protocol.rs b/codex-rs/protocol/src/protocol.rs index f9c56c5bc4..999c27699c 100644 --- a/codex-rs/protocol/src/protocol.rs +++ b/codex-rs/protocol/src/protocol.rs @@ -377,11 +377,60 @@ pub enum AskForApproval { #[default] OnRequest, + /// Fine-grained rejection controls for approval prompts. + /// + /// When a field is `true`, prompts of that category are automatically + /// rejected instead of shown to the user. + Reject { + /// Reject approval prompts related to sandbox escalation. + sandbox_approval: bool, + /// Reject prompts triggered by execpolicy `prompt` rules. + rules: bool, + /// Reject MCP elicitation prompts. + mcp_elicitations: bool, + }, + /// Never ask the user to approve commands. Failures are immediately returned /// to the model, and never escalated to the user for approval. Never, } +impl AskForApproval { + /// Backward-compatible defaults for `approval_policy = "reject"` in + /// `config.toml`. + pub const fn reject_defaults() -> Self { + Self::Reject { + sandbox_approval: true, + rules: false, + mcp_elicitations: false, + } + } + + pub const fn rejects_sandbox_approval(self) -> bool { + matches!( + self, + Self::Reject { + sandbox_approval: true, + .. + } + ) + } + + pub const fn rejects_rules_approval(self) -> bool { + matches!(self, Self::Reject { rules: true, .. }) + } + + pub const fn rejects_mcp_elicitations(self) -> bool { + matches!( + self, + Self::Reject { + mcp_elicitations: true, + .. + } + ) + } +} + /// Represents whether outbound network access is available to the agent. #[derive( Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Display, Default, JsonSchema, TS,