Set codex-local creation defaults for model and sandbox bypass

This commit is contained in:
Dotta
2026-03-03 12:41:50 -06:00
parent 8351f7f1bd
commit 0810101fda
5 changed files with 78 additions and 9 deletions

View File

@@ -1,8 +1,10 @@
export const type = "codex_local";
export const label = "Codex (local)";
export const DEFAULT_CODEX_LOCAL_MODEL = "gpt-5.3-codex";
export const DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX = true;
export const models = [
{ id: "gpt-5.3-codex", label: "gpt-5.3-codex" },
{ id: DEFAULT_CODEX_LOCAL_MODEL, label: DEFAULT_CODEX_LOCAL_MODEL },
{ id: "gpt-5.3-codex-spark", label: "gpt-5.3-codex-spark" },
{ id: "gpt-5", label: "gpt-5" },
{ id: "o3", label: "o3" },

View File

@@ -1,4 +1,8 @@
import type { CreateConfigValues } from "@paperclipai/adapter-utils";
import {
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
DEFAULT_CODEX_LOCAL_MODEL,
} from "../index.js";
function parseCommaArgs(value: string): string[] {
return value
@@ -55,7 +59,7 @@ export function buildCodexLocalConfig(v: CreateConfigValues): Record<string, unk
if (v.cwd) ac.cwd = v.cwd;
if (v.instructionsFilePath) ac.instructionsFilePath = v.instructionsFilePath;
if (v.promptTemplate) ac.promptTemplate = v.promptTemplate;
if (v.model) ac.model = v.model;
ac.model = v.model || DEFAULT_CODEX_LOCAL_MODEL;
if (v.thinkingEffort) ac.modelReasoningEffort = v.thinkingEffort;
ac.timeoutSec = 0;
ac.graceSec = 15;
@@ -68,7 +72,10 @@ export function buildCodexLocalConfig(v: CreateConfigValues): Record<string, unk
}
if (Object.keys(env).length > 0) ac.env = env;
ac.search = v.search;
ac.dangerouslyBypassApprovalsAndSandbox = v.dangerouslyBypassSandbox;
ac.dangerouslyBypassApprovalsAndSandbox =
typeof v.dangerouslyBypassSandbox === "boolean"
? v.dangerouslyBypassSandbox
: DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX;
if (v.command) ac.command = v.command;
if (v.extraArgs) ac.extraArgs = parseCommaArgs(v.extraArgs);
return ac;

View File

@@ -32,6 +32,10 @@ import { assertBoard, assertCompanyAccess, getActorInfo } from "./authz.js";
import { findServerAdapter, listAdapterModels } from "../adapters/index.js";
import { redactEventPayload } from "../redaction.js";
import { runClaudeLogin } from "@paperclipai/adapter-claude-local/server";
import {
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
DEFAULT_CODEX_LOCAL_MODEL,
} from "@paperclipai/adapter-codex-local";
export function agentRoutes(db: Db) {
const DEFAULT_INSTRUCTIONS_PATH_KEYS: Record<string, string> = {
@@ -170,6 +174,25 @@ export function agentRoutes(db: Db) {
return trimmed.length > 0 ? trimmed : null;
}
function applyCreateDefaultsByAdapterType(
adapterType: string | null | undefined,
adapterConfig: Record<string, unknown>,
): Record<string, unknown> {
if (adapterType !== "codex_local") return adapterConfig;
const next = { ...adapterConfig };
if (!asNonEmptyString(next.model)) {
next.model = DEFAULT_CODEX_LOCAL_MODEL;
}
const hasBypassFlag =
typeof next.dangerouslyBypassApprovalsAndSandbox === "boolean" ||
typeof next.dangerouslyBypassSandbox === "boolean";
if (!hasBypassFlag) {
next.dangerouslyBypassApprovalsAndSandbox = DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX;
}
return next;
}
function resolveInstructionsFilePath(candidatePath: string, adapterConfig: Record<string, unknown>) {
const trimmed = candidatePath.trim();
if (path.isAbsolute(trimmed)) return trimmed;
@@ -546,9 +569,13 @@ export function agentRoutes(db: Db) {
await assertCanCreateAgentsForCompany(req, companyId);
const sourceIssueIds = parseSourceIssueIds(req.body);
const { sourceIssueId: _sourceIssueId, sourceIssueIds: _sourceIssueIds, ...hireInput } = req.body;
const requestedAdapterConfig = applyCreateDefaultsByAdapterType(
hireInput.adapterType,
((hireInput.adapterConfig ?? {}) as Record<string, unknown>),
);
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(
companyId,
((hireInput.adapterConfig ?? {}) as Record<string, unknown>),
requestedAdapterConfig,
{ strictMode: strictSecretsMode },
);
const normalizedHireInput = {
@@ -677,9 +704,13 @@ export function agentRoutes(db: Db) {
assertBoard(req);
}
const requestedAdapterConfig = applyCreateDefaultsByAdapterType(
req.body.adapterType,
((req.body.adapterConfig ?? {}) as Record<string, unknown>),
);
const normalizedAdapterConfig = await secretsSvc.normalizeAdapterConfigForPersistence(
companyId,
((req.body.adapterConfig ?? {}) as Record<string, unknown>),
requestedAdapterConfig,
{ strictMode: strictSecretsMode },
);

View File

@@ -11,6 +11,10 @@ import type { AdapterModel } from "../api/agents";
import { agentsApi } from "../api/agents";
import { secretsApi } from "../api/secrets";
import { assetsApi } from "../api/assets";
import {
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
DEFAULT_CODEX_LOCAL_MODEL,
} from "@paperclipai/adapter-codex-local";
import {
Popover,
PopoverContent,
@@ -433,7 +437,13 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
if (isCreate) {
// Reset all adapter-specific fields to defaults when switching adapter type
const { adapterType: _at, ...defaults } = defaultCreateValues;
set!({ ...defaults, adapterType: t });
const nextValues: CreateConfigValues = { ...defaults, adapterType: t };
if (t === "codex_local") {
nextValues.model = DEFAULT_CODEX_LOCAL_MODEL;
nextValues.dangerouslyBypassSandbox =
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX;
}
set!(nextValues);
} else {
// Clear all adapter config and explicitly blank out model + both effort keys
// so the old adapter's values don't bleed through via eff()
@@ -441,9 +451,15 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
...prev,
adapterType: t,
adapterConfig: {
model: "",
model: t === "codex_local" ? DEFAULT_CODEX_LOCAL_MODEL : "",
effort: "",
modelReasoningEffort: "",
...(t === "codex_local"
? {
dangerouslyBypassApprovalsAndSandbox:
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
}
: {}),
},
}));
}

View File

@@ -18,6 +18,10 @@ import { Button } from "@/components/ui/button";
import { cn } from "../lib/utils";
import { getUIAdapter } from "../adapters";
import { defaultCreateValues } from "./agent-config-defaults";
import {
DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX,
DEFAULT_CODEX_LOCAL_MODEL,
} from "@paperclipai/adapter-codex-local";
import { AsciiArtAnimation } from "./AsciiArtAnimation";
import { ChoosePathButton } from "./PathInstructionsModal";
import { HintIcon } from "./agent-config-primitives";
@@ -156,11 +160,15 @@ export function OnboardingWizard() {
...defaultCreateValues,
adapterType,
cwd,
model,
model: adapterType === "codex_local" ? model || DEFAULT_CODEX_LOCAL_MODEL : model,
command,
args,
url,
dangerouslySkipPermissions: adapterType === "claude_local",
dangerouslyBypassSandbox:
adapterType === "codex_local"
? DEFAULT_CODEX_LOCAL_BYPASS_APPROVALS_AND_SANDBOX
: defaultCreateValues.dangerouslyBypassSandbox,
});
}
@@ -456,7 +464,12 @@ export function OnboardingWizard() {
: "border-border hover:bg-accent/50"
)}
onClick={() => {
if (!opt.comingSoon) setAdapterType(opt.value as AdapterType);
if (opt.comingSoon) return;
const nextType = opt.value as AdapterType;
setAdapterType(nextType);
if (nextType === "codex_local" && !model) {
setModel(DEFAULT_CODEX_LOCAL_MODEL);
}
}}
>
<opt.icon className="h-4 w-4" />