fix: expose codex submit execution mode mapping

This commit is contained in:
unidesk-code-queue-runner
2026-05-23 08:27:23 +00:00
parent ac04e61937
commit f878841857
12 changed files with 287 additions and 7 deletions
@@ -38,6 +38,7 @@ export const defaultCodeModels = ["gpt-5.5", "gpt-5.4-mini", "gpt-5.4", deepseek
export const opencodeNpmPackage = "opencode-ai@1.14.48";
export const defaultCodeExecutionMode: CodeExecutionMode = "default";
export const codeExecutionModes: CodeExecutionMode[] = ["default", "windows-native"];
const codeExecutionModeAliases = new Set(["default", "windows-native", "windows", "win32", "native-windows"]);
export interface CodeModelProviderSourceConfig {
codeModels: string[];
@@ -104,6 +105,18 @@ export function normalizeCodeExecutionMode(value: unknown): CodeExecutionMode {
return defaultCodeExecutionMode;
}
export function normalizeRequestedCodeExecutionMode(value: unknown): string | null {
const raw = typeof value === "string" ? value.trim().toLowerCase() : "";
if (raw.length === 0) return null;
if (!/^[a-z0-9][a-z0-9-]{0,63}$/u.test(raw)) return null;
return raw;
}
export function requestedCodeExecutionModeIsRecognized(value: unknown): boolean {
const requested = normalizeRequestedCodeExecutionMode(value);
return requested === null || codeExecutionModeAliases.has(requested);
}
export function codeExecutionModeInfo(mode: CodeExecutionMode): Record<string, JsonValue> {
if (mode === "windows-native") {
return {
@@ -37,6 +37,7 @@ import {
codeModelProviderSourceContract,
normalizeCodeExecutionMode,
normalizeCodeModel,
normalizeRequestedCodeExecutionMode,
terminalStatus,
} from "./code-agent/common";
import type { ActiveRun, ActiveRunSlotWaiter } from "./code-agent/common";
@@ -1024,6 +1025,7 @@ function normalizeTask(task: QueueTask): QueueTask {
task.providerId = normalizeTaskProviderId(task.providerId);
task.model ||= config.defaultModel;
task.executionMode = normalizeCodeExecutionMode(task.executionMode);
task.requestedExecutionMode = normalizeRequestedCodeExecutionMode(task.requestedExecutionMode);
task.cwd = resolveTaskCwd(task.providerId, task.cwd);
task.reasoningEffort = resolveReasoningEffort(task.model, task.reasoningEffort);
task.maxAttempts = clampTaskAttempts(task.maxAttempts || config.defaultMaxAttempts);
@@ -2573,7 +2575,12 @@ function normalizeRequest(value: unknown): QueueTaskRequest {
if (typeof record.cwd === "string" && record.cwd.length > 0) request.cwd = record.cwd;
if (typeof record.model === "string" && record.model.length > 0) request.model = record.model;
if (typeof record.reasoningEffort === "string" && record.reasoningEffort.length > 0) request.reasoningEffort = record.reasoningEffort;
if (typeof record.executionMode === "string" && record.executionMode.length > 0) request.executionMode = normalizeCodeExecutionMode(record.executionMode);
if (typeof record.executionMode === "string" && record.executionMode.length > 0) {
const requestedExecutionMode = normalizeRequestedCodeExecutionMode(record.executionMode);
if (requestedExecutionMode === null) throw new Error("executionMode must be a short mode identifier");
request.requestedExecutionMode = requestedExecutionMode;
request.executionMode = normalizeCodeExecutionMode(requestedExecutionMode);
}
if (typeof record.maxAttempts === "number" && Number.isInteger(record.maxAttempts) && record.maxAttempts > 0) request.maxAttempts = clampTaskAttempts(record.maxAttempts);
const referenceTaskIds = collectReferenceTaskIds(record, record.prompt);
if (referenceTaskIds.length > 0) request.referenceTaskIds = referenceTaskIds;
@@ -2594,6 +2601,7 @@ function createTask(request: QueueTaskRequest): QueueTask {
const providerId = normalizeTaskProviderId(request.providerId);
const model = normalizeCodeModel(request.model ?? config.defaultModel);
const executionMode = normalizeCodeExecutionMode(request.executionMode);
const requestedExecutionMode = normalizeRequestedCodeExecutionMode(request.requestedExecutionMode);
const cwd = resolveTaskCwd(providerId, request.cwd);
validateExecutionModeForTask(providerId, cwd, model, executionMode);
rememberWorkdir(providerId, executionMode, cwd, at);
@@ -2612,6 +2620,7 @@ function createTask(request: QueueTaskRequest): QueueTask {
model,
reasoningEffort: resolveReasoningEffort(model, request.reasoningEffort),
executionMode,
requestedExecutionMode,
maxAttempts: request.maxAttempts ?? config.defaultMaxAttempts,
status: "queued",
createdAt: at,
@@ -14,7 +14,7 @@ import type { ActiveRun, ActiveRunSlotWaiter } from "./code-agent/common";
import type { JsonValue, QueueRecord, QueuedStatusReason, QueueTask, RuntimeConfig, TaskStatus, TranscriptLine } from "./types";
export interface QueueApiContext {
config: Pick<RuntimeConfig, "codeModels" | "codexModels" | "codexSqliteLogExportBatchSize" | "codexSqliteLogExportEnabled" | "codexSqliteLogExportIntervalMs" | "codexSqliteLogMaxBytes" | "deepseekApiBase" | "deepseekApiKey" | "deepseekModel" | "defaultModel" | "defaultReasoningEffort" | "defaultWorkdir" | "judgeMaxTokens" | "judgeRepairAttempts" | "mainProviderId" | "maxActiveQueues" | "maxInMemoryEventRecords" | "maxInMemoryOutputRecords" | "minimaxApiBase" | "minimaxApiKey" | "minimaxModel" | "modelReasoningEfforts" | "notifyClaudeQqBaseUrl" | "notifyClaudeQqEnabled" | "notifyClaudeQqMaxResponseChars" | "notifyClaudeQqRetryIntervalMs" | "notifyClaudeQqSendAttempts" | "notifyClaudeQqTargetType" | "notifyClaudeQqTimeoutMs" | "outputArchiveDir" | "remoteDefaultWorkdir" | "schedulerEnabled" | "schedulerPollIntervalMs" | "windowsNativeCodexDefaultWorkdir">;
config: Pick<RuntimeConfig, "approvalPolicy" | "codeModels" | "codexModels" | "codexSqliteLogExportBatchSize" | "codexSqliteLogExportEnabled" | "codexSqliteLogExportIntervalMs" | "codexSqliteLogMaxBytes" | "deepseekApiBase" | "deepseekApiKey" | "deepseekModel" | "defaultModel" | "defaultReasoningEffort" | "defaultWorkdir" | "judgeMaxTokens" | "judgeRepairAttempts" | "mainProviderId" | "maxActiveQueues" | "maxInMemoryEventRecords" | "maxInMemoryOutputRecords" | "minimaxApiBase" | "minimaxApiKey" | "minimaxModel" | "modelReasoningEfforts" | "notifyClaudeQqBaseUrl" | "notifyClaudeQqEnabled" | "notifyClaudeQqMaxResponseChars" | "notifyClaudeQqRetryIntervalMs" | "notifyClaudeQqSendAttempts" | "notifyClaudeQqTargetType" | "notifyClaudeQqTimeoutMs" | "outputArchiveDir" | "remoteDefaultWorkdir" | "sandbox" | "schedulerEnabled" | "schedulerPollIntervalMs" | "windowsNativeCodexDefaultWorkdir">;
activeRunSlotQueueIds: () => string[];
activeRunSlotWaiterSummaries: () => JsonValue[];
activeRuns: Map<string, ActiveRun>;
@@ -268,6 +268,7 @@ function taskForListResponse(task: QueueTask, lite = false, queueTasks?: QueueTa
},
providerId: task.providerId,
executionMode: task.executionMode,
requestedExecutionMode: task.requestedExecutionMode ?? null,
executionModeInfo: codeExecutionModeInfo(task.executionMode),
cwd: task.cwd,
model: task.model,
@@ -325,6 +326,7 @@ function taskForListResponse(task: QueueTask, lite = false, queueTasks?: QueueTa
referenceInjection: task.referenceInjection,
providerId: task.providerId,
executionMode: task.executionMode,
requestedExecutionMode: task.requestedExecutionMode ?? null,
executionModeInfo: codeExecutionModeInfo(task.executionMode),
cwd: task.cwd,
model: task.model,
@@ -483,6 +485,14 @@ function queueSummary(includeDevReady = true, tasks: QueueTask[] = ctx().tasks()
modelProviderConfig: codeModelProviderSourceContract(ctx().config) as unknown as JsonValue,
executionModes: executionModeOptions(),
executionModeInfo: Object.fromEntries(codeExecutionModes.map((mode) => [mode, codeExecutionModeInfo(mode)])) as unknown as JsonValue,
runnerPermissions: {
observed: true,
scope: "code-queue-service-config",
sandbox: ctx().config.sandbox,
approvalPolicy: ctx().config.approvalPolicy,
perTaskOverrideSupported: false,
secretsPrinted: false,
} as unknown as JsonValue,
agentPorts: {
codex: codeAgentPortInfo("codex"),
opencode: codeAgentPortInfo("opencode"),
@@ -1447,6 +1447,7 @@ function taskForMetaResponse(task: QueueTask): JsonValue {
referenceInjection: task.referenceInjection,
providerId: task.providerId,
executionMode: task.executionMode,
requestedExecutionMode: task.requestedExecutionMode ?? null,
executionModeInfo: codeExecutionModeInfo(task.executionMode),
cwd: task.cwd,
model: task.model,
@@ -1518,6 +1519,7 @@ function taskForCompactMetaResponse(task: QueueTask): JsonValue {
},
providerId: task.providerId,
executionMode: task.executionMode,
requestedExecutionMode: task.requestedExecutionMode ?? null,
executionModeInfo: codeExecutionModeInfo(task.executionMode),
cwd: task.cwd,
model: task.model,
@@ -2391,6 +2393,7 @@ function taskTraceSummaryResponse(task: QueueTask, oaTraceStats: JsonValue | nul
status: task.status,
providerId: task.providerId,
executionMode: task.executionMode,
requestedExecutionMode: task.requestedExecutionMode ?? null,
executionModeInfo: codeExecutionModeInfo(task.executionMode),
model: task.model,
agentPort: codeAgentPortForModel(task.model),
@@ -2552,6 +2555,7 @@ function taskSummaryResponse(task: QueueTask, url: URL): JsonValue {
status: task.status,
providerId: task.providerId,
executionMode: task.executionMode,
requestedExecutionMode: task.requestedExecutionMode ?? null,
executionModeInfo: codeExecutionModeInfo(task.executionMode),
model: task.model,
agentPort: codeAgentPortForModel(task.model),
@@ -191,6 +191,7 @@ export interface QueueTaskRequest {
model?: string;
reasoningEffort?: string;
executionMode?: CodeExecutionMode;
requestedExecutionMode?: string | null;
maxAttempts?: number;
referenceTaskIds?: string[];
basePrompt?: string;
@@ -394,6 +395,7 @@ export interface QueueTask {
model: string;
reasoningEffort: string | null;
executionMode: CodeExecutionMode;
requestedExecutionMode?: string | null;
maxAttempts: number;
status: TaskStatus;
createdAt: string;