Update Codex CLI 0.137.0 compatibility

This commit is contained in:
murashit 2026-06-04 11:54:53 +09:00
parent 2e5da6b706
commit 2598ee1327
52 changed files with 171 additions and 28 deletions

View file

@ -74,7 +74,7 @@ Codex Panel acts as a local Obsidian client for Codex App Server:
| Key | Version | Policy |
| ------------------------ | --------- | ---------------------------------------------------------- |
| `obsidian.minAppVersion` | `1.12.0` | Track the latest patch for this Obsidian minor. |
| `codex.testedCliVersion` | `0.136.0` | Track app-server compatibility by Codex CLI minor version. |
| `codex.testedCliVersion` | `0.137.0` | Track app-server compatibility by Codex CLI minor version. |
Codex Panel depends on the experimental `codex app-server` API.

View file

@ -177,6 +177,7 @@ export function approvalDetails(approval: PendingApproval): { key: string; value
break;
case "item/permissions/requestApproval":
addOptional(rows, "cwd", approval.params.cwd);
addOptional(rows, "environment", approval.params.environmentId);
rows.push(...permissionRows(approval.params.permissions));
break;
}

File diff suppressed because one or more lines are too long

View file

@ -3,4 +3,11 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RateLimitSnapshot } from "./RateLimitSnapshot";
/**
* Sparse rolling rate-limit update.
*
* Clients should merge available values into the most recent `account/rateLimits/read` response
* or refetch that snapshot. Nullable account metadata may be unavailable in a rolling update and
* does not clear a previously observed value.
*/
export type AccountRateLimitsUpdatedNotification = { rateLimits: RateLimitSnapshot, };

View file

@ -3,6 +3,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { AppToolApproval } from "./AppToolApproval";
import type { AppToolsConfig } from "./AppToolsConfig";
import type { ApprovalsReviewer } from "./ApprovalsReviewer";
import type { AppsDefaultConfig } from "./AppsDefaultConfig";
export type AppsConfig = { _default: AppsDefaultConfig | null, } & ({ [key in string]?: { enabled: boolean, destructive_enabled: boolean | null, open_world_enabled: boolean | null, default_tools_approval_mode: AppToolApproval | null, default_tools_enabled: boolean | null, tools: AppToolsConfig | null, } });
export type AppsConfig = { _default: AppsDefaultConfig | null, } & ({ [key in string]?: { enabled: boolean, approvals_reviewer: ApprovalsReviewer | null, destructive_enabled: boolean | null, open_world_enabled: boolean | null, default_tools_approval_mode: AppToolApproval | null, default_tools_enabled: boolean | null, tools: AppToolsConfig | null, } });

View file

