fix: persist and restore Codex modelReasoningEffort across session archive/resume#419
fix: persist and restore Codex modelReasoningEffort across session archive/resume#419
Conversation
…esume - Add model_reasoning_effort column to sessions DB (schema v7 migration) - Store modelReasoningEffort when bootstrapping a Codex session - Restore modelReasoningEffort when resuming an archived session - Allow changing modelReasoningEffort at runtime via set-session-config RPC - Add REST endpoint POST /sessions/:id/model-reasoning-effort for web UI - Add supportsModelReasoningEffort capability to codex flavor - Add web UI controls to change reasoning effort in active Codex sessions Agent-Logs-Url: https://github.com/tiann/hapi/sessions/9a0417ed-4d43-423d-bd91-0616050c6dbd Co-authored-by: tiann <4233744+tiann@users.noreply.github.com>
Deploying hapi with
|
| Latest commit: |
e1f7465
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://5b35ca40.hapi-bqd.pages.dev |
| Branch Preview URL: | https://copilot-fix-archived-session.hapi-bqd.pages.dev |
…ump to v7 Agent-Logs-Url: https://github.com/tiann/hapi/sessions/9a0417ed-4d43-423d-bd91-0616050c6dbd Co-authored-by: tiann <4233744+tiann@users.noreply.github.com>
There was a problem hiding this comment.
Findings
- [Major]
modelReasoningEffortis only validated as an arbitrary non-empty string, so invalid values can be persisted and then replayed into Codex on resume. Evidence:hub/src/web/routes/sessions.ts:25,hub/src/web/routes/machines.ts:12,hub/src/web/routes/cli.ts:17,cli/src/codex/runCodex.ts:149. - [Minor] The new composer control only renders
default/low/medium/high/xhigh, but Codex also acceptsnoneandminimal, so resumed sessions using those values show no selected option. Evidence:web/src/components/AssistantChat/HappyComposer.tsx:642,cli/src/commands/codex.ts:9.
Summary
Review mode: initial. Two correctness issues in the new reasoning-effort persistence path: unsupported values are accepted end to end, and the new composer UI cannot represent all valid persisted Codex values.
Testing
Not run (automation): bun is not installed in this runner (bun: command not found).
HAPI Bot
| }) | ||
|
|
||
| const modelReasoningEffortSchema = z.object({ | ||
| modelReasoningEffort: z.string().trim().min(1).nullable() |
There was a problem hiding this comment.
[MAJOR] modelReasoningEffort is only checked as z.string().trim().min(1) here, and runCodex() later accepts any string via a cast (cli/src/codex/runCodex.ts:149). That lets values like "foo" get stored in SQLite and then sent back to Codex as model_reasoning_effort / reasoning_effort during resume, which can break the restored session.
Suggested fix:
const codexReasoningEffortSchema = z.enum(['none', 'minimal', 'low', 'medium', 'high', 'xhigh']).nullable()
const modelReasoningEffortSchema = z.object({
modelReasoningEffort: codexReasoningEffortSchema
})Apply the same schema to /cli/sessions, /machines/:id/spawn, and resolveModelReasoningEffort() so the persisted value set stays consistent.
| type="button" | ||
| disabled={controlsDisabled} | ||
| className={`flex w-full items-center gap-2 px-3 py-2 text-left text-sm transition-colors ${ | ||
| controlsDisabled |
There was a problem hiding this comment.
[MINOR] The new settings UI only iterates CODEX_REASONING_EFFORT_OPTIONS, which excludes none and minimal, even though Codex sessions can already persist those values (cli/src/commands/codex.ts:9). After resume, those sessions will render with no selected option, so the UI no longer reflects the stored config.
Suggested fix:
export const CODEX_REASONING_EFFORT_OPTIONS = [
{ value: 'default', label: 'Default' },
{ value: 'none', label: 'None' },
{ value: 'minimal', label: 'Minimal' },
{ value: 'low', label: 'Low' },
{ value: 'medium', label: 'Medium' },
{ value: 'high', label: 'High' },
{ value: 'xhigh', label: 'XHigh' },
]If none / minimal are intentionally unsupported in the web UI, reject them in the backend instead of persisting them.
Codex sessions with a custom reasoning effort (e.g.,
xhigh) would silently reset tomediumafter being archived and resumed, with no way to change it on a running resumed session.Root cause
modelReasoningEffortwas never stored in the DB — only held in-memory during the active session lifetime.Changes
DB (schema v6 → v7)
model_reasoning_effort TEXTcolumn tosessionstablePersistence & sync (hub)
modelReasoningEffortthroughgetOrCreateSession→StoredSession→SessionCache.refreshSessionresumeSessionnow passessession.modelReasoningEfforttospawnSession, restoring the setting on resumeSessionCache.applySessionConfigandmergeSessionshandle the new fieldPOST /sessions/:id/model-reasoning-effortfor runtime changesCLI (codex)
bootstrapSessionandapi.getOrCreateSessionaccept and forwardmodelReasoningEffortcurrentModelReasoningEffortchanged fromconst→let;set-session-configRPC handler now applies it and returns it inappliedShared
ModelReasoningEffortcapability toflavors.ts; codex now declares itsupportsModelReasoningEffort()helper (mirrors existingsupportsEffort)SessionSchemagainsmodelReasoningEffort?: string | nullWeb UI
HappyComposershows a reasoning-effort picker for active Codex sessions (gated onsupportsModelReasoningEffort)useSessionActionsgainssetModelReasoningEffortmutationmisc.reasoningEffortlocale key (EN + ZH-CN)