fix(codex): unchain app-server defaults (#70082)

This commit is contained in:
pashpashpash
2026-04-22 01:53:49 -07:00
committed by GitHub
parent 43a941b51c
commit abf940db61
6 changed files with 20 additions and 14 deletions

View File

@@ -19,6 +19,7 @@ Docs: https://docs.openclaw.ai
### Fixes
- Gateway/pairing webchat: render `/pair qr` replies as structured media instead of raw markdown text, preserve inline reply threading and silent-control handling on media replies, avoid persisting sensitive QR images into transcript history, and keep local webchat media embedding behind internal-only trust markers. (#70047) Thanks @BunsDev.
- Codex harness: default app-server runs to unchained local execution, so OpenAI heartbeats can use network and shell tools without stalling behind native Codex approvals or the workspace-write sandbox.
- OpenAI/Responses: keep embedded OpenAI Responses runs on HTTP when `models.providers.openai.baseUrl` points at a local mock or other non-public endpoint, so mocked/custom endpoints no longer drift onto the hardcoded public websocket transport. (#69815) Thanks @vincentkoc.
- Channels/config: require resolved runtime config on channel send/action/client helpers and block runtime helper `loadConfig()` calls, so SecretRefs are resolved at startup/boundaries instead of being re-read during sends.
- CLI/channels: preserve bundled setup promotion metadata when a loaded partial channel plugin omits it, so adding a non-default account still moves legacy single-account fields such as Telegram `streaming` into `accounts.default`.

View File

@@ -263,9 +263,12 @@ By default, the plugin starts Codex locally with:
codex app-server --listen stdio://
```
By default, OpenClaw asks Codex to request native approvals. You can tune that
policy further, for example by tightening it and routing reviews through the
guardian:
By default, OpenClaw starts local Codex harness sessions fully unchained:
`approvalPolicy: "never"` and `sandbox: "danger-full-access"`. That matches the
trusted local operator posture used by the Codex CLI and lets autonomous
heartbeats use network and shell tools without waiting on an invisible native
approval path. You can tighten that policy, for example by routing reviews
through the guardian:
```json5
{
@@ -320,8 +323,8 @@ Supported `appServer` fields:
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
| `approvalPolicy` | `"on-request"` | Native Codex approval policy sent to thread start/resume/turn. |
| `sandbox` | `"workspace-write"` | Native Codex sandbox mode sent to thread start/resume. |
| `approvalPolicy` | `"never"` | Native Codex approval policy sent to thread start/resume/turn. |
| `sandbox` | `"danger-full-access"` | Native Codex sandbox mode sent to thread start/resume. |
| `approvalsReviewer` | `"user"` | Use `"guardian_subagent"` to let Codex guardian review native approvals. |
| `serviceTier` | unset | Optional Codex service tier, for example `"priority"`. |

View File

@@ -66,12 +66,12 @@
"approvalPolicy": {
"type": "string",
"enum": ["never", "on-request", "on-failure", "untrusted"],
"default": "on-request"
"default": "never"
},
"sandbox": {
"type": "string",
"enum": ["read-only", "workspace-write", "danger-full-access"],
"default": "workspace-write"
"default": "danger-full-access"
},
"approvalsReviewer": {
"type": "string",

View File

@@ -60,7 +60,7 @@ describe("Codex app-server config", () => {
).toThrow("appServer.url is required");
});
it("defaults native Codex approvals to on-request", () => {
it("defaults native Codex approvals to unchained local execution", () => {
const runtime = resolveCodexAppServerRuntimeOptions({
pluginConfig: {},
env: {},
@@ -68,8 +68,8 @@ describe("Codex app-server config", () => {
expect(runtime).toEqual(
expect.objectContaining({
approvalPolicy: "on-request",
sandbox: "workspace-write",
approvalPolicy: "never",
sandbox: "danger-full-access",
approvalsReviewer: "user",
}),
);

View File

@@ -136,11 +136,11 @@ export function resolveCodexAppServerRuntimeOptions(
approvalPolicy:
resolveApprovalPolicy(config.approvalPolicy) ??
resolveApprovalPolicy(env.OPENCLAW_CODEX_APP_SERVER_APPROVAL_POLICY) ??
"on-request",
"never",
sandbox:
resolveSandbox(config.sandbox) ??
resolveSandbox(env.OPENCLAW_CODEX_APP_SERVER_SANDBOX) ??
"workspace-write",
"danger-full-access",
approvalsReviewer:
resolveApprovalsReviewer(config.approvalsReviewer) ??
(env.OPENCLAW_CODEX_APP_SERVER_GUARDIAN === "1" ? "guardian_subagent" : "user"),

View File

@@ -188,6 +188,8 @@ describe("runCodexAppServerAttempt", () => {
params: expect.objectContaining({
model: "gpt-5.4-codex",
modelProvider: "openai",
approvalPolicy: "never",
sandbox: "danger-full-access",
}),
},
{
@@ -435,9 +437,9 @@ describe("runCodexAppServerAttempt", () => {
threadId: "thread-existing",
model: "gpt-5.4-codex",
modelProvider: "openai",
approvalPolicy: "on-request",
approvalPolicy: "never",
approvalsReviewer: "user",
sandbox: "workspace-write",
sandbox: "danger-full-access",
persistExtendedHistory: true,
});
});