Merge pull request #515 from irisitymichaelgrundberg/feat/codex-reasoning-effort

feat(codex): start a codex session at a chosen reasoning effort
This commit is contained in:
Codeman maintainer
2026-10-04 23:24:39 +02:00
7 changed files with 93 additions and 1 deletions
+10
View File
@@ -11,6 +11,7 @@
*/
import type { CliEntry } from './types.js';
import { CODEX_REASONING_EFFORTS } from '../../types/session.js';
const HOME_DIRS = {
local: '~/.local/bin',
@@ -534,6 +535,7 @@ const CODEX: CliEntry = {
bypassApprovals: { type: 'bool' },
animations: { type: 'bool' },
model: { type: 'token', pattern: 'model' },
reasoningEffort: { type: 'enum', values: [...CODEX_REASONING_EFFORTS] },
resumeId: { type: 'token', pattern: 'id' },
},
variants: [
@@ -545,6 +547,14 @@ const CODEX: CliEntry = {
{ flag: '--config', value: 'tui.animations=true', when: { param: 'animations', is: true } },
{ flag: '--config', value: 'tui.animations=false', when: { param: 'animations', is: false } },
{ flag: '--model', valueFrom: 'model', when: { param: 'model', state: 'set' } },
// One literal per level: an argv token cannot splice a value into a literal, and
// `model_reasoning_effort=<level>` is a single `--config` value. The enum above is
// what admits a level, so an unknown one emits nothing.
...CODEX_REASONING_EFFORTS.map((level) => ({
flag: '--config',
value: `model_reasoning_effort=${level}`,
when: { param: 'reasoningEffort', is: level },
})),
{ lit: 'resume', when: { param: 'resumeId', state: 'set' } },
{ valueFrom: 'resumeId', when: { param: 'resumeId', state: 'set' } },
],
+12
View File
@@ -377,6 +377,16 @@ export function isEffortLevel(value: string | undefined): value is EffortLevel {
return value !== undefined && (EFFORT_LEVELS as readonly string[]).includes(value);
}
/**
* Reasoning effort levels codex accepts as `model_reasoning_effort` (codex-cli 0.154.0).
* Which of them a given model honours is codex's business; Codeman only keeps the value
* to a known word, since it lands in the launch argv.
*/
export const CODEX_REASONING_EFFORTS = ['none', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'ultra'] as const;
/** Codex reasoning effort for a session, passed as `--config model_reasoning_effort=<level>` */
export type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORTS)[number];
/** OpenCode session configuration */
export interface OpenCodeConfig {
/** Model identifier (e.g., "anthropic/claude-sonnet-4-5", "openai/gpt-5.2", "ollama/codellama") */
@@ -398,6 +408,8 @@ export type CodexRenderMode = 'hybrid';
export interface CodexConfig {
/** Model identifier (e.g., "gpt-5", "o4-mini"). Passed via --model. */
model?: string;
/** Reasoning effort for this session. Passed via --config model_reasoning_effort=<level>. */
reasoningEffort?: CodexReasoningEffort;
/** Resume a previous codex conversation by session id (passed via --resume) */
resumeSessionId?: string;
/** Bypass approval prompts (passes --dangerously-bypass-approvals-and-sandbox) */
+2
View File
@@ -18,6 +18,7 @@ import {
MIN_TERMINAL_SCROLLBACK_LINES,
} from '../config/terminal-history.js';
import { MAX_EDITABLE_BYTES } from '../config/file-editing.js';
import { CODEX_REASONING_EFFORTS } from '../types/session.js';
import { MIN_MATCH_LENGTH, MAX_MATCH_LENGTH } from '../config/agent-wait.js';
import { MAX_WAKE_MACS } from '../config/remote-wake-limits.js';
import { MAX_INPUT_LENGTH } from '../config/terminal-limits.js';
@@ -298,6 +299,7 @@ const CodexConfigSchema = z
.max(100)
.regex(/^[a-zA-Z0-9._\-/]+$/)
.optional(),
reasoningEffort: z.enum(CODEX_REASONING_EFFORTS).optional(),
resumeSessionId: z
.string()
.max(100)