mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-20 10:06:54 +03:00
Prewarm Codex Live with safe fallback
Return after a durable starting record, overlap app-server initialization with page startup, dynamically reclaim generation after worker failure, and cap hard-crash leases at 15 seconds.\n\nAI-assisted: OpenAI Codex.
This commit is contained in:
@@ -6,6 +6,7 @@ import { describe, it } from 'node:test';
|
||||
|
||||
import { CODEX_WORKER_OWNER } from '../skill/scripts/live/codex-worker.mjs';
|
||||
import {
|
||||
CODEX_WORKER_EVENT_LEASE_MS,
|
||||
CODEX_WORKER_EVENT_TYPES,
|
||||
CodexLiveWorkerSupervisor,
|
||||
buildDeterministicScaffoldCommand,
|
||||
@@ -145,6 +146,7 @@ describe('Codex Live worker supervisor ownership and lifecycle', () => {
|
||||
supervisor.thread = { id: 'live-worker-thread' };
|
||||
supervisor.fetchEvent = async (_base, _token, options) => {
|
||||
assert.deepEqual(options.types, CODEX_WORKER_EVENT_TYPES);
|
||||
assert.equal(options.leaseMs, CODEX_WORKER_EVENT_LEASE_MS);
|
||||
return cleanups.length === 0
|
||||
? { type: 'accept', id: 'abc12345', variantId: '1' }
|
||||
: { type: 'exit' };
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
buildCodexWorkerInstructions,
|
||||
buildCodexWorkerTurnInputs,
|
||||
buildGenerationTurnInput,
|
||||
codexWorkerProcessStateIsOwned,
|
||||
codexWorkerStateIsOwned,
|
||||
isCodexRuntime,
|
||||
readPreparedArtifact,
|
||||
@@ -53,6 +54,8 @@ describe('Codex Live worker configuration', () => {
|
||||
assert.equal(codexWorkerStateIsOwned({ owner: CODEX_WORKER_OWNER, cwd, threadId: 'worker-1' }, cwd), true);
|
||||
assert.equal(codexWorkerStateIsOwned({ owner: 'desktop', cwd, threadId: 'desktop-1' }, cwd), false);
|
||||
assert.equal(codexWorkerStateIsOwned({ owner: CODEX_WORKER_OWNER, cwd: '/tmp/other', threadId: 'worker-1' }, cwd), false);
|
||||
assert.equal(codexWorkerProcessStateIsOwned({ owner: CODEX_WORKER_OWNER, cwd, pid: 123, status: 'starting' }, cwd), true);
|
||||
assert.equal(codexWorkerStateIsOwned({ owner: CODEX_WORKER_OWNER, cwd, pid: 123, status: 'starting' }, cwd), false);
|
||||
});
|
||||
|
||||
it('leaves the portable foreground path untouched when the switch is off', () => {
|
||||
@@ -160,6 +163,47 @@ describe('Codex Live worker configuration', () => {
|
||||
assert.equal(output.fallback, 'foreground');
|
||||
assert.throws(() => process.kill(output.childPid, 0), (error) => error.code === 'ESRCH');
|
||||
});
|
||||
|
||||
it('returns a durable starting record without waiting for app-server readiness', () => {
|
||||
const cwd = mkdtempSync(path.join(tmpdir(), 'codex-worker-prewarm-'));
|
||||
const liveDir = path.join(cwd, '.impeccable/live');
|
||||
mkdirSync(liveDir, { recursive: true });
|
||||
writeFileSync(path.join(liveDir, 'server.json'), JSON.stringify({
|
||||
pid: process.pid,
|
||||
port: 1,
|
||||
token: 'smoke-token',
|
||||
}));
|
||||
const fakeCodex = path.join(cwd, 'fake-codex');
|
||||
writeFileSync(fakeCodex, '#!/bin/sh\nwhile true; do sleep 1; done\n');
|
||||
chmodSync(fakeCodex, 0o755);
|
||||
const script = path.resolve('skill/scripts/live-codex-worker.mjs');
|
||||
const startedAt = Date.now();
|
||||
const result = spawnSync(process.execPath, [script, '--background', '--no-wait'], {
|
||||
cwd,
|
||||
encoding: 'utf-8',
|
||||
env: {
|
||||
...process.env,
|
||||
IMPECCABLE_LIVE_CODEX_WORKER: '1',
|
||||
IMPECCABLE_CODEX_PATH: fakeCodex,
|
||||
},
|
||||
timeout: 5_000,
|
||||
});
|
||||
assert.equal(result.status, 0, result.stderr);
|
||||
const output = JSON.parse(result.stdout);
|
||||
assert.equal(output.status, 'starting');
|
||||
assert.equal(output.starting, true);
|
||||
assert.equal(codexWorkerProcessStateIsOwned(output, cwd), true);
|
||||
assert.ok(Date.now() - startedAt < 1_000, 'prewarm should not wait for app-server initialization');
|
||||
|
||||
const stopped = spawnSync(process.execPath, [script, '--stop'], {
|
||||
cwd,
|
||||
encoding: 'utf-8',
|
||||
env: { ...process.env, IMPECCABLE_LIVE_CODEX_STOP_TIMEOUT_MS: '1000' },
|
||||
timeout: 3_000,
|
||||
});
|
||||
assert.equal(stopped.status, 0, stopped.stderr);
|
||||
assert.equal(JSON.parse(stopped.stdout).status, 'stopped');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Codex Live worker structured artifact boundary', () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
manualApplyPollBanner,
|
||||
normalizePollTypes,
|
||||
parseReplyArgs,
|
||||
resolveCodexWorkerFallbackTypes,
|
||||
requiresAgentReply,
|
||||
} from '../skill/scripts/live-poll.mjs';
|
||||
|
||||
@@ -167,4 +168,27 @@ describe('live-poll stream helpers', () => {
|
||||
['steer', 'manual_edit_apply', 'carbonize_cleanup', 'exit'],
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps generation isolated while the Codex worker starts and restores it after failure', () => {
|
||||
const cwd = '/tmp/live-fallback';
|
||||
const control = ['steer', 'manual_edit_apply', 'carbonize_cleanup', 'exit'];
|
||||
const starting = {
|
||||
owner: 'impeccable-live-codex-worker-v1',
|
||||
cwd,
|
||||
pid: 123,
|
||||
status: 'starting',
|
||||
};
|
||||
assert.deepEqual(resolveCodexWorkerFallbackTypes(control, {
|
||||
cwd,
|
||||
state: starting,
|
||||
isPidReachable: () => true,
|
||||
}), control);
|
||||
|
||||
const fallback = resolveCodexWorkerFallbackTypes(control, {
|
||||
cwd,
|
||||
state: { ...starting, status: 'error' },
|
||||
isPidReachable: () => false,
|
||||
});
|
||||
assert.deepEqual(fallback, [...control, 'generate', 'accept', 'discard', 'prefetch']);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user