@ -8,7 +8,17 @@ export type ConfigLayerSource = { "type": "mdm", domain: string, key: string, }
* This is the path to the system config.toml file, though it is not
* guaranteed to exist.
*/
file: AbsolutePathBuf, } | { "type": "user",
file: AbsolutePathBuf, } | { "type": "enterpriseManaged",
/**
* Stable identifier for the delivered layer.
*/
id: string,
/**
* Admin-facing name for the delivered layer. This is surfaced in
* diagnostics so users know which cloud layer needs administrator
* attention.
*/
name: string, } | { "type": "user",
/**
* This is the path to the user's config.toml file, though it is not
* guaranteed to exist.

View file

@ -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 HookSource = "system" | "user" | "project" | "mdm" | "sessionFlags" | "plugin" | "cloudRequirements" | "legacyManagedConfigFile" | "legacyManagedConfigMdm" | "unknown";
export type HookSource = "system" | "user" | "project" | "mdm" | "sessionFlags" | "plugin" | "cloudRequirements" | "cloudManagedConfig" | "legacyManagedConfigFile" | "legacyManagedConfigMdm" | "unknown";

View file

@ -4,7 +4,7 @@
import type { AbsolutePathBuf } from "../AbsolutePathBuf";
import type { RequestPermissionProfile } from "./RequestPermissionProfile";
export type PermissionsRequestApprovalParams = { threadId: string, turnId: string, itemId: string,
export type PermissionsRequestApprovalParams = { threadId: string, turnId: string, itemId: string, environmentId: string | null,
/**
* Unix timestamp (in milliseconds) when this approval request started.
*/

View file

@ -5,5 +5,6 @@ import type { PlanType } from "../PlanType";
import type { CreditsSnapshot } from "./CreditsSnapshot";
import type { RateLimitReachedType } from "./RateLimitReachedType";
import type { RateLimitWindow } from "./RateLimitWindow";
import type { SpendControlLimitSnapshot } from "./SpendControlLimitSnapshot";
export type RateLimitSnapshot = { limitId: string | null, limitName: string | null, primary: RateLimitWindow | null, secondary: RateLimitWindow | null, credits: CreditsSnapshot | null, planType: PlanType | null, rateLimitReachedType: RateLimitReachedType | null, };
export type RateLimitSnapshot = { limitId: string | null, limitName: string | null, primary: RateLimitWindow | null, secondary: RateLimitWindow | null, credits: CreditsSnapshot | null, individualLimit: SpendControlLimitSnapshot | null, planType: PlanType | null, rateLimitReachedType: RateLimitReachedType | null, };

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RemoteControlClient = { clientId: string, displayName: string | null, deviceType: string | null, platform: string | null, osVersion: string | null, deviceModel: string | null, appVersion: string | null, lastSeenAt: bigint | null, };

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RemoteControlClientsListOrder = "asc" | "desc";

View file

@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RemoteControlClientsListOrder } from "./RemoteControlClientsListOrder";
export type RemoteControlClientsListParams = { environmentId: string, cursor?: string | null, limit?: number | null, order?: RemoteControlClientsListOrder | null, };

View file

@ -0,0 +1,6 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { RemoteControlClient } from "./RemoteControlClient";
export type RemoteControlClientsListResponse = { data: Array<RemoteControlClient>, nextCursor: string | null, };

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RemoteControlClientsRevokeParams = { environmentId: string, clientId: string, };

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RemoteControlClientsRevokeResponse = Record<string, never>;

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RemoteControlPairingStartParams = { manualCode?: boolean, };

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type RemoteControlPairingStartResponse = { pairingCode: string, manualPairingCode: string | null, environmentId: string, expiresAt: bigint, };

View file

@ -0,0 +1,5 @@
// GENERATED CODE! DO NOT MODIFY BY HAND!
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
export type SpendControlLimitSnapshot = { limit: string, used: string, remainingPercent: number, resetsAt: number, };

View file

@ -17,6 +17,10 @@ sessionId: string,
* Source thread id when this thread was created by forking another thread.
*/
forkedFromId: string | null,
/**
* The ID of the parent thread. This will only be set if this thread is a subagent.
*/
parentThreadId: string | null,
/**
* Usually the first user message in the thread, if available.
*/

View file

@ -52,10 +52,4 @@ threadSource?: ThreadSource | null,
* populating `thread.turns`. This is useful when the client plans to call
* `thread/turns/list` immediately after forking.
*/
excludeTurns?: boolean,
/**
* Deprecated and ignored by app-server. Kept only so older clients can
* continue sending the field while rollout persistence always uses the
* limited history policy.
*/
persistExtendedHistory?: boolean, };
excludeTurns?: boolean, };

View file

@ -69,10 +69,4 @@ excludeTurns?: boolean,
* When present, include a `thread/turns/list` page in the resume response
* so clients can bootstrap recent turns without a second request.
*/
initialTurnsPage?: ThreadResumeInitialTurnsPageParams | null,
/**
* Deprecated and ignored by app-server. Kept only so older clients can
* continue sending the field while rollout persistence always uses the
* limited history policy.
*/
persistExtendedHistory?: boolean, };
initialTurnsPage?: ThreadResumeInitialTurnsPageParams | null, };

View file

@ -49,10 +49,4 @@ mockExperimentalField?: string | null,
* If true, opt into emitting raw Responses API items on the event stream.
* This is for internal use only (e.g. Codex Cloud).
*/
experimentalRawEvents?: boolean,
/**
* Deprecated and ignored by app-server. Kept only so older clients can
* continue sending the field while rollout persistence always uses the
* limited history policy.
*/
persistExtendedHistory?: boolean, };
experimentalRawEvents?: boolean, };

View file

@ -333,9 +333,17 @@ export type { ReasoningEffortOption } from "./ReasoningEffortOption";
export type { ReasoningSummaryPartAddedNotification } from "./ReasoningSummaryPartAddedNotification";
export type { ReasoningSummaryTextDeltaNotification } from "./ReasoningSummaryTextDeltaNotification";
export type { ReasoningTextDeltaNotification } from "./ReasoningTextDeltaNotification";
export type { RemoteControlClient } from "./RemoteControlClient";
export type { RemoteControlClientsListOrder } from "./RemoteControlClientsListOrder";
export type { RemoteControlClientsListParams } from "./RemoteControlClientsListParams";
export type { RemoteControlClientsListResponse } from "./RemoteControlClientsListResponse";
export type { RemoteControlClientsRevokeParams } from "./RemoteControlClientsRevokeParams";
export type { RemoteControlClientsRevokeResponse } from "./RemoteControlClientsRevokeResponse";
export type { RemoteControlConnectionStatus } from "./RemoteControlConnectionStatus";
export type { RemoteControlDisableResponse } from "./RemoteControlDisableResponse";
export type { RemoteControlEnableResponse } from "./RemoteControlEnableResponse";
export type { RemoteControlPairingStartParams } from "./RemoteControlPairingStartParams";
export type { RemoteControlPairingStartResponse } from "./RemoteControlPairingStartResponse";
export type { RemoteControlStatusChangedNotification } from "./RemoteControlStatusChangedNotification";
export type { RemoteControlStatusReadResponse } from "./RemoteControlStatusReadResponse";
export type { RequestPermissionProfile } from "./RequestPermissionProfile";
@ -368,6 +376,7 @@ export type { SkillsListEntry } from "./SkillsListEntry";
export type { SkillsListParams } from "./SkillsListParams";
export type { SkillsListResponse } from "./SkillsListResponse";
export type { SortDirection } from "./SortDirection";
export type { SpendControlLimitSnapshot } from "./SpendControlLimitSnapshot";
export type { SubagentMigration } from "./SubagentMigration";
export type { TerminalInteractionNotification } from "./TerminalInteractionNotification";
export type { TextElement } from "./TextElement";

View file

@ -1,4 +1,5 @@
import type { RateLimitWindow } from "../generated/app-server/v2/RateLimitWindow";
import type { SpendControlLimitSnapshot } from "../generated/app-server/v2/SpendControlLimitSnapshot";
import type { ThreadTokenUsage } from "../generated/app-server/v2/ThreadTokenUsage";
import { jsonPreview } from "../utils";
import { sortedAvailableModels } from "./model";
@ -94,6 +95,7 @@ export function rateLimitSummary(snapshot: RuntimeSnapshot, nowMs = Date.now()):
const rows = [
rateLimitWindowSummary("primary", rateLimit.primary, name, reached, rateLimit.rateLimitReachedType, nowMs),
rateLimitWindowSummary("secondary", rateLimit.secondary, name, reached, rateLimit.rateLimitReachedType, nowMs),
spendControlLimitSummary(rateLimit.individualLimit, name, nowMs),
].filter((row): row is RateLimitSummaryRow => row !== null);
if (rows.length === 0) return null;
@ -230,6 +232,25 @@ function rateLimitWindowSummary(
};
}
function spendControlLimitSummary(limit: SpendControlLimitSnapshot | null, name: string, nowMs: number): RateLimitSummaryRow | null {
if (!limit) return null;
const remainingPercent = Math.max(0, Math.min(100, Math.round(limit.remainingPercent)));
const percent = 100 - remainingPercent;
const level = remainingPercent <= 10 ? "danger" : remainingPercent <= 30 ? "warn" : "ok";
const resetLabel = limit.resetsAt ? formatRateLimitRemaining(limit.resetsAt, nowMs) : null;
const resetText = limit.resetsAt && resetLabel ? ` ${capitalize(resetLabel)}. Reset at ${formatRateLimitReset(limit.resetsAt)}.` : "";
const value = `${limit.used} / ${limit.limit}`;
return {
label: "monthly",
value,
resetLabel,
title: `${name} monthly limit: ${value} used, ${String(remainingPercent)}% remaining.${resetText}`,
percent,
level,
};
}
function formatRateLimitDuration(minutes: number): string {
if (minutes === 10_080) return "1w";
if (minutes % 60 === 0) return `${String(minutes / 60)}h`;

View file

@ -272,6 +272,7 @@ function thread(overrides: Partial<Thread> = {}): Thread {
id: "019e0182-cb70-7a72-ab48-8bc9d0b0d781",
sessionId: "019e0182-cb70-7a72-ab48-8bc9d0b0d781",
forkedFromId: null,
parentThreadId: null,
preview: "Preview",
ephemeral: false,
modelProvider: "openai",

View file

@ -14,6 +14,7 @@ function thread(overrides: Partial<Thread> = {}): Thread {
id: "019abcde-0000-7000-8000-000000000001",
sessionId: "session-1",
forkedFromId: null,
parentThreadId: null,
preview: "Preview",
ephemeral: false,
modelProvider: "openai",

View file

@ -53,6 +53,7 @@ function thread(overrides: Partial<Thread> = {}): Thread {
id: "thread-1",
sessionId: "session-1",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -52,6 +52,7 @@ describe("approval model", () => {
threadId: "thread",
turnId: "turn",
itemId: "item",
environmentId: null,
startedAtMs: 1,
reason: "Need network",
permissions: { network: { enabled: true }, fileSystem: null },
@ -162,6 +163,7 @@ describe("approval model", () => {
threadId: "thread",
turnId: "turn",
itemId: "permissions",
environmentId: null,
startedAtMs: 1,
reason: "Need network",
permissions: { network: { enabled: true }, fileSystem: null },
@ -184,6 +186,7 @@ describe("approval model", () => {
threadId: "thread",
turnId: "turn",
itemId: "permissions",
environmentId: null,
startedAtMs: 1,
reason: "Need network",
permissions: { network: { enabled: true }, fileSystem: null },

View file

@ -167,6 +167,7 @@ function threadFixture(id: string, overrides: Partial<Thread> = {}): Thread {
id,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -655,6 +655,7 @@ describe("ChatController", () => {
primary: { usedPercent: 64, windowDurationMins: 300, resetsAt: null },
secondary: null,
credits: null,
individualLimit: null,
planType: null,
rateLimitReachedType: null,
},
@ -1590,6 +1591,7 @@ function supportedApprovalRequests(): ServerRequest[] {
threadId: "thread",
turnId: "turn",
itemId: "permissions",
environmentId: null,
startedAtMs: 1,
reason: "Need access",
permissions: { network: null, fileSystem: null },
@ -1616,6 +1618,7 @@ function thread(id: string, cwd: string): Thread {
id,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -471,6 +471,7 @@ export function thread(id: string): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -24,6 +24,7 @@ function thread(overrides: Partial<Thread> = {}): Thread {
id: "019abcde-0000-7000-8000-000000000001",
sessionId: "session-1",
forkedFromId: null,
parentThreadId: null,
preview: "Preview",
ephemeral: false,
modelProvider: "openai",

View file

@ -41,6 +41,7 @@ function thread(overrides: Partial<Thread> = {}): Thread {
id: "thread-1",
sessionId: "session-1",
forkedFromId: null,
parentThreadId: null,
preview: "Preview",
ephemeral: false,
modelProvider: "openai",

View file

@ -11,6 +11,7 @@ function thread(id: string): Thread {
id,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -20,6 +20,7 @@ function thread(id: string, name: string | null = null): Thread {
id,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -24,6 +24,7 @@ function thread(id: string): Thread {
id,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -12,6 +12,7 @@ function thread(id: string, name: string | null = null): Thread {
id,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -17,6 +17,7 @@ function thread(id: string): Thread {
id,
sessionId: id,
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -280,6 +280,7 @@ function threadSnapshot(id: string): Extract<ServerNotification, { method: "thre
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "Preview",
ephemeral: false,
modelProvider: "openai",

View file

@ -351,6 +351,7 @@ function threadFixture(id: string): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: true,
modelProvider: "openai",

View file

@ -125,6 +125,7 @@ function threadFixture(id: string): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "Thread preview",
ephemeral: false,
modelProvider: "openai",

View file

@ -71,6 +71,7 @@ function threadFixture(id: string, name: string): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -176,6 +176,7 @@ export function pendingApproval(): PendingApproval {
threadId: "thread",
turnId: "turn",
itemId: "permission",
environmentId: null,
startedAtMs: 1,
cwd: "/vault",
reason: "Need network",

View file

@ -886,6 +886,7 @@ function threadFixture(threadId: string) {
id: threadId,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "Restored thread",
ephemeral: false,
modelProvider: "openai",

View file

@ -237,6 +237,7 @@ function threadFixture(id: string, name: string | null): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -694,6 +694,7 @@ function thread(id: string): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: true,
modelProvider: "openai",

View file

@ -43,6 +43,7 @@ function thread(options: Partial<Thread> & { id: string }): Thread {
id: options.id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: options.preview ?? options.id,
ephemeral: false,
modelProvider: "openai",

View file

@ -50,6 +50,7 @@ function threadFixture(overrides: Partial<Thread> = {}): Thread {
id: "thread",
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -393,6 +393,7 @@ function threadFixture(overrides: Record<string, unknown> = {}): Record<string,
id: "thread",
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -556,6 +556,7 @@ function thread(id: string): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: id,
ephemeral: false,
modelProvider: "openai",

View file

@ -565,6 +565,7 @@ describe("runtime settings", () => {
primary: { usedPercent: 72.4, windowDurationMins: 300, resetsAt: 1_800_000_000 },
secondary: null,
credits: null,
individualLimit: null,
planType: null,
rateLimitReachedType: null,
},
@ -585,6 +586,7 @@ describe("runtime settings", () => {
primary: { usedPercent: 95, windowDurationMins: null, resetsAt: null },
secondary: null,
credits: null,
individualLimit: null,
planType: null,
rateLimitReachedType: "rate_limit_reached",
},
@ -604,6 +606,7 @@ describe("runtime settings", () => {
primary: { usedPercent: 15, windowDurationMins: 300, resetsAt: null },
secondary: { usedPercent: 38, windowDurationMins: 10_080, resetsAt: null },
credits: null,
individualLimit: null,
planType: null,
rateLimitReachedType: null,
},
@ -626,6 +629,7 @@ describe("runtime settings", () => {
primary: { usedPercent: 10, windowDurationMins: 300, resetsAt: 1_800_000_000 },
secondary: null,
credits: null,
individualLimit: null,
planType: null,
rateLimitReachedType: null,
},
@ -635,6 +639,27 @@ describe("runtime settings", () => {
).toMatchObject({
rows: [{ resetLabel: "reset due" }],
});
expect(
rateLimitSummary(
runtimeSnapshot({
rateLimit: {
limitId: "codex",
limitName: "Codex",
primary: null,
secondary: null,
credits: null,
individualLimit: { limit: "$100", used: "$72", remainingPercent: 28, resetsAt: 1_800_000_000 },
planType: null,
rateLimitReachedType: null,
},
}),
1_799_991_600_000,
),
).toMatchObject({
rows: [{ label: "monthly", value: "$72 / $100", resetLabel: "reset in 2h 20m", percent: 72 }],
level: "warn",
});
});
});
@ -689,6 +714,7 @@ function threadFixture(id: string): Thread {
id,
sessionId: "session",
forkedFromId: null,
parentThreadId: null,
preview: "",
ephemeral: false,
modelProvider: "openai",

View file

@ -256,6 +256,7 @@ function thread(overrides: Partial<Thread> = {}): Thread {
id: "019e0182-cb70-7a72-ab48-8bc9d0b0d781",
sessionId: "019e0182-cb70-7a72-ab48-8bc9d0b0d781",
forkedFromId: null,
parentThreadId: null,
preview: "Preview",
ephemeral: false,
modelProvider: "openai",