mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix codex harness service tiers (#79152)
This commit is contained in:
@@ -2135,8 +2135,8 @@ jobs:
|
||||
# inside the already-isolated container to keep MCP cron/tool
|
||||
# execution representative instead of failing on nested sandbox
|
||||
# setup.
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_ARGS=["exec","--json","--color","never","--sandbox","danger-full-access","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS=["exec","resume","{sessionId}","-c","sandbox_mode=\"danger-full-access\"","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_ARGS=["exec","--json","--color","never","--sandbox","danger-full-access","-c","service_tier=\"priority\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS=["exec","resume","{sessionId}","-c","sandbox_mode=\"danger-full-access\"","-c","service_tier=\"priority\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo "OPENCLAW_LIVE_CLI_BACKEND_DEBUG=1" >> "$GITHUB_ENV"
|
||||
echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
|
||||
echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
|
||||
@@ -2354,8 +2354,8 @@ jobs:
|
||||
live-cli-backend-docker)
|
||||
echo "OPENCLAW_LIVE_CLI_BACKEND_MODEL=codex-cli/gpt-5.4" >> "$GITHUB_ENV"
|
||||
echo "OPENCLAW_LIVE_CLI_BACKEND_AUTH=api-key" >> "$GITHUB_ENV"
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_ARGS=["exec","--json","--color","never","--sandbox","danger-full-access","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS=["exec","resume","{sessionId}","-c","sandbox_mode=\"danger-full-access\"","-c","service_tier=\"fast\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_ARGS=["exec","--json","--color","never","--sandbox","danger-full-access","-c","service_tier=\"priority\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo 'OPENCLAW_LIVE_CLI_BACKEND_RESUME_ARGS=["exec","resume","{sessionId}","-c","sandbox_mode=\"danger-full-access\"","-c","service_tier=\"priority\"","--skip-git-repo-check"]' >> "$GITHUB_ENV"
|
||||
echo "OPENCLAW_LIVE_CLI_BACKEND_DEBUG=1" >> "$GITHUB_ENV"
|
||||
echo "OPENCLAW_CLI_BACKEND_LOG_OUTPUT=1" >> "$GITHUB_ENV"
|
||||
echo "OPENCLAW_TEST_CONSOLE=1" >> "$GITHUB_ENV"
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Telegram: preserve the channel-specific 10-option poll cap in the unified outbound adapter so over-limit polls are rejected before send. (#78762) Thanks @obviyus.
|
||||
- Runtime/install: raise the supported Node 22 floor to `22.16+` so native SQLite query handling can rely on the `node:sqlite` statement metadata API while continuing to recommend Node 24. (#78921)
|
||||
- Discord/voice: include a bounded one-line STT transcript preview in verbose voice logs so live voice debugging shows what speakers said before the agent reply.
|
||||
- Codex app-server: pin the managed Codex harness and Codex CLI smoke package to `@openai/codex@0.129.0-alpha.15` and defer OpenClaw integration dynamic tools behind Codex tool search by default, saving roughly 5.5k upfront dynamic-tool tokens on source-reply Codex turns while keeping `codexDynamicToolsLoading: "direct"` as a compatibility escape hatch.
|
||||
- Codex app-server: pin the managed Codex harness and Codex CLI smoke package to `@openai/codex@0.129.0`, defer OpenClaw integration dynamic tools behind Codex tool search by default, and accept current Codex service-tier values so legacy `fast` settings survive the stable harness upgrade as `priority`.
|
||||
- Discord/voice: stream ElevenLabs TTS directly into Discord playback and send ElevenLabs latency optimization as the documented query parameter so spoken replies can start sooner.
|
||||
- Discord/voice: keep TTS playback running when another user starts speaking, ignore new capture during playback to avoid feedback loops, and downgrade expected receive-stream aborts to verbose diagnostics.
|
||||
- Telegram: treat successful same-chat `message` tool outbound sends during an inbound telegram turn as delivered when deciding whether to emit the rewritten silent reply fallback (#78685). Thanks @neeravmakwana.
|
||||
|
||||
@@ -498,7 +498,7 @@ To opt in to Codex guardian-reviewed approvals, set `appServer.mode:
|
||||
config: {
|
||||
appServer: {
|
||||
mode: "guardian",
|
||||
serviceTier: "fast",
|
||||
serviceTier: "priority",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -650,7 +650,7 @@ Supported `appServer` fields:
|
||||
| `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 `"auto_review"` to let Codex review native approval prompts. `guardian_subagent` remains a legacy alias. |
|
||||
| `serviceTier` | unset | Optional Codex app-server service tier: `"fast"`, `"flex"`, or `null`. Invalid legacy values are ignored. |
|
||||
| `serviceTier` | unset | Optional Codex app-server service tier. `"priority"` enables fast-mode routing, `"flex"` requests flex processing, `null` clears the override, and legacy `"fast"` is accepted as `"priority"`. |
|
||||
|
||||
OpenClaw-owned dynamic tool calls are bounded independently from
|
||||
`appServer.requestTimeoutMs`: each Codex `item/tool/call` request must receive
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
"type": "string",
|
||||
"enum": ["user", "auto_review", "guardian_subagent"]
|
||||
},
|
||||
"serviceTier": { "type": ["string", "null"], "enum": ["fast", "flex", null] },
|
||||
"serviceTier": { "type": ["string", "null"] },
|
||||
"defaultWorkspaceDir": {
|
||||
"type": "string"
|
||||
}
|
||||
@@ -363,7 +363,7 @@
|
||||
},
|
||||
"appServer.serviceTier": {
|
||||
"label": "Service Tier",
|
||||
"help": "Optional Codex app-server service tier. Use fast, flex, or null.",
|
||||
"help": "Optional Codex app-server service tier. Use priority, flex, or null. Legacy fast is accepted as priority.",
|
||||
"advanced": true
|
||||
},
|
||||
"appServer.defaultWorkspaceDir": {
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@mariozechner/pi-coding-agent": "0.73.0",
|
||||
"@openai/codex": "0.129.0-alpha.15",
|
||||
"@openai/codex": "0.129.0",
|
||||
"ajv": "^8.20.0",
|
||||
"ws": "^8.20.0"
|
||||
},
|
||||
|
||||
@@ -35,6 +35,7 @@ function threadStartResult(threadId = "thread-auth-contract") {
|
||||
return {
|
||||
thread: {
|
||||
id: threadId,
|
||||
sessionId: "session-1",
|
||||
forkedFromId: null,
|
||||
preview: "",
|
||||
ephemeral: false,
|
||||
|
||||
@@ -82,14 +82,14 @@ describe("Codex app-server config", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("drops invalid legacy service tiers without discarding the rest of the config", () => {
|
||||
it("normalizes legacy service tiers without discarding the rest of the config", () => {
|
||||
const runtime = resolveCodexAppServerRuntimeOptions({
|
||||
pluginConfig: {
|
||||
appServer: {
|
||||
mode: "guardian",
|
||||
approvalPolicy: "on-request",
|
||||
sandbox: "read-only",
|
||||
serviceTier: "priority",
|
||||
serviceTier: "fast",
|
||||
},
|
||||
},
|
||||
env: {},
|
||||
@@ -100,9 +100,22 @@ describe("Codex app-server config", () => {
|
||||
approvalPolicy: "on-request",
|
||||
sandbox: "read-only",
|
||||
approvalsReviewer: "auto_review",
|
||||
serviceTier: "priority",
|
||||
}),
|
||||
);
|
||||
expect(runtime).not.toHaveProperty("serviceTier");
|
||||
});
|
||||
|
||||
it("passes through non-empty Codex app-server service tiers for forward compatibility", () => {
|
||||
const runtime = resolveCodexAppServerRuntimeOptions({
|
||||
pluginConfig: {
|
||||
appServer: {
|
||||
serviceTier: "batch-preview",
|
||||
},
|
||||
},
|
||||
env: {},
|
||||
});
|
||||
|
||||
expect(runtime.serviceTier).toBe("batch-preview");
|
||||
});
|
||||
|
||||
it("rejects malformed plugin config instead of treating freeform strings as control values", () => {
|
||||
|
||||
@@ -188,8 +188,8 @@ const codexDynamicToolsProfileSchema = z.enum(["native-first", "openclaw-compat"
|
||||
const codexDynamicToolsLoadingSchema = z.enum(["searchable", "direct"]);
|
||||
const codexAppServerServiceTierSchema = z
|
||||
.preprocess(
|
||||
(value) => (value === null ? null : resolveServiceTier(value)),
|
||||
z.enum(["fast", "flex"]).nullable().optional(),
|
||||
(value) => (value === null ? null : normalizeCodexServiceTier(value)),
|
||||
z.string().trim().min(1).nullable().optional(),
|
||||
)
|
||||
.optional();
|
||||
|
||||
@@ -327,7 +327,7 @@ export function resolveCodexAppServerRuntimeOptions(
|
||||
resolvePolicyMode(config.mode) ??
|
||||
resolvePolicyMode(env.OPENCLAW_CODEX_APP_SERVER_MODE) ??
|
||||
"yolo";
|
||||
const serviceTier = resolveServiceTier(config.serviceTier);
|
||||
const serviceTier = normalizeCodexServiceTier(config.serviceTier);
|
||||
if (transport === "websocket" && !url) {
|
||||
throw new Error(
|
||||
"plugins.entries.codex.config.appServer.url is required when appServer.transport is websocket",
|
||||
@@ -523,8 +523,26 @@ function resolveApprovalsReviewer(value: unknown): CodexAppServerApprovalsReview
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function resolveServiceTier(value: unknown): CodexServiceTier | undefined {
|
||||
return value === "fast" || value === "flex" ? value : undefined;
|
||||
export function normalizeCodexServiceTier(value: unknown): CodexServiceTier | undefined {
|
||||
if (typeof value !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) {
|
||||
return undefined;
|
||||
}
|
||||
const normalized = trimmed.toLowerCase();
|
||||
if (normalized === "fast" || normalized === "priority") {
|
||||
return "priority";
|
||||
}
|
||||
if (normalized === "flex") {
|
||||
return "flex";
|
||||
}
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
export function isCodexFastServiceTier(value: unknown): boolean {
|
||||
return normalizeCodexServiceTier(value) === "priority";
|
||||
}
|
||||
|
||||
function normalizePositiveNumber(value: unknown, fallback: number): number {
|
||||
|
||||
+8
-14
@@ -83,13 +83,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -1273,13 +1269,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ServiceTier": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
]
|
||||
},
|
||||
"SessionSource": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -1429,6 +1418,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1513,6 +1503,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"description": "Origin of the thread (CLI, VSCode, codex exec, codex app-server, etc.).",
|
||||
"allOf": [
|
||||
|
||||
+8
-14
@@ -83,13 +83,9 @@
|
||||
]
|
||||
},
|
||||
"serviceTier": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ServiceTier"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
"type": [
|
||||
"string",
|
||||
"null"
|
||||
]
|
||||
},
|
||||
"thread": {
|
||||
@@ -1273,13 +1269,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"ServiceTier": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"fast",
|
||||
"flex"
|
||||
]
|
||||
},
|
||||
"SessionSource": {
|
||||
"oneOf": [
|
||||
{
|
||||
@@ -1429,6 +1418,7 @@
|
||||
"id",
|
||||
"modelProvider",
|
||||
"preview",
|
||||
"sessionId",
|
||||
"source",
|
||||
"status",
|
||||
"turns",
|
||||
@@ -1513,6 +1503,10 @@
|
||||
"description": "Usually the first user message in the thread, if available.",
|
||||
"type": "string"
|
||||
},
|
||||
"sessionId": {
|
||||
"description": "Session id shared by threads that belong to the same session tree.",
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"description": "Origin of the thread (CLI, VSCode, codex exec, codex app-server, etc.).",
|
||||
"allOf": [
|
||||
|
||||
@@ -140,6 +140,7 @@ export type CodexTurn = {
|
||||
|
||||
export type CodexThread = {
|
||||
id: string;
|
||||
sessionId?: string;
|
||||
name?: string | null;
|
||||
cwd?: string | null;
|
||||
};
|
||||
|
||||
@@ -67,6 +67,7 @@ function threadStartResult(threadId = "thread-1") {
|
||||
return {
|
||||
thread: {
|
||||
id: threadId,
|
||||
sessionId: "session-1",
|
||||
forkedFromId: null,
|
||||
preview: "",
|
||||
ephemeral: false,
|
||||
|
||||
@@ -87,6 +87,7 @@ function threadStartResult(threadId = "thread-1") {
|
||||
return {
|
||||
thread: {
|
||||
id: threadId,
|
||||
sessionId: "session-1",
|
||||
forkedFromId: null,
|
||||
preview: "",
|
||||
ephemeral: false,
|
||||
@@ -4006,7 +4007,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
approvalPolicy: "on-request",
|
||||
approvalsReviewer: "guardian_subagent",
|
||||
sandbox: "danger-full-access",
|
||||
serviceTier: "fast",
|
||||
serviceTier: "priority",
|
||||
developerInstructions: expect.stringContaining(CODEX_GPT5_BEHAVIOR_CONTRACT),
|
||||
persistExtendedHistory: true,
|
||||
});
|
||||
@@ -4018,7 +4019,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
approvalPolicy: "on-request",
|
||||
approvalsReviewer: "guardian_subagent",
|
||||
sandboxPolicy: { type: "dangerFullAccess" },
|
||||
serviceTier: "fast",
|
||||
serviceTier: "priority",
|
||||
model: "gpt-5.4-codex",
|
||||
}),
|
||||
},
|
||||
@@ -4026,7 +4027,7 @@ describe("runCodexAppServerAttempt", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("drops invalid legacy service tiers before app-server resume and turn requests", async () => {
|
||||
it("passes current Codex service tier request values through app-server resume and turn requests", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
const workspaceDir = path.join(tempDir, "workspace");
|
||||
await writeExistingBinding(sessionFile, workspaceDir, { model: "gpt-5.2" });
|
||||
@@ -4046,13 +4047,9 @@ describe("runCodexAppServerAttempt", () => {
|
||||
await run;
|
||||
|
||||
const resumeRequest = requests.find((request) => request.method === "thread/resume");
|
||||
expect(resumeRequest?.params).toEqual(
|
||||
expect.not.objectContaining({ serviceTier: expect.anything() }),
|
||||
);
|
||||
expect(resumeRequest?.params).toEqual(expect.objectContaining({ serviceTier: "priority" }));
|
||||
const turnRequest = requests.find((request) => request.method === "turn/start");
|
||||
expect(turnRequest?.params).toEqual(
|
||||
expect.not.objectContaining({ serviceTier: expect.anything() }),
|
||||
);
|
||||
expect(turnRequest?.params).toEqual(expect.objectContaining({ serviceTier: "priority" }));
|
||||
});
|
||||
|
||||
it("keys plugin app inventory by websocket credentials without exposing them", () => {
|
||||
|
||||
@@ -49,10 +49,11 @@ function createAppServerOptions(): Parameters<typeof startOrResumeThread>[0]["ap
|
||||
};
|
||||
}
|
||||
|
||||
function threadStartResult(threadId = "thread-1") {
|
||||
function threadStartResult(threadId = "thread-1", serviceTier: string | null = null) {
|
||||
return {
|
||||
thread: {
|
||||
id: threadId,
|
||||
sessionId: "session-1",
|
||||
forkedFromId: null,
|
||||
preview: "",
|
||||
ephemeral: false,
|
||||
@@ -72,7 +73,7 @@ function threadStartResult(threadId = "thread-1") {
|
||||
},
|
||||
model: "gpt-5.4",
|
||||
modelProvider: "openai",
|
||||
serviceTier: null,
|
||||
serviceTier,
|
||||
cwd: tempDir,
|
||||
instructionSources: [],
|
||||
approvalPolicy: "never",
|
||||
@@ -125,6 +126,27 @@ describe("Codex app-server dynamic tool schema boundary contract", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("accepts Codex app-server priority service tier responses", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
const workspaceDir = path.join(tempDir, "workspace");
|
||||
const request = vi.fn(async (method: string) => {
|
||||
if (method === "thread/start") {
|
||||
return threadStartResult("thread-priority", "priority");
|
||||
}
|
||||
throw new Error(`unexpected method: ${method}`);
|
||||
});
|
||||
|
||||
const binding = await startOrResumeThread({
|
||||
client: { request } as never,
|
||||
params: createParams(sessionFile, workspaceDir),
|
||||
cwd: workspaceDir,
|
||||
dynamicTools: [],
|
||||
appServer: createAppServerOptions(),
|
||||
});
|
||||
|
||||
expect(binding.threadId).toBe("thread-priority");
|
||||
});
|
||||
|
||||
it("treats dynamic tool schema changes as thread-fingerprint changes", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
const workspaceDir = path.join(tempDir, "workspace");
|
||||
|
||||
@@ -172,6 +172,26 @@ describe("codex app-server session binding", () => {
|
||||
expect(binding?.modelProvider).toBeUndefined();
|
||||
});
|
||||
|
||||
it("normalizes legacy fast service tier bindings to Codex priority", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.json");
|
||||
await fs.writeFile(
|
||||
resolveCodexAppServerBindingPath(sessionFile),
|
||||
`${JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
threadId: "thread-123",
|
||||
sessionFile,
|
||||
cwd: tempDir,
|
||||
serviceTier: "fast",
|
||||
createdAt: "2026-05-03T00:00:00.000Z",
|
||||
updatedAt: "2026-05-03T00:00:00.000Z",
|
||||
})}\n`,
|
||||
);
|
||||
|
||||
const binding = await readCodexAppServerBinding(sessionFile);
|
||||
|
||||
expect(binding?.serviceTier).toBe("priority");
|
||||
});
|
||||
|
||||
it("does not infer native Codex auth from the profile id prefix", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.json");
|
||||
await writeCodexAppServerBinding(
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/agent-runtime";
|
||||
import {
|
||||
CODEX_PLUGINS_MARKETPLACE_NAME,
|
||||
normalizeCodexServiceTier,
|
||||
type CodexAppServerApprovalPolicy,
|
||||
type CodexAppServerSandboxMode,
|
||||
} from "./config.js";
|
||||
@@ -311,5 +312,5 @@ function readSandboxMode(value: unknown): CodexAppServerSandboxMode | undefined
|
||||
}
|
||||
|
||||
function readServiceTier(value: unknown): CodexServiceTier | undefined {
|
||||
return value === "fast" || value === "flex" ? value : undefined;
|
||||
return normalizeCodexServiceTier(value);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export const MIN_CODEX_APP_SERVER_VERSION = "0.125.0";
|
||||
export const MANAGED_CODEX_APP_SERVER_PACKAGE = "@openai/codex";
|
||||
export const MANAGED_CODEX_APP_SERVER_PACKAGE_VERSION = "0.129.0-alpha.15";
|
||||
export const MANAGED_CODEX_APP_SERVER_PACKAGE_VERSION = "0.129.0";
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
readCodexComputerUseStatus,
|
||||
type CodexComputerUseSetupParams,
|
||||
} from "./app-server/computer-use.js";
|
||||
import type { CodexComputerUseConfig } from "./app-server/config.js";
|
||||
import { isCodexFastServiceTier, type CodexComputerUseConfig } from "./app-server/config.js";
|
||||
import { listAllCodexAppServerModels } from "./app-server/models.js";
|
||||
import { isJsonObject, type JsonValue } from "./app-server/protocol.js";
|
||||
import { rememberCodexRateLimits } from "./app-server/rate-limit-cache.js";
|
||||
@@ -447,7 +447,7 @@ async function describeConversationBinding(
|
||||
`- Thread: ${formatCodexDisplayText(threadBinding?.threadId ?? "unknown")}`,
|
||||
`- Workspace: ${formatCodexDisplayText(data.workspaceDir)}`,
|
||||
`- Model: ${formatCodexDisplayText(threadBinding?.model ?? "default")}`,
|
||||
`- Fast: ${threadBinding?.serviceTier === "fast" ? "on" : "off"}`,
|
||||
`- Fast: ${isCodexFastServiceTier(threadBinding?.serviceTier) ? "on" : "off"}`,
|
||||
`- Permissions: ${threadBinding ? formatPermissionsMode(threadBinding) : "default"}`,
|
||||
`- Active run: ${formatCodexDisplayText(active ? active.turnId : "none")}`,
|
||||
`- Session: ${formatCodexDisplayText(data.sessionFile)}`,
|
||||
|
||||
@@ -78,7 +78,7 @@ describe("codex conversation binding", () => {
|
||||
request: vi.fn(async (method: string, requestParams: Record<string, unknown>) => {
|
||||
requests.push({ method, params: requestParams });
|
||||
return {
|
||||
thread: { id: "thread-new", cwd: tempDir },
|
||||
thread: { id: "thread-new", sessionId: "session-1", cwd: tempDir },
|
||||
model: "gpt-5.4-mini",
|
||||
};
|
||||
}),
|
||||
@@ -138,7 +138,7 @@ describe("codex conversation binding", () => {
|
||||
request: vi.fn(async (method: string, requestParams: Record<string, unknown>) => {
|
||||
requests.push({ method, params: requestParams });
|
||||
return {
|
||||
thread: { id: "thread-new", cwd: tempDir },
|
||||
thread: { id: "thread-new", sessionId: "session-1", cwd: tempDir },
|
||||
model: "gpt-5.4-mini",
|
||||
modelProvider: "openai",
|
||||
};
|
||||
@@ -261,7 +261,7 @@ describe("codex conversation binding", () => {
|
||||
}
|
||||
if (method === "thread/start") {
|
||||
return {
|
||||
thread: { id: "thread-new", cwd: tempDir },
|
||||
thread: { id: "thread-new", sessionId: "session-1", cwd: tempDir },
|
||||
model: "gpt-5.4-mini",
|
||||
};
|
||||
}
|
||||
@@ -340,13 +340,13 @@ describe("codex conversation binding", () => {
|
||||
model: "gpt-5.4-mini",
|
||||
approvalPolicy: "on-request",
|
||||
sandbox: "workspace-write",
|
||||
serviceTier: "fast",
|
||||
serviceTier: "priority",
|
||||
});
|
||||
expect(requests[1]?.params).not.toHaveProperty("modelProvider");
|
||||
expect(requests[2]?.params).toMatchObject({
|
||||
threadId: "thread-new",
|
||||
approvalPolicy: "on-request",
|
||||
serviceTier: "fast",
|
||||
serviceTier: "priority",
|
||||
});
|
||||
const savedBinding = JSON.parse(
|
||||
await fs.readFile(`${sessionFile}.codex-app-server.json`, "utf8"),
|
||||
@@ -356,7 +356,7 @@ describe("codex conversation binding", () => {
|
||||
authProfileId: "work",
|
||||
approvalPolicy: "on-request",
|
||||
sandbox: "workspace-write",
|
||||
serviceTier: "fast",
|
||||
serviceTier: "priority",
|
||||
});
|
||||
expect(savedBinding).not.toHaveProperty("modelProvider");
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ describe("codex conversation controls", () => {
|
||||
|
||||
await expect(readCodexAppServerBinding(sessionFile)).resolves.toMatchObject({
|
||||
threadId: "thread-1",
|
||||
serviceTier: "fast",
|
||||
serviceTier: "priority",
|
||||
approvalPolicy: "on-request",
|
||||
sandbox: "workspace-write",
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CODEX_CONTROL_METHODS } from "./app-server/capabilities.js";
|
||||
import {
|
||||
isCodexFastServiceTier,
|
||||
resolveCodexAppServerRuntimeOptions,
|
||||
type CodexAppServerApprovalPolicy,
|
||||
type CodexAppServerSandboxMode,
|
||||
@@ -139,9 +140,9 @@ export async function setCodexConversationFastMode(params: {
|
||||
}): Promise<string> {
|
||||
const binding = await requireThreadBinding(params.sessionFile);
|
||||
if (params.enabled == null) {
|
||||
return `Codex fast mode: ${binding.serviceTier === "fast" ? "on" : "off"}.`;
|
||||
return `Codex fast mode: ${isCodexFastServiceTier(binding.serviceTier) ? "on" : "off"}.`;
|
||||
}
|
||||
const serviceTier: CodexServiceTier = params.enabled ? "fast" : "flex";
|
||||
const serviceTier: CodexServiceTier = params.enabled ? "priority" : "flex";
|
||||
// Fast mode is sent on each later turn; do not require Codex to accept an
|
||||
// immediate thread/resume control request just to persist the preference.
|
||||
await writeCodexAppServerBinding(params.sessionFile, {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
} from "openclaw/plugin-sdk/cli-backend";
|
||||
|
||||
const CODEX_CLI_DEFAULT_MODEL_REF = "codex-cli/gpt-5.5";
|
||||
const CODEX_CLI_NPM_PACKAGE = "@openai/codex@0.129.0-alpha.15";
|
||||
const CODEX_CLI_NPM_PACKAGE = "@openai/codex@0.129.0";
|
||||
|
||||
export function buildOpenAICodexCliBackend(): CliBackendPlugin {
|
||||
return {
|
||||
@@ -32,7 +32,7 @@ export function buildOpenAICodexCliBackend(): CliBackendPlugin {
|
||||
"--sandbox",
|
||||
"workspace-write",
|
||||
"-c",
|
||||
'service_tier="fast"',
|
||||
'service_tier="priority"',
|
||||
"--skip-git-repo-check",
|
||||
],
|
||||
resumeArgs: [
|
||||
@@ -42,7 +42,7 @@ export function buildOpenAICodexCliBackend(): CliBackendPlugin {
|
||||
"-c",
|
||||
'sandbox_mode="workspace-write"',
|
||||
"-c",
|
||||
'service_tier="fast"',
|
||||
'service_tier="priority"',
|
||||
"--skip-git-repo-check",
|
||||
],
|
||||
output: "jsonl",
|
||||
|
||||
Generated
+29
-29
@@ -496,8 +496,8 @@ importers:
|
||||
specifier: 0.73.0
|
||||
version: 0.73.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(ws@8.20.0)(zod@4.4.3)
|
||||
'@openai/codex':
|
||||
specifier: 0.129.0-alpha.15
|
||||
version: 0.129.0-alpha.15
|
||||
specifier: 0.129.0
|
||||
version: 0.129.0
|
||||
ajv:
|
||||
specifier: ^8.20.0
|
||||
version: 8.20.0
|
||||
@@ -3198,43 +3198,43 @@ packages:
|
||||
resolution: {integrity: sha512-tlc/FcYIv5i8RYsl2iDil4A0gOihaas1R5jPcIC4Zw3GhjKsVilw90aHcVlhZPTBLGBzd379S+VcnsDjd9ChiA==}
|
||||
engines: {node: '>=12.4.0'}
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15':
|
||||
resolution: {integrity: sha512-OQLHP6rjcINfe/L0N/u9q/f0XhbV4JmzgWeEgks03gLQZuI/G0CPO2gVfJk27Eg8UEhEdz0YyeIuPCZP293XDg==}
|
||||
'@openai/codex@0.129.0':
|
||||
resolution: {integrity: sha512-8zZlcO4ploUzULJ3xT5qx8eOCL/L7gOrpWXCtr2kP568idZjWhbz3L2WE8BvjBDUF17WMDhjOklCj6DGd1cKfQ==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-darwin-arm64':
|
||||
resolution: {integrity: sha512-w4hHyBuasNrewr1cNRUcwWWXgTrLPYCtFJl+YvpADdgFw0iA1xlymRASfCf5BCkKdonW427tL0pD/jYBkOJnsQ==}
|
||||
'@openai/codex@0.129.0-darwin-arm64':
|
||||
resolution: {integrity: sha512-tVFwzbh612oip/yZMeQziMtUWLz08A8ChhS6U/bNZjCKWD11bQvDZjxZJNzhWvmom/gKeXstwoUp9u1S8eCcnA==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-darwin-x64':
|
||||
resolution: {integrity: sha512-G35Mr4pxUm9Lqe88uycW8dlGNW0SDu+/oQSvlYFYfNeLAjlmLPZ1hpraQoLMiQHc649F9SA+mEtSNfkKs+jB4A==}
|
||||
'@openai/codex@0.129.0-darwin-x64':
|
||||
resolution: {integrity: sha512-BtGc4ujzxRVIB0DcpiehP7/aQeAGEi0pNd9C98rtIqy1OBMwhOZ3ri/achzP0lxw8LWWFp8sL+hQdTGze6SGwg==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-linux-arm64':
|
||||
resolution: {integrity: sha512-HXFTHxj51vZtBgtsO7RL6v/nbB3K+Hkp71pJqgWR3qGsY00nNeM40bx1e0P0SS6VkCBJEHVE6i3y9yaIFhZMtg==}
|
||||
'@openai/codex@0.129.0-linux-arm64':
|
||||
resolution: {integrity: sha512-VnjI4Xla4uwaAqYCekwBm4dlucvaduTdhVr3bqU+6qfG5N9yn1bR7ZS7xMRlaRgS0oIst9fgYyC2niSYPOzuDA==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-linux-x64':
|
||||
resolution: {integrity: sha512-0UNw7e+BW5gXNsdg7Y/hoim9rrAL+bsKXGUXODsX+aPYRBpLOZT/SDlj/a3wvXk4uzxQ2OQWZqmk3E/VNNo/4g==}
|
||||
'@openai/codex@0.129.0-linux-x64':
|
||||
resolution: {integrity: sha512-YwkJtcHXeXdI+cfdv7qKGfafwePEEbSCRL5Z++/8djnI+iBj6nIMz4ouhe12yvsMccVqNTtCH8H0QrygHARpNg==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-win32-arm64':
|
||||
resolution: {integrity: sha512-d5TedgG1pGYji26EZt2dAaPbpdgp3DSjIheEG84lzNcMyW2kma0Q2YK+PnQo0d+SVgRszdLHluBSQQaKRfdsNw==}
|
||||
'@openai/codex@0.129.0-win32-arm64':
|
||||
resolution: {integrity: sha512-8rwpYBKg/vI3IHZB2ggFmIDz+4slG7mfYTFoQtRw2m2KMS1g1XMOJK9heM80NMiCY3hqmyMN81bOQ7aKAmgFLg==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-win32-x64':
|
||||
resolution: {integrity: sha512-LtZZBiqyhC2q5PYZEiKuyp9wNO4vck93krBTwqp5/nSMTRAkDRgGpjMVWG1Fz7iJLuy9IbQwVncrkd3hWhGZig==}
|
||||
'@openai/codex@0.129.0-win32-x64':
|
||||
resolution: {integrity: sha512-yP59c7O3J8zZ/eyN6HXMeeZ2xksJE8/Xy9kn3qznC7jCN3GEtM7B6Wv4gEY5F/jzik+B+tU71rmkGmqzQjfVVQ==}
|
||||
engines: {node: '>=16'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -10015,31 +10015,31 @@ snapshots:
|
||||
|
||||
'@nolyfill/domexception@1.0.28': {}
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15':
|
||||
'@openai/codex@0.129.0':
|
||||
optionalDependencies:
|
||||
'@openai/codex-darwin-arm64': '@openai/codex@0.129.0-alpha.15-darwin-arm64'
|
||||
'@openai/codex-darwin-x64': '@openai/codex@0.129.0-alpha.15-darwin-x64'
|
||||
'@openai/codex-linux-arm64': '@openai/codex@0.129.0-alpha.15-linux-arm64'
|
||||
'@openai/codex-linux-x64': '@openai/codex@0.129.0-alpha.15-linux-x64'
|
||||
'@openai/codex-win32-arm64': '@openai/codex@0.129.0-alpha.15-win32-arm64'
|
||||
'@openai/codex-win32-x64': '@openai/codex@0.129.0-alpha.15-win32-x64'
|
||||
'@openai/codex-darwin-arm64': '@openai/codex@0.129.0-darwin-arm64'
|
||||
'@openai/codex-darwin-x64': '@openai/codex@0.129.0-darwin-x64'
|
||||
'@openai/codex-linux-arm64': '@openai/codex@0.129.0-linux-arm64'
|
||||
'@openai/codex-linux-x64': '@openai/codex@0.129.0-linux-x64'
|
||||
'@openai/codex-win32-arm64': '@openai/codex@0.129.0-win32-arm64'
|
||||
'@openai/codex-win32-x64': '@openai/codex@0.129.0-win32-x64'
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-darwin-arm64':
|
||||
'@openai/codex@0.129.0-darwin-arm64':
|
||||
optional: true
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-darwin-x64':
|
||||
'@openai/codex@0.129.0-darwin-x64':
|
||||
optional: true
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-linux-arm64':
|
||||
'@openai/codex@0.129.0-linux-arm64':
|
||||
optional: true
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-linux-x64':
|
||||
'@openai/codex@0.129.0-linux-x64':
|
||||
optional: true
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-win32-arm64':
|
||||
'@openai/codex@0.129.0-win32-arm64':
|
||||
optional: true
|
||||
|
||||
'@openai/codex@0.129.0-alpha.15-win32-x64':
|
||||
'@openai/codex@0.129.0-win32-x64':
|
||||
optional: true
|
||||
|
||||
'@openclaw/fs-safe@https://codeload.github.com/openclaw/fs-safe/tar.gz/c7ccb99d3058f2acf2ad2758ad2470c7e113a53c':
|
||||
|
||||
@@ -54,7 +54,7 @@ const checks: Array<{ file: string; snippets: string[] }> = [
|
||||
file: "v2/TurnStartParams.ts",
|
||||
snippets: [
|
||||
"permissions?: PermissionProfileSelectionParams | null",
|
||||
"serviceTier?: ServiceTier | null",
|
||||
"serviceTier?: string | null",
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -208,7 +208,7 @@ func runCodexExecPrompt(ctx context.Context, req codexPromptRequest) (string, er
|
||||
"exec",
|
||||
"--model", req.Model,
|
||||
"-c", fmt.Sprintf("model_reasoning_effort=%q", normalizeThinking(req.Thinking)),
|
||||
"-c", `service_tier="fast"`,
|
||||
"-c", `service_tier="priority"`,
|
||||
"--sandbox", "read-only",
|
||||
"--ignore-rules",
|
||||
"--skip-git-repo-check",
|
||||
|
||||
@@ -183,7 +183,7 @@ while [ "$#" -gt 0 ]; do
|
||||
model_reasoning_effort=\"high\")
|
||||
saw_effort=1
|
||||
;;
|
||||
service_tier=\"fast\")
|
||||
service_tier=\"priority\")
|
||||
saw_service=1
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -420,7 +420,7 @@ if [ "$provider" = "codex-cli" ] && [ "${OPENCLAW_LIVE_CLI_BACKEND_AUTH:-auto}"
|
||||
--sandbox \
|
||||
danger-full-access \
|
||||
-c \
|
||||
'service_tier="fast"' \
|
||||
'service_tier="priority"' \
|
||||
--skip-git-repo-check \
|
||||
--model \
|
||||
"$codex_probe_model" \
|
||||
|
||||
@@ -67,7 +67,7 @@ function createBackendEntry(params: {
|
||||
params.id === "claude-cli"
|
||||
? "@anthropic-ai/claude-code"
|
||||
: params.id === "codex-cli"
|
||||
? "@openai/codex@0.129.0-alpha.15"
|
||||
? "@openai/codex@0.129.0"
|
||||
: params.id === "google-gemini-cli"
|
||||
? "@google/gemini-cli"
|
||||
: undefined,
|
||||
@@ -290,7 +290,7 @@ beforeEach(() => {
|
||||
"--sandbox",
|
||||
"workspace-write",
|
||||
"-c",
|
||||
'service_tier="fast"',
|
||||
'service_tier="priority"',
|
||||
"--skip-git-repo-check",
|
||||
],
|
||||
resumeArgs: [
|
||||
@@ -300,7 +300,7 @@ beforeEach(() => {
|
||||
"-c",
|
||||
'sandbox_mode="workspace-write"',
|
||||
"-c",
|
||||
'service_tier="fast"',
|
||||
'service_tier="priority"',
|
||||
"--skip-git-repo-check",
|
||||
],
|
||||
systemPromptFileConfigArg: "-c",
|
||||
@@ -388,7 +388,7 @@ describe("resolveCliBackendConfig reliability merge", () => {
|
||||
"--sandbox",
|
||||
"workspace-write",
|
||||
"-c",
|
||||
'service_tier="fast"',
|
||||
'service_tier="priority"',
|
||||
"--skip-git-repo-check",
|
||||
]);
|
||||
expect(resolved?.config.resumeArgs).toEqual([
|
||||
@@ -398,7 +398,7 @@ describe("resolveCliBackendConfig reliability merge", () => {
|
||||
"-c",
|
||||
'sandbox_mode="workspace-write"',
|
||||
"-c",
|
||||
'service_tier="fast"',
|
||||
'service_tier="priority"',
|
||||
"--skip-git-repo-check",
|
||||
]);
|
||||
});
|
||||
@@ -493,7 +493,7 @@ describe("resolveCliBackendLiveTest", () => {
|
||||
defaultModelRef: "codex-cli/gpt-5.5",
|
||||
defaultImageProbe: true,
|
||||
defaultMcpProbe: true,
|
||||
dockerNpmPackage: "@openai/codex@0.129.0-alpha.15",
|
||||
dockerNpmPackage: "@openai/codex@0.129.0",
|
||||
dockerBinaryName: "codex",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -361,7 +361,7 @@ describe("package artifact reuse", () => {
|
||||
expect(workflow).toContain("OPENCLAW_LIVE_CLI_BACKEND_MODEL=codex-cli/gpt-5.4");
|
||||
expect(workflow).toContain("OPENCLAW_LIVE_CLI_BACKEND_AUTH=api-key");
|
||||
expect(workflow).toContain("OPENCLAW_LIVE_CLI_BACKEND_USE_CI_SAFE_CODEX_CONFIG=1");
|
||||
expect((workflow.match(/service_tier=\\"fast\\"/g) ?? []).length).toBeGreaterThanOrEqual(2);
|
||||
expect((workflow.match(/service_tier=\\"priority\\"/g) ?? []).length).toBeGreaterThanOrEqual(2);
|
||||
expect(workflow).not.toContain(
|
||||
'OPENCLAW_LIVE_CLI_BACKEND_ARGS=["exec","--json","--color","never","--sandbox","danger-full-access","--skip-git-repo-check"]',
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user