fix: clarify codex supervisor active counts

This commit is contained in:
Codex
2026-05-23 02:49:09 +00:00
parent 982f21ec62
commit 8393bc531a
5 changed files with 233 additions and 11 deletions
+191 -3
View File
@@ -189,6 +189,7 @@ interface CompactTaskMutationResponseOptions {
interface CodexTasksOptions {
queueId: string | undefined;
requestedLimit: number;
limit: number;
beforeId: string | undefined;
unreadOnly: boolean;
@@ -288,6 +289,14 @@ interface CodexTasksDegraded {
reason: string;
}
interface SupervisorStatusCounts {
counts: Record<string, number>;
exact: boolean;
source: "queue-summary-counts" | "overview-page-fallback";
scope: "all-queues" | "queue";
queueId: string | null;
}
interface CodexQueuesOptions {
full: boolean;
limit: number;
@@ -1851,9 +1860,11 @@ function parseTasksOptions(args: string[]): CodexTasksOptions {
const unsupported = statusFilter.filter((status) => !supported.has(status));
if (unsupported.length > 0) throw new Error(`unsupported --status value: ${unsupported.join(", ")}; supported: ${Array.from(supported).join(", ")}`);
}
const requestedLimit = positiveIntegerOption(args, ["--limit"], defaultTasksLimit);
return {
queueId: optionValue(args, ["--queue", "--queue-id"]),
limit: positiveIntegerOption(args, ["--limit"], defaultTasksLimit, maxTasksLimit),
requestedLimit,
limit: Math.min(requestedLimit, maxTasksLimit),
beforeId: optionValue(args, ["--before-id", "--beforeId"]),
unreadOnly: hasFlag(args, "--unread-only") || hasFlag(args, "--unread"),
statusFilter,
@@ -2376,13 +2387,25 @@ function filterTasksForOptions(tasks: Record<string, unknown>[], options: CodexT
.filter((task) => !options.unreadOnly || taskUnreadTerminal(task));
}
function baseTaskListOptions(options: CodexTasksOptions): CodexTasksOptions {
return {
queueId: options.queueId,
requestedLimit: options.requestedLimit,
limit: options.limit,
beforeId: options.beforeId,
unreadOnly: options.unreadOnly,
statusFilter: options.statusFilter,
view: options.view,
};
}
function taskListCommand(options: CodexTasksOptions, extra: string[] = []): string {
const args = ["codex", "tasks"];
if (options.view !== "supervisor") args.push("--view", options.view);
if (options.queueId !== undefined) args.push("--queue", options.queueId);
if (options.unreadOnly) args.push("--unread");
if (options.statusFilter !== null) args.push("--status", options.statusFilter.join(","));
if (options.limit !== defaultTasksLimit) args.push("--limit", String(options.limit));
if (options.requestedLimit !== defaultTasksLimit) args.push("--limit", String(options.requestedLimit));
if (options.beforeId !== undefined) args.push("--before-id", options.beforeId);
args.push(...extra);
return `bun scripts/cli.ts ${args.join(" ")}`;
@@ -2406,6 +2429,155 @@ function sectionNextCommand(
return sourceNextCommand;
}
function countRecordValues(value: unknown): Record<string, number> {
const record = asRecord(value);
const counts: Record<string, number> = {};
if (record === null) return counts;
for (const [status, rawCount] of Object.entries(record)) {
const count = typeof rawCount === "number" ? rawCount : typeof rawCount === "string" ? Number(rawCount) : Number.NaN;
if (Number.isFinite(count) && count >= 0) counts[status] = Math.floor(count);
}
return counts;
}
function queueSummaryCountsForOptions(taskPage: CodexTasksTaskPage, options: CodexTasksOptions): SupervisorStatusCounts | null {
const queue = taskPage.queue;
if (queue === null) return null;
if (options.queueId !== undefined) {
for (const row of asArray(queue.queues)) {
const record = asRecord(row);
if (record === null || asString(record.id) !== options.queueId) continue;
if (asRecord(record.counts) === null) return null;
return {
counts: countRecordValues(record.counts),
exact: true,
source: "queue-summary-counts",
scope: "queue",
queueId: options.queueId,
};
}
return null;
}
if (asRecord(queue.counts) === null) return null;
return {
counts: countRecordValues(queue.counts),
exact: true,
source: "queue-summary-counts",
scope: "all-queues",
queueId: null,
};
}
function fallbackStatusCountsForOptions(taskPage: CodexTasksTaskPage, options: CodexTasksOptions): SupervisorStatusCounts {
const counts: Record<string, number> = {};
for (const task of taskPage.tasks) {
if (options.queueId !== undefined && asString(task.queueId) !== options.queueId) continue;
const status = asString(task.status);
if (status.length === 0) continue;
counts[status] = (counts[status] ?? 0) + 1;
}
return {
counts,
exact: false,
source: "overview-page-fallback",
scope: options.queueId === undefined ? "all-queues" : "queue",
queueId: options.queueId ?? null,
};
}
function statusCountsForOptions(taskPage: CodexTasksTaskPage, options: CodexTasksOptions): SupervisorStatusCounts {
return queueSummaryCountsForOptions(taskPage, options) ?? fallbackStatusCountsForOptions(taskPage, options);
}
function positiveCount(value: unknown): number | null {
const count = asNumber(value, Number.NaN);
return Number.isFinite(count) && count >= 0 ? Math.floor(count) : null;
}
function runtimeMaxActiveQueues(taskPage: CodexTasksTaskPage): number | null {
const value = positiveCount(taskPage.queue?.maxActiveQueues);
return value !== null && value > 0 ? value : null;
}
function activeRunningRedlineState(activeCount: number, hardRedline: number, burstRedline: number, routineTarget: number): string {
if (activeCount >= hardRedline) return "at-or-over-hard-redline";
if (activeCount >= burstRedline) return "burst-redline";
if (activeCount >= routineTarget) return "above-routine-target";
return "below-routine-target";
}
function supervisorActiveRunningSummary(
taskPage: CodexTasksTaskPage,
options: CodexTasksOptions,
runningSection: CodexTasksSection<CodexTasksSupervisorEntry>,
diagnostics: Record<string, unknown> | null,
): Record<string, unknown> {
const statusCounts = statusCountsForOptions(taskPage, options);
const runningCount = statusCounts.counts.running ?? 0;
const judgingCount = statusCounts.counts.judging ?? 0;
const activeStatusCount = runningCount + judgingCount;
const heartbeatActiveCount = positiveCount(diagnostics?.activeHeartbeatCount);
const schedulerLocalActiveRunSlotCount = positiveCount(diagnostics?.schedulerActiveRunSlotCount);
const effectiveActiveRunnerCount = Math.max(activeStatusCount, heartbeatActiveCount ?? 0, schedulerLocalActiveRunSlotCount ?? 0);
const policy = submitPolicyContract().concurrency;
const routineTarget = policy.gpt55Routine;
const burstRedline = Math.max(policy.gpt55BurstMax, policy.minimaxSimpleMax);
const hardRedline = 15;
const runtimeLimit = runtimeMaxActiveQueues(taskPage);
const redlineState = activeRunningRedlineState(activeStatusCount, hardRedline, burstRedline, routineTarget);
const exactInterpretation = statusCounts.exact
? "activeRunning.count is exact from queue status counts; row pagination does not change this count"
: "activeRunning.count is page-scoped because queue status counts were absent; do not use it for commander redline decisions without a queue summary/raw cross-check";
const baseOptions = baseTaskListOptions({ ...options, beforeId: undefined, unreadOnly: false, statusFilter: null });
const runningOptions: CodexTasksOptions = { ...baseOptions, statusFilter: ["running", "judging"] };
const queuedOptions: CodexTasksOptions = { ...baseOptions, statusFilter: ["queued", "retry_wait"] };
return {
count: activeStatusCount,
exact: statusCounts.exact,
source: statusCounts.source,
scope: statusCounts.scope,
queueId: statusCounts.queueId,
statuses: {
running: runningCount,
judging: judgingCount,
},
effectiveActiveRunnerCount,
effectiveActiveRunnerCountSources: {
activeStatusCount,
heartbeatActiveCount,
schedulerLocalActiveRunSlotCount,
},
rowPage: {
returned: runningSection.returned,
availableInCurrentOverview: runningSection.count,
returnedLimit: taskSectionLimit(options),
truncated: runningSection.truncated,
hasMore: runningSection.hasMore,
distinction: "returned is the compact row page; count is the active running total used for supervision",
},
redline: {
countField: "supervisor.activeRunning.count",
routineTarget,
burstRedline,
hardRedline,
runtimeMaxActiveQueues: runtimeLimit,
state: redlineState,
remainingToRoutineTarget: Math.max(0, routineTarget - activeStatusCount),
remainingToBurstRedline: Math.max(0, burstRedline - activeStatusCount),
remainingToHardRedline: Math.max(0, hardRedline - activeStatusCount),
decisionReady: statusCounts.exact,
interpretation: exactInterpretation,
},
commands: {
running: taskListCommand(runningOptions),
runningFull: taskListCommand({ ...runningOptions, view: "full" }),
queued: taskListCommand(queuedOptions),
queues: "bun scripts/cli.ts codex queues",
nextRunningPage: runningSection.commands.next,
},
};
}
function fetchTaskSummaries(taskIds: string[], fetcher: CodexResponseFetcher): { summaries: Map<string, Record<string, unknown>>; degraded: CodexTasksDegraded | null } {
const boundedIds = taskIds.slice(0, maxTasksLimit);
const summaries = new Map<string, Record<string, unknown>>();
@@ -2504,6 +2676,7 @@ function codexTasksOverviewResult(
const diagnostics = supervisorExecutionDiagnostics(asRecord(taskPage.queue)?.executionDiagnostics);
const activity = compactCodeQueueActivity(asRecord(taskPage.queue) ?? {}, diagnostics);
const commanderConcurrency = asRecord(activity.commanderConcurrency) ?? {};
const activeRunning = supervisorActiveRunningSummary(taskPage, options, runningSection, diagnostics);
const visibleSupervisorItems = [...runningSection.items, ...unreadSection.items, ...recentSection.items, ...queuedSection.items];
const classifierCounts = visibleSupervisorItems.reduce((counts, item) => {
const key = item.kind;
@@ -2517,7 +2690,10 @@ function codexTasksOverviewResult(
filters: {
view: options.view,
queueId: options.queueId ?? null,
requestedLimit: options.requestedLimit,
limit: options.limit,
effectiveLimit: options.limit,
limitCapped: options.limit < options.requestedLimit,
unreadOnly: options.unreadOnly,
status: options.statusFilter,
beforeId: options.beforeId ?? null,
@@ -2526,6 +2702,7 @@ function codexTasksOverviewResult(
endpoint: "/api/tasks/overview",
queueId: options.queueId ?? null,
limit: asNumber(pagination.limit, 0) || null,
limitSemantics: "upstream overview fetch limit; separate from filters.requestedLimit/effectiveLimit and compact section row counts",
returned: asNumber(pagination.returned, 0) || null,
total: asNumber(pagination.total, 0) || null,
hasMore: asBoolean(pagination.hasMore),
@@ -2536,9 +2713,13 @@ function codexTasksOverviewResult(
disclosure: {
defaultView: "supervisor",
policy: "bounded summary rows only; prompt/body are short previews and raw detail requires explicit task/full/trace/output commands",
limitSemantics: "--limit is request/scanning/page budget; supervisor sections still return compact bounded row pages and expose counts separately",
outputBudget: {
promptPreviewChars: supervisorPromptPreviewChars,
bodyPreviewChars: supervisorBodyPreviewChars,
requestedLimit: options.requestedLimit,
effectiveLimit: options.limit,
limitCapped: options.limit < options.requestedLimit,
sectionReturnedLimit: sectionLimit,
recentCompletedReturnedLimit: recentLimit,
recentCompletedBodyPreviewChars: supervisorRecentBodyPreviewChars,
@@ -2551,6 +2732,9 @@ function codexTasksOverviewResult(
counts: {
scanned: allTasks.length,
running: runningSection.count,
activeRunningCount: activeRunning.count,
activeRunningExact: activeRunning.exact,
activeRunningRowsReturned: runningSection.returned,
completedUnread: unreadSection.count,
recentCompleted: recentSection.count,
queued: queuedSection.count,
@@ -2563,12 +2747,13 @@ function codexTasksOverviewResult(
classifierCounts,
commanderConcurrency,
activity,
activeRunning,
executionDiagnostics: diagnostics,
degraded,
commands: {
refresh: taskListCommand(options),
unread: taskListCommand({ ...options, unreadOnly: true }),
byStatus: `bun scripts/cli.ts codex tasks --status <status>${options.queueId === undefined ? "" : ` --queue ${options.queueId}`}${options.limit === defaultTasksLimit ? "" : ` --limit ${options.limit}`}`,
byStatus: `bun scripts/cli.ts codex tasks --status <status>${options.queueId === undefined ? "" : ` --queue ${options.queueId}`}${options.requestedLimit === defaultTasksLimit ? "" : ` --limit ${options.requestedLimit}`}`,
full: fullCommand,
next: nextCommand,
},
@@ -2599,7 +2784,10 @@ function codexTasksFullResult(
filters: {
view: "full",
queueId: options.queueId ?? null,
requestedLimit: options.requestedLimit,
limit: options.limit,
effectiveLimit: options.limit,
limitCapped: options.limit < options.requestedLimit,
unreadOnly: options.unreadOnly,
status: options.statusFilter,
beforeId: options.beforeId ?? null,