mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-14 23:26:39 +03:00
Cut Live variant two output latency
This commit is contained in:
@@ -340,6 +340,8 @@ export class CodexLiveWorkerSupervisor {
|
||||
prepared,
|
||||
phase,
|
||||
expectedVariants: Number(event.count || arrivedVariants),
|
||||
sessionId: event.id,
|
||||
scaffold: event.scaffold,
|
||||
cwd: this.cwd,
|
||||
maxBytes: this.config.maxArtifactBytes,
|
||||
});
|
||||
@@ -379,7 +381,11 @@ export class CodexLiveWorkerSupervisor {
|
||||
if (this.isCanceled(event.id)) return;
|
||||
const result = await this.runTurnWithReconnect({
|
||||
input,
|
||||
outputSchema: codexWorkerOutputSchemaForPhase(phase, Number(event.count || arrivedVariants)),
|
||||
outputSchema: codexWorkerOutputSchemaForPhase(
|
||||
phase,
|
||||
Number(event.count || arrivedVariants),
|
||||
{ sourceDelta: phase === 'second' && !prepared.previewMode },
|
||||
),
|
||||
onAgentMessage: publishCandidate,
|
||||
eventId: event.id,
|
||||
});
|
||||
|
||||
@@ -57,8 +57,30 @@ export const CODEX_WORKER_OUTPUT_SCHEMA = Object.freeze({
|
||||
required: ['files'],
|
||||
additionalProperties: false,
|
||||
});
|
||||
const CODEX_SOURCE_DELTA_OUTPUT_SCHEMA = Object.freeze({
|
||||
type: 'object',
|
||||
properties: {
|
||||
sourceDelta: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
variantId: { type: 'integer', minimum: 2, maximum: 2 },
|
||||
markup: { type: 'string', minLength: 1 },
|
||||
css: { type: 'string', minLength: 1 },
|
||||
},
|
||||
required: ['variantId', 'markup', 'css'],
|
||||
additionalProperties: false,
|
||||
},
|
||||
},
|
||||
required: ['sourceDelta'],
|
||||
additionalProperties: false,
|
||||
});
|
||||
|
||||
export function codexWorkerOutputSchemaForPhase(phase, expectedVariants = 3) {
|
||||
export function codexWorkerOutputSchemaForPhase(
|
||||
phase,
|
||||
expectedVariants = 3,
|
||||
{ sourceDelta = false } = {},
|
||||
) {
|
||||
if (sourceDelta) return CODEX_SOURCE_DELTA_OUTPUT_SCHEMA;
|
||||
const requirePlan = Number(expectedVariants) > 1 && (phase === 'first' || phase === 'atomic');
|
||||
return {
|
||||
...CODEX_WORKER_OUTPUT_SCHEMA,
|
||||
@@ -139,6 +161,7 @@ export function buildGenerationTurnInput({
|
||||
const first = phase === 'first';
|
||||
const second = phase === 'second';
|
||||
const component = Boolean(prepared.previewMode);
|
||||
const sourceDelta = second && !component;
|
||||
const actionRules = event.action === 'bolder' && count > 1
|
||||
? [
|
||||
'For /bolder, keep variant 1 low-risk: preserve the selected root’s high-level layout and create impact through controlled hierarchy, proportion, or rhythm. Reserve root recomposition for variant 2 or 3.',
|
||||
@@ -156,7 +179,7 @@ export function buildGenerationTurnInput({
|
||||
: second
|
||||
? [
|
||||
'Produce only variant 2 now so it can be reviewed immediately.',
|
||||
'Variant 1 is already visible and immutable. Do not return or alter its file, markup, or CSS.',
|
||||
'Variant 1 is already visible and immutable. Do not return or alter its markup or CSS.',
|
||||
'Follow the durable variant plan below and implement direction 2 as an independently shippable option.',
|
||||
'Defer tunable parameters: params must be absent or empty for this phase.',
|
||||
]
|
||||
@@ -175,10 +198,14 @@ export function buildGenerationTurnInput({
|
||||
`LIVE GENERATION PHASE: ${phase}`,
|
||||
...phaseRules,
|
||||
...actionRules,
|
||||
component
|
||||
sourceDelta
|
||||
? 'Return exactly sourceDelta for variant 2. markup is only the selected root replacement, without an outer data-impeccable wrapper. css is only the complete fenced CSS for variant 2, following event.scaffold.cssAuthoring.'
|
||||
: component
|
||||
? `Return staged component files relative to componentDir. Allowed variant extension: .${artifact.componentExtension}. The supervisor updates manifest.json.`
|
||||
: `Return exactly one file whose path is ${JSON.stringify(prepared.artifactFile)} and whose content is the complete staged source artifact.`,
|
||||
component
|
||||
sourceDelta
|
||||
? 'Do not repeat the staged artifact, variant 1, style tags, wrapper comments, or any data-impeccable attributes. The supervisor merges and validates this delta transactionally.'
|
||||
: component
|
||||
? 'For the final/atomic phase include params.json keyed by variant number. Never include manifest.json or paths outside componentDir.'
|
||||
: 'Keep the existing session wrapper and markers intact. Add only valid variant blocks and preview CSS inside that wrapper.',
|
||||
'',
|
||||
@@ -267,10 +294,25 @@ export function applyCodexWorkerOutput({
|
||||
prepared,
|
||||
phase,
|
||||
expectedVariants,
|
||||
sessionId,
|
||||
scaffold,
|
||||
cwd = process.cwd(),
|
||||
maxBytes = 2_000_000,
|
||||
}) {
|
||||
const parsed = typeof output === 'string' ? parseWorkerJson(output) : output;
|
||||
if (!prepared.previewMode && phase === 'second') {
|
||||
const artifactPath = resolveInside(cwd, prepared.artifactFile);
|
||||
if (!artifactPath) throw workerError('artifact_path_outside_project');
|
||||
const content = applyCodexSourceDelta({
|
||||
source: fs.readFileSync(artifactPath, 'utf-8'),
|
||||
delta: parsed?.sourceDelta,
|
||||
sessionId,
|
||||
styleMode: scaffold?.styleMode || scaffold?.cssAuthoring?.mode || 'scoped',
|
||||
});
|
||||
if (Buffer.byteLength(content) > maxBytes) throw workerError('worker_output_too_large');
|
||||
fs.writeFileSync(artifactPath, content, 'utf-8');
|
||||
return { files: [prepared.artifactFile], plan: null, sourceDelta: true };
|
||||
}
|
||||
if (!Array.isArray(parsed?.files) || parsed.files.length === 0) {
|
||||
throw workerError('worker_output_files_missing');
|
||||
}
|
||||
@@ -344,6 +386,90 @@ export function applyCodexWorkerOutput({
|
||||
return { files: [...seen], plan };
|
||||
}
|
||||
|
||||
export function applyCodexSourceDelta({
|
||||
source,
|
||||
delta,
|
||||
sessionId,
|
||||
styleMode = 'scoped',
|
||||
}) {
|
||||
if (!delta || typeof delta !== 'object' || Array.isArray(delta)) {
|
||||
throw workerError('worker_output_source_delta_missing');
|
||||
}
|
||||
if (Number(delta.variantId) !== 2) throw workerError('worker_output_source_delta_variant_invalid');
|
||||
const markup = String(delta.markup || '').trim();
|
||||
const css = String(delta.css || '').trim();
|
||||
if (!markup || !css) throw workerError('worker_output_source_delta_empty');
|
||||
if (/data-impeccable-(?:variant|variants|css)|impeccable-variants-(?:start|end)/i.test(markup)) {
|
||||
throw workerError('worker_output_source_delta_wrapper_forbidden');
|
||||
}
|
||||
if (/<\/?style\b|`|\$\{/i.test(css)) {
|
||||
throw workerError('worker_output_source_delta_css_unsafe');
|
||||
}
|
||||
const cssVariantRefs = [...css.matchAll(/\[data-impeccable-variant=(?:"([^"]+)"|'([^']+)')\]/g)]
|
||||
.map((match) => match[1] || match[2]);
|
||||
if (cssVariantRefs.length === 0 || cssVariantRefs.some((variant) => variant !== '2')) {
|
||||
throw workerError('worker_output_source_delta_css_unfenced');
|
||||
}
|
||||
const astroGlobal = styleMode === 'astro-global-prefixed';
|
||||
if (astroGlobal ? /@scope\b/.test(css) : !/@scope\s*\(\s*\[data-impeccable-variant=(?:"2"|'2')\]\s*\)/.test(css)) {
|
||||
throw workerError('worker_output_source_delta_css_strategy_invalid');
|
||||
}
|
||||
|
||||
const id = String(sessionId || '');
|
||||
if (!id) throw workerError('worker_output_source_delta_session_missing');
|
||||
const wrapper = findSessionWrapper(source, id);
|
||||
if (!wrapper) throw workerError('worker_output_source_delta_wrapper_missing');
|
||||
if (extractSourceVariantBlock(source, 2)) throw workerError('worker_output_source_delta_variant_exists');
|
||||
|
||||
const escapedId = escapeRegExp(id);
|
||||
const styleOpen = new RegExp(`<style\\b[^>]*\\bdata-impeccable-css=(?:"${escapedId}"|'${escapedId}')[^>]*>`, 'i');
|
||||
const styleMatch = styleOpen.exec(source);
|
||||
if (!styleMatch) throw workerError('worker_output_source_delta_style_missing');
|
||||
const styleContentStart = styleMatch.index + styleMatch[0].length;
|
||||
const styleClose = source.indexOf('</style>', styleContentStart);
|
||||
if (styleClose < 0 || styleClose > wrapper.closeEnd) {
|
||||
throw workerError('worker_output_source_delta_style_invalid');
|
||||
}
|
||||
const styleContent = source.slice(styleContentStart, styleClose);
|
||||
let nextStyleContent;
|
||||
const firstTick = styleContent.indexOf('`');
|
||||
const lastTick = styleContent.lastIndexOf('`');
|
||||
if (firstTick >= 0 || lastTick >= 0) {
|
||||
if (firstTick < 0 || lastTick <= firstTick) {
|
||||
throw workerError('worker_output_source_delta_style_invalid');
|
||||
}
|
||||
nextStyleContent = styleContent.slice(0, lastTick).trimEnd()
|
||||
+ '\n' + css + '\n'
|
||||
+ styleContent.slice(lastTick);
|
||||
} else {
|
||||
nextStyleContent = styleContent.trimEnd() + '\n' + css + '\n';
|
||||
}
|
||||
let merged = source.slice(0, styleContentStart) + nextStyleContent + source.slice(styleClose);
|
||||
|
||||
const nextWrapper = findSessionWrapper(merged, id);
|
||||
if (!nextWrapper) throw workerError('worker_output_source_delta_wrapper_missing');
|
||||
const closeLineStart = merged.lastIndexOf('\n', nextWrapper.closeStart) + 1;
|
||||
const closeLinePrefix = merged.slice(closeLineStart, nextWrapper.closeStart);
|
||||
const childIndent = nextWrapper.indent + ' ';
|
||||
const contentIndent = childIndent + ' ';
|
||||
const indentedMarkup = markup.split('\n')
|
||||
.map((line) => line.trim() ? contentIndent + line : '')
|
||||
.join('\n');
|
||||
const variantBlock = [
|
||||
`${childIndent}<div data-impeccable-variant="2">`,
|
||||
indentedMarkup,
|
||||
`${childIndent}</div>`,
|
||||
].join('\n');
|
||||
if (/^\s*$/.test(closeLinePrefix)) {
|
||||
merged = merged.slice(0, closeLineStart) + variantBlock + '\n' + merged.slice(closeLineStart);
|
||||
} else {
|
||||
merged = merged.slice(0, nextWrapper.closeStart)
|
||||
+ '\n' + variantBlock + '\n' + nextWrapper.indent
|
||||
+ merged.slice(nextWrapper.closeStart);
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
function normalizeVariantPlan(plan, expectedVariants) {
|
||||
if (!plan || typeof plan !== 'object' || Array.isArray(plan)) {
|
||||
throw workerError('worker_output_plan_invalid');
|
||||
@@ -436,6 +562,40 @@ function sanitizeEvent(event) {
|
||||
return copy;
|
||||
}
|
||||
|
||||
function findSessionWrapper(source, sessionId) {
|
||||
const escapedId = escapeRegExp(sessionId);
|
||||
const open = new RegExp(`<div\\b[^>]*\\bdata-impeccable-variants=(?:"${escapedId}"|'${escapedId}')[^>]*>`, 'i');
|
||||
const wrapperOpen = open.exec(source);
|
||||
if (!wrapperOpen) return null;
|
||||
const token = /<div\b[^>]*\/\s*>|<div\b[^>]*>|<\/div\s*>/gi;
|
||||
token.lastIndex = wrapperOpen.index;
|
||||
let depth = 0;
|
||||
let match;
|
||||
while ((match = token.exec(source))) {
|
||||
if (/^<\/div/i.test(match[0])) {
|
||||
depth -= 1;
|
||||
if (depth === 0) {
|
||||
const lineStart = source.lastIndexOf('\n', wrapperOpen.index) + 1;
|
||||
const indent = source.slice(lineStart, wrapperOpen.index).match(/^\s*/)?.[0] || '';
|
||||
return {
|
||||
openStart: wrapperOpen.index,
|
||||
closeStart: match.index,
|
||||
closeEnd: token.lastIndex,
|
||||
indent,
|
||||
};
|
||||
}
|
||||
} else if (!/\/\s*>$/.test(match[0])) {
|
||||
depth += 1;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractSourceVariantBlock(source, variantId) {
|
||||
const attr = escapeRegExp(String(variantId));
|
||||
return new RegExp(`<div\\b[^>]*\\bdata-impeccable-variant=(?:"${attr}"|'${attr}')[^>]*>`, 'i').test(source);
|
||||
}
|
||||
|
||||
function parseWorkerJson(value) {
|
||||
const text = String(value || '').trim().replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/, '');
|
||||
try {
|
||||
|
||||
@@ -455,7 +455,6 @@ describe('Codex Live worker supervisor ownership and lifecycle', () => {
|
||||
generationEpoch: 1,
|
||||
});
|
||||
const first = '<main><div data-impeccable-variants="codexprogress"><style data-impeccable-css="codexprogress">@scope ([data-impeccable-variant="1"]) { h1 { color: red; } }</style><div data-impeccable-variant="original"><h1>Original</h1></div><div data-impeccable-variant="1"><h1>One</h1></div></div></main>';
|
||||
const second = '<main><div data-impeccable-variants="codexprogress"><style data-impeccable-css="codexprogress">@scope ([data-impeccable-variant="1"]) { h1 { color: red; } }\n@scope ([data-impeccable-variant="2"]) { h1 { color: green; } }</style><div data-impeccable-variant="original"><h1>Original</h1></div><div data-impeccable-variant="1"><h1>Mutated One</h1></div><div data-impeccable-variant="2"><h1>Two</h1></div></div></main>';
|
||||
const final = '<main><div data-impeccable-variants="codexprogress"><style data-impeccable-css="codexprogress">@scope ([data-impeccable-variant="1"]) { h1 { color: red; } }\n@scope ([data-impeccable-variant="2"]) { h1 { color: green; } }\n@scope ([data-impeccable-variant="3"]) { h1 { color: blue; } }</style><div data-impeccable-variant="original"><h1>Original</h1></div><div data-impeccable-variant="1"><h1>Mutated One again</h1></div><div data-impeccable-variant="2"><h1>Mutated Two</h1></div><div data-impeccable-variant="3"><h1>Three</h1></div></div></main>';
|
||||
const client = fakeClient();
|
||||
let turn = 0;
|
||||
@@ -473,11 +472,21 @@ describe('Codex Live worker supervisor ownership and lifecycle', () => {
|
||||
onStarted?.(`turn-${turn}`);
|
||||
const prompt = input.find((item) => item.type === 'text').text;
|
||||
prompts.push(prompt);
|
||||
const artifactPath = JSON.parse(prompt.match(/Return exactly one file whose path is ("[^"]+")/)[1]);
|
||||
const message = JSON.stringify({
|
||||
files: [{ path: artifactPath, content: turn === 1 ? first : turn === 2 ? second : final }],
|
||||
...(turn === 1 ? { plan } : {}),
|
||||
});
|
||||
const message = turn === 2
|
||||
? JSON.stringify({
|
||||
sourceDelta: {
|
||||
variantId: 2,
|
||||
markup: '<h1>Two</h1>',
|
||||
css: '@scope ([data-impeccable-variant="2"]) { h1 { color: green; } }',
|
||||
},
|
||||
})
|
||||
: (() => {
|
||||
const artifactPath = JSON.parse(prompt.match(/Return exactly one file whose path is ("[^"]+")/)[1]);
|
||||
return JSON.stringify({
|
||||
files: [{ path: artifactPath, content: turn === 1 ? first : final }],
|
||||
...(turn === 1 ? { plan } : {}),
|
||||
});
|
||||
})();
|
||||
await Promise.all([
|
||||
onAgentMessage?.(message),
|
||||
onAgentMessage?.(message),
|
||||
@@ -507,7 +516,7 @@ describe('Codex Live worker supervisor ownership and lifecycle', () => {
|
||||
id: sessionId,
|
||||
count: 3,
|
||||
action: 'impeccable',
|
||||
scaffold: { file: 'src/App.jsx' },
|
||||
scaffold: { file: 'src/App.jsx', styleMode: 'scoped' },
|
||||
});
|
||||
|
||||
assert.equal(checkpoints.length, 3);
|
||||
|
||||
@@ -234,6 +234,10 @@ describe('Codex Live worker structured artifact boundary', () => {
|
||||
assert.deepEqual(finalSchema.required, ['files']);
|
||||
assert.equal(finalSchema.properties.plan, undefined, 'strict schemas cannot expose optional properties');
|
||||
assert.deepEqual(codexWorkerOutputSchemaForPhase('atomic', 1).required, ['files']);
|
||||
assert.deepEqual(
|
||||
codexWorkerOutputSchemaForPhase('second', 3, { sourceDelta: true }).required,
|
||||
['sourceDelta'],
|
||||
);
|
||||
});
|
||||
|
||||
it('writes only the prepared source artifact path', () => {
|
||||
@@ -263,6 +267,105 @@ describe('Codex Live worker structured artifact boundary', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('merges a fenced variant 2 delta without letting the model resend variant 1', () => {
|
||||
const cwd = mkdtempSync(path.join(tmpdir(), 'codex-worker-source-delta-'));
|
||||
const artifact = path.join(cwd, '.impeccable/live/artifacts/session-r2.jsx');
|
||||
mkdirSync(path.dirname(artifact), { recursive: true });
|
||||
const before = [
|
||||
'<main>',
|
||||
' <div data-impeccable-variants="session" data-impeccable-variant-count="3" style={{ display: "contents" }}>',
|
||||
' <style data-impeccable-css="session">{`',
|
||||
'@scope ([data-impeccable-variant="1"]) { :scope > .one { color: red; } }',
|
||||
'`}</style>',
|
||||
' <div data-impeccable-variant="original"><h1>Original</h1></div>',
|
||||
' <div data-impeccable-variant="1"><h1 className="one">Immutable</h1></div>',
|
||||
' </div>',
|
||||
'</main>',
|
||||
].join('\n');
|
||||
writeFileSync(artifact, before);
|
||||
const prepared = { artifactFile: '.impeccable/live/artifacts/session-r2.jsx' };
|
||||
|
||||
applyCodexWorkerOutput({
|
||||
output: {
|
||||
sourceDelta: {
|
||||
variantId: 2,
|
||||
markup: '<article className="two"><h1>Two</h1></article>',
|
||||
css: '@scope ([data-impeccable-variant="2"]) { :scope > .two { color: green; } }',
|
||||
},
|
||||
},
|
||||
prepared,
|
||||
phase: 'second',
|
||||
expectedVariants: 3,
|
||||
sessionId: 'session',
|
||||
scaffold: { styleMode: 'scoped' },
|
||||
cwd,
|
||||
});
|
||||
|
||||
const after = readFileSync(artifact, 'utf-8');
|
||||
assert.match(after, /<h1 className="one">Immutable<\/h1>/);
|
||||
assert.match(after, /data-impeccable-variant="2"/);
|
||||
assert.match(after, /<article className="two"><h1>Two<\/h1><\/article>/);
|
||||
assert.match(after, /@scope \(\[data-impeccable-variant="2"\]\)/);
|
||||
assert.equal((after.match(/data-impeccable-variant="1"/g) || []).length, 2);
|
||||
|
||||
assert.throws(() => applyCodexWorkerOutput({
|
||||
output: {
|
||||
sourceDelta: {
|
||||
variantId: 2,
|
||||
markup: '<article>Unsafe</article>',
|
||||
css: '@scope ([data-impeccable-variant="1"]) { :scope { color: hotpink; } }',
|
||||
},
|
||||
},
|
||||
prepared: { ...prepared, artifactFile: prepared.artifactFile },
|
||||
phase: 'second',
|
||||
expectedVariants: 3,
|
||||
sessionId: 'session',
|
||||
scaffold: { styleMode: 'scoped' },
|
||||
cwd,
|
||||
}), /worker_output_source_delta_css_unfenced/);
|
||||
});
|
||||
|
||||
it('merges Astro global-prefixed deltas without introducing scoped CSS', () => {
|
||||
const cwd = mkdtempSync(path.join(tmpdir(), 'codex-worker-astro-delta-'));
|
||||
const artifact = path.join(cwd, '.impeccable/live/artifacts/session-r2.astro');
|
||||
mkdirSync(path.dirname(artifact), { recursive: true });
|
||||
writeFileSync(artifact, [
|
||||
'<main>',
|
||||
' <!-- impeccable-variants-start session -->',
|
||||
' <div data-impeccable-variants="session" data-impeccable-variant-count="3" style="display: contents">',
|
||||
' <style is:inline data-impeccable-css="session">',
|
||||
' [data-impeccable-variant="1"] > .one { color: red; }',
|
||||
' </style>',
|
||||
' <div data-impeccable-variant="original"><h1>Original</h1></div>',
|
||||
' <div data-impeccable-variant="1"><h1 class="one">One</h1></div>',
|
||||
' </div>',
|
||||
' <!-- impeccable-variants-end session -->',
|
||||
'</main>',
|
||||
].join('\n'));
|
||||
|
||||
applyCodexWorkerOutput({
|
||||
output: {
|
||||
sourceDelta: {
|
||||
variantId: 2,
|
||||
markup: '<article class="two"><h1>Two</h1></article>',
|
||||
css: '[data-impeccable-variant="2"] > .two { color: green; }',
|
||||
},
|
||||
},
|
||||
prepared: { artifactFile: '.impeccable/live/artifacts/session-r2.astro' },
|
||||
phase: 'second',
|
||||
expectedVariants: 3,
|
||||
sessionId: 'session',
|
||||
scaffold: { styleMode: 'astro-global-prefixed' },
|
||||
cwd,
|
||||
});
|
||||
|
||||
const after = readFileSync(artifact, 'utf-8');
|
||||
assert.match(after, /\[data-impeccable-variant="2"\] > \.two/);
|
||||
assert.match(after, /<div data-impeccable-variant="2">/);
|
||||
assert.doesNotMatch(after, /@scope/);
|
||||
assert.match(after, /<!-- impeccable-variants-end session -->/);
|
||||
});
|
||||
|
||||
it('never lets a final component turn rewrite arrived variant 1', () => {
|
||||
const cwd = mkdtempSync(path.join(tmpdir(), 'codex-worker-component-'));
|
||||
const componentDir = path.join(cwd, '.impeccable/live/artifacts/session-r2-svelte');
|
||||
|
||||
Reference in New Issue
Block a user