@lesliechan721/agent-skill-eval 0.1.0-beta.38 → 0.1.0-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/codex-workflow-evaluation.d.ts +16 -1
- package/dist/codex-workflow-evaluation.js +40 -5
- package/dist/codex-workflow-evaluation.js.map +1 -1
- package/dist/codex-workflow-fixtures.d.ts +37 -0
- package/dist/codex-workflow-fixtures.js +144 -0
- package/dist/codex-workflow-fixtures.js.map +1 -0
- package/dist/codex-workflow.d.ts +32 -4
- package/dist/codex-workflow.js +249 -10
- package/dist/codex-workflow.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/instruction-v2.d.ts +53 -0
- package/dist/instruction-v2.js +169 -0
- package/dist/instruction-v2.js.map +1 -0
- package/dist/json-schema.js +9 -0
- package/dist/json-schema.js.map +1 -1
- package/dist/schemas/digests.json +5 -1
- package/dist/schemas/instruction-v2-receipt.schema.json +24 -0
- package/dist/schemas/instruction-v2-request.schema.json +51 -0
- package/dist/schemas/workflow-evaluation.schema.json +38 -0
- package/dist/schemas/workflow-fixture-action.schema.json +15 -0
- package/dist/types.d.ts +1 -1
- package/package.json +3 -3
package/dist/codex-workflow.js
CHANGED
|
@@ -5,11 +5,13 @@ import fs from 'fs-extra';
|
|
|
5
5
|
import { CodexEvalAttemptControl, EvalAppServerSession, extractAppServerThreadId, assertHostReadContainmentAvailable, hostReadContainmentProfile, } from './codex-eval-app-server.js';
|
|
6
6
|
import { applyCodexEvalProviderEnvironment, createCodexEvalTemporaryRoot, materializeCodexEvalRuntimeHome, redactCodexEvalValue, } from './codex-eval-runtime-config.js';
|
|
7
7
|
import { applyCodexEvalGitIsolation } from './codex-eval-isolation.js';
|
|
8
|
+
import { parseInstructionV2ReasoningEffort, parseInstructionV2Receipt, parseInstructionV2Transport, } from './instruction-v2.js';
|
|
8
9
|
import { runProviderProcess } from './process.js';
|
|
9
10
|
import { assertProviderRunPaths } from './run-paths.js';
|
|
10
11
|
import { parseEvalProviderGrade, } from './custom-process.js';
|
|
11
12
|
import { createCodexGrader, parseConversationGraderOutput } from './providers.js';
|
|
12
13
|
import { parseWorkflowEvaluation, normalizeWorkflowChecks, WorkflowEvaluation, } from './codex-workflow-evaluation.js';
|
|
14
|
+
import { runWorkflowFixtureAction, validateWorkflowFixtureActions } from './codex-workflow-fixtures.js';
|
|
13
15
|
const MAX_ADAPTER_OUTPUT_BYTES = 4 * 1024 * 1024;
|
|
14
16
|
const MAX_REQUEST_TEXT_BYTES = 200_000;
|
|
15
17
|
const MAX_ROLE_COUNT = 32;
|
|
@@ -70,10 +72,10 @@ async function assertWorkspaceRoleFile(workspace, relative) {
|
|
|
70
72
|
throw new Error(`workflow role configFile must be a regular file: ${relative}`);
|
|
71
73
|
}
|
|
72
74
|
}
|
|
73
|
-
export async function parseCodexWorkflowRequest(value, allowedModels, workspace) {
|
|
75
|
+
export async function parseCodexWorkflowRequest(value, allowedModels, workspace, fixtures) {
|
|
74
76
|
if (!isRecord(value))
|
|
75
77
|
throw new Error('workflow prepare stdout must be one JSON object.');
|
|
76
|
-
exactKeys(value, ['version', 'prompt', 'sandbox', 'model', 'developerInstructions', 'roles', 'multiAgent'], ['evaluation'], 'workflow prepare stdout');
|
|
78
|
+
exactKeys(value, ['version', 'prompt', 'sandbox', 'model', 'developerInstructions', 'roles', 'multiAgent'], ['evaluation', 'transport', 'reasoningEffort'], 'workflow prepare stdout');
|
|
77
79
|
if (value.version !== 1)
|
|
78
80
|
throw new Error('workflow prepare stdout version must be 1.');
|
|
79
81
|
if (value.sandbox !== 'read-only' && value.sandbox !== 'workspace-write') {
|
|
@@ -121,14 +123,16 @@ export async function parseCodexWorkflowRequest(value, allowedModels, workspace)
|
|
|
121
123
|
if (multiAgent.protocol === 'v1'
|
|
122
124
|
&& (multiAgent.hideSpawnAgentMetadata || multiAgent.exposeSpawnAgentModelOverrides))
|
|
123
125
|
throw new Error('workflow request V1 metadata fields must be false.');
|
|
124
|
-
|
|
126
|
+
const request = {
|
|
125
127
|
version: 1,
|
|
126
128
|
prompt: boundedString(value.prompt, 'workflow request prompt', MAX_REQUEST_TEXT_BYTES),
|
|
127
129
|
sandbox: value.sandbox,
|
|
128
130
|
model: value.model,
|
|
131
|
+
...(value.reasoningEffort === undefined ? {} : { reasoningEffort: parseInstructionV2ReasoningEffort(value.reasoningEffort) }),
|
|
129
132
|
developerInstructions: boundedString(value.developerInstructions, 'workflow request developerInstructions', MAX_REQUEST_TEXT_BYTES),
|
|
130
133
|
roles,
|
|
131
134
|
...(value.evaluation === undefined ? {} : { evaluation: parseWorkflowEvaluation(value.evaluation) }),
|
|
135
|
+
...(value.transport === undefined ? {} : { transport: await parseInstructionV2Transport(value.transport, workspace) }),
|
|
132
136
|
multiAgent: {
|
|
133
137
|
protocol: multiAgent.protocol,
|
|
134
138
|
maxDepth: multiAgent.maxDepth,
|
|
@@ -136,6 +140,28 @@ export async function parseCodexWorkflowRequest(value, allowedModels, workspace)
|
|
|
136
140
|
exposeSpawnAgentModelOverrides: multiAgent.exposeSpawnAgentModelOverrides,
|
|
137
141
|
},
|
|
138
142
|
};
|
|
143
|
+
if (request.transport) {
|
|
144
|
+
const external = request.transport.request;
|
|
145
|
+
if (external.instructions.text !== request.developerInstructions || external.task !== request.prompt
|
|
146
|
+
|| external.run.access !== request.sandbox || (external.run.model ?? null) !== request.model
|
|
147
|
+
|| external.run.reasoningEffort !== request.reasoningEffort) {
|
|
148
|
+
throw new Error('instruction-v2 request must match workflow instructions, task, access, model, and reasoningEffort.');
|
|
149
|
+
}
|
|
150
|
+
if (request.evaluation?.interactions.length || request.evaluation?.setupPrompt !== undefined) {
|
|
151
|
+
throw new Error('instruction-v2 transport does not support evaluation interactions or setupPrompt.');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const actions = [
|
|
155
|
+
...(request.evaluation?.setupActions ?? []),
|
|
156
|
+
...(request.evaluation?.finalActions ?? []),
|
|
157
|
+
...(request.evaluation?.interactions.flatMap((interaction) => interaction.action ? [interaction.action] : []) ?? []),
|
|
158
|
+
];
|
|
159
|
+
if (actions.length) {
|
|
160
|
+
if (!fixtures)
|
|
161
|
+
throw new Error('workflow fixture actions require the Eval-owned fixture root.');
|
|
162
|
+
await validateWorkflowFixtureActions(actions, fixtures);
|
|
163
|
+
}
|
|
164
|
+
return request;
|
|
139
165
|
}
|
|
140
166
|
function parseJsonObject(stdout, label) {
|
|
141
167
|
let value;
|
|
@@ -295,6 +321,7 @@ function workflowConfig(request, workspace) {
|
|
|
295
321
|
`features.multi_agent_v2.expose_spawn_agent_model_overrides=${String(request.multiAgent.exposeSpawnAgentModelOverrides)}`,
|
|
296
322
|
`agents.max_depth=${request.multiAgent.maxDepth}`,
|
|
297
323
|
`developer_instructions=${configValue(request.developerInstructions)}`,
|
|
324
|
+
...(request.reasoningEffort ? [`model_reasoning_effort=${configValue(request.reasoningEffort)}`] : []),
|
|
298
325
|
...request.roles.flatMap((role) => [
|
|
299
326
|
`agents.${role.name}.description=${configValue(role.description)}`,
|
|
300
327
|
`agents.${role.name}.config_file=${configValue(path.join(workspace, role.configFile))}`,
|
|
@@ -1478,6 +1505,203 @@ function sandboxPolicy(request) {
|
|
|
1478
1505
|
excludeSlashTmp: false,
|
|
1479
1506
|
};
|
|
1480
1507
|
}
|
|
1508
|
+
function workflowFixtureRunner(input, control) {
|
|
1509
|
+
return (action) => runWorkflowFixtureAction({
|
|
1510
|
+
action, workspace: input.input.workspacePath, fixtures: input.input.fixturesPath,
|
|
1511
|
+
output: input.input.outputDir, evalRoot: input.evalRoot, sourceEnv: input.sourceEnv, runtime: input.codexRuntime,
|
|
1512
|
+
timeoutMs: control.remaining('workflow fixture action'), signal: control.signal,
|
|
1513
|
+
processManagement: input.processManagement,
|
|
1514
|
+
...(input.processTree ? { processTree: input.processTree } : {}),
|
|
1515
|
+
...(input.protectedEvalRoots ? { protectedEvalRoots: input.protectedEvalRoots } : {}),
|
|
1516
|
+
});
|
|
1517
|
+
}
|
|
1518
|
+
async function readInstructionV2File(root, relative, limit) {
|
|
1519
|
+
relativeWorkspacePath(relative, 'instruction-v2 capture path');
|
|
1520
|
+
let target = root;
|
|
1521
|
+
for (const part of relative.split('/')) {
|
|
1522
|
+
target = path.join(target, part);
|
|
1523
|
+
if ((await fs.lstat(target)).isSymbolicLink())
|
|
1524
|
+
throw new Error('instruction-v2 capture must not contain symbolic links.');
|
|
1525
|
+
}
|
|
1526
|
+
const stat = await fs.lstat(target);
|
|
1527
|
+
if (!stat.isFile() || stat.size > limit)
|
|
1528
|
+
throw new Error('instruction-v2 capture is not a bounded regular file.');
|
|
1529
|
+
return fs.readFile(target, 'utf8');
|
|
1530
|
+
}
|
|
1531
|
+
const instructionV2Transport = {
|
|
1532
|
+
async run(input) {
|
|
1533
|
+
const selected = input.request.transport;
|
|
1534
|
+
if (!path.isAbsolute(input.codexBin))
|
|
1535
|
+
throw new Error('instruction-v2 requires the Engine-resolved absolute Codex executable.');
|
|
1536
|
+
const control = new CodexEvalAttemptControl({
|
|
1537
|
+
label: 'instruction-v2 workflow', timeoutMs: input.timeoutMs,
|
|
1538
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
1539
|
+
});
|
|
1540
|
+
const temporaryRoot = await createCodexEvalTemporaryRoot('instruction-v2-workflow-');
|
|
1541
|
+
const runtimeRoot = await fs.realpath(temporaryRoot.root);
|
|
1542
|
+
const codexHome = path.join(runtimeRoot, 'codex-home');
|
|
1543
|
+
const runDirectory = path.join(runtimeRoot, 'run');
|
|
1544
|
+
const env = {
|
|
1545
|
+
...buildEngineEnvironment(input.sourceEnv, runtimeRoot, codexHome, input.codexRuntime),
|
|
1546
|
+
AW_SUBAGENT_RUN_DIR: runDirectory,
|
|
1547
|
+
AW_SUBAGENT_RESULT_FILE: path.join(runDirectory, 'result.json'),
|
|
1548
|
+
AW_SUBAGENT_TRACE_FILE: path.join(runDirectory, 'codex-events.jsonl'),
|
|
1549
|
+
AW_SUBAGENT_CODEX_BINARY: input.codexBin,
|
|
1550
|
+
};
|
|
1551
|
+
const startedAt = Date.now();
|
|
1552
|
+
let cleaned = false;
|
|
1553
|
+
let judgeNumber = 0;
|
|
1554
|
+
const judgeUsage = [];
|
|
1555
|
+
const grader = input.request.evaluation ? createCodexGrader({
|
|
1556
|
+
sourceEnv: input.sourceEnv, codexRuntime: input.codexRuntime, codexBin: input.codexBin,
|
|
1557
|
+
...(input.request.model ? { model: input.request.model } : {}), processManagement: input.processManagement,
|
|
1558
|
+
}) : undefined;
|
|
1559
|
+
const evaluation = input.request.evaluation ? new WorkflowEvaluation(input.request.evaluation, input.input.workspacePath, async (prompt) => {
|
|
1560
|
+
const outputDir = path.join(input.input.outputDir, 'workflow-judges', String(++judgeNumber));
|
|
1561
|
+
await fs.ensureDir(outputDir);
|
|
1562
|
+
const result = await grader({ prompt, outputDir, timeoutMs: control.remaining('external semantic check'), signal: control.signal });
|
|
1563
|
+
if (!result.mechanicalPassed)
|
|
1564
|
+
throw new Error('external workflow semantic grader did not complete its read-only checks.');
|
|
1565
|
+
judgeUsage.push(result.usage);
|
|
1566
|
+
return parseConversationGraderOutput(result.output);
|
|
1567
|
+
}, workflowFixtureRunner(input, control)) : undefined;
|
|
1568
|
+
try {
|
|
1569
|
+
await Promise.all([
|
|
1570
|
+
fs.ensureDir(env.HOME), fs.ensureDir(env.TMPDIR), fs.mkdir(runDirectory, { mode: 0o700 }),
|
|
1571
|
+
materializeCodexEvalRuntimeHome(input.codexRuntime, codexHome, { trustedProject: input.input.workspacePath }),
|
|
1572
|
+
]);
|
|
1573
|
+
await evaluation?.runSetupActions();
|
|
1574
|
+
const before = await snapshotWorkspace(input.input.workspacePath);
|
|
1575
|
+
let containment;
|
|
1576
|
+
if (input.request.evaluation) {
|
|
1577
|
+
containment = hostReadContainmentProfile({
|
|
1578
|
+
forbiddenHostRoots: [input.input.fixturesPath, input.input.outputDir],
|
|
1579
|
+
writableRoots: [runtimeRoot, input.input.workspacePath],
|
|
1580
|
+
unwritableRoots: input.request.sandbox === 'read-only' ? [input.input.workspacePath] : [],
|
|
1581
|
+
}) + '\n' + [...new Set([input.evalRoot, ...(input.protectedEvalRoots ?? [])])].map((root) => `(deny file-read* (require-all (subpath ${JSON.stringify(root)}) (require-not (subpath ${JSON.stringify(input.input.workspacePath)}))))`).join('\n');
|
|
1582
|
+
for (let ancestor = path.dirname(input.input.workspacePath); ancestor !== path.dirname(ancestor); ancestor = path.dirname(ancestor)) {
|
|
1583
|
+
containment += `\n(allow file-read-metadata (literal ${JSON.stringify(ancestor)}))`;
|
|
1584
|
+
}
|
|
1585
|
+
await assertHostReadContainmentAvailable(containment);
|
|
1586
|
+
}
|
|
1587
|
+
evaluation?.observe({ method: 'evaluation/externalSubmission', runId: selected.request.run.id }, null);
|
|
1588
|
+
const processResult = await runProviderProcess({
|
|
1589
|
+
executable: containment ? '/usr/bin/sandbox-exec' : selected.command[0],
|
|
1590
|
+
args: containment ? ['-p', containment, ...selected.command] : [...selected.command.slice(1)],
|
|
1591
|
+
cwd: input.input.workspacePath, env, stdin: JSON.stringify(selected.request),
|
|
1592
|
+
timeoutMs: control.remaining('external execution'), maxBufferBytes: MAX_ADAPTER_OUTPUT_BYTES,
|
|
1593
|
+
signal: control.signal,
|
|
1594
|
+
}, {}, {
|
|
1595
|
+
containment: input.processManagement.mode === 'unmanaged-confirmed' ? 'unmanaged-confirmed' : 'verified-observed',
|
|
1596
|
+
...(input.processManagement.mode === 'unmanaged-confirmed' ? {} : { processTree: input.processTree }),
|
|
1597
|
+
});
|
|
1598
|
+
let receipt = null;
|
|
1599
|
+
let diagnostic = null;
|
|
1600
|
+
try {
|
|
1601
|
+
receipt = parseInstructionV2Receipt(JSON.parse(await readInstructionV2File(runDirectory, 'result.json', 64 * 1024)));
|
|
1602
|
+
}
|
|
1603
|
+
catch (error) {
|
|
1604
|
+
diagnostic = `External result receipt unavailable: ${error.message}`;
|
|
1605
|
+
}
|
|
1606
|
+
const trace = [];
|
|
1607
|
+
if (receipt?.traceFile) {
|
|
1608
|
+
try {
|
|
1609
|
+
const raw = await readInstructionV2File(runDirectory, receipt.traceFile, 8 * 1024 * 1024);
|
|
1610
|
+
const lines = raw.split(/\r?\n/u).filter((line) => line.trim());
|
|
1611
|
+
if (lines.length > 5_000)
|
|
1612
|
+
throw new Error('instruction-v2 trace event limit exceeded.');
|
|
1613
|
+
for (const line of lines)
|
|
1614
|
+
trace.push(JSON.parse(line));
|
|
1615
|
+
}
|
|
1616
|
+
catch (error) {
|
|
1617
|
+
diagnostic ??= `External trace unavailable: ${error.message}`;
|
|
1618
|
+
trace.length = 0;
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
const completed = receipt?.outcome === 'completed' && receipt.providerTerminal === 'turn.completed'
|
|
1622
|
+
&& receipt.instructionChannel !== 'user-prefix'
|
|
1623
|
+
&& receipt.instructionsRevision === selected.request.instructions.revision
|
|
1624
|
+
&& processResult.exitCode === 0 && processResult.signal === null
|
|
1625
|
+
&& !processResult.timedOut && !processResult.cancelled && !processResult.maxBufferExceeded
|
|
1626
|
+
&& receipt.generationStarted !== false && receipt.scopeViolation !== true
|
|
1627
|
+
&& (receipt.localExitCode === undefined || receipt.localExitCode === 0)
|
|
1628
|
+
&& (input.processManagement.mode === 'unmanaged-confirmed' || processResult.gradingEvidenceAccepted)
|
|
1629
|
+
&& processResult.stdout.trim() !== '';
|
|
1630
|
+
const status = completed ? 'completed' : receipt?.outcome === 'failed'
|
|
1631
|
+
&& (receipt.providerTerminal === 'turn.failed' || receipt.generationStarted === false) ? 'failed' : 'unknown';
|
|
1632
|
+
if (!completed)
|
|
1633
|
+
diagnostic ??= 'External execution lacks compatible channel, instruction revision, terminal, normal exit, or final text evidence.';
|
|
1634
|
+
const after = await snapshotWorkspace(input.input.workspacePath);
|
|
1635
|
+
await temporaryRoot.cleanup();
|
|
1636
|
+
cleaned = true;
|
|
1637
|
+
const usage = standardUsage(receipt?.usage);
|
|
1638
|
+
const evidence = {
|
|
1639
|
+
version: 1, rootThreadId: receipt?.providerSessionId ?? selected.request.run.id,
|
|
1640
|
+
completion: { status, turnStatus: receipt?.providerTerminal ?? 'unknown', durationMs: Date.now() - startedAt },
|
|
1641
|
+
termination: {
|
|
1642
|
+
reason: status,
|
|
1643
|
+
providerProcessCleanupConfirmed: input.processManagement.mode !== 'unmanaged-confirmed'
|
|
1644
|
+
&& processResult.gradingEvidenceAccepted,
|
|
1645
|
+
},
|
|
1646
|
+
usage, finalMessage: processResult.stdout, workspaceDiff: workspaceDiff(before, after),
|
|
1647
|
+
skillLoads: [], threadGraph: [], collaborationCalls: [], leafCalls: [],
|
|
1648
|
+
cleanup: { isolatedCodexHomeRemoved: true },
|
|
1649
|
+
transport: {
|
|
1650
|
+
type: 'instruction-v2', request: selected.request, command: selected.command, receipt,
|
|
1651
|
+
traceAvailable: trace.length > 0,
|
|
1652
|
+
observationLimits: [
|
|
1653
|
+
'Provider JSONL events are captured as supplied; complete file-access attribution and nested delegation coverage are not established.',
|
|
1654
|
+
'A file diff proves observed final content, not absence of intermediate writes. Model statements do not prove read-only behavior, independent history, or OS isolation.',
|
|
1655
|
+
'Provider trace is read after process exit. Artifact snapshots measure before submission and after cleanup; replayed event order does not supply intermediate snapshots.',
|
|
1656
|
+
],
|
|
1657
|
+
diagnostic, exitCode: processResult.exitCode, signal: processResult.signal, stderr: processResult.stderr,
|
|
1658
|
+
},
|
|
1659
|
+
};
|
|
1660
|
+
if (completed && evaluation) {
|
|
1661
|
+
for (const frame of trace)
|
|
1662
|
+
evaluation.observe({ method: 'evaluation/externalTraceCapture', capturedAfterExit: true, frame }, evidence.rootThreadId);
|
|
1663
|
+
const messages = [
|
|
1664
|
+
{ type: 'response_item', payload: { type: 'message', role: 'user', content: [{ type: 'input_text', text: selected.request.task }] } },
|
|
1665
|
+
...trace,
|
|
1666
|
+
{ type: 'response_item', payload: { type: 'agent_message', text: processResult.stdout } },
|
|
1667
|
+
];
|
|
1668
|
+
try {
|
|
1669
|
+
evidence.evaluation = await evaluation.finish(evidence, messages);
|
|
1670
|
+
if (!trace.length) {
|
|
1671
|
+
evidence.evaluation.complete = false;
|
|
1672
|
+
evidence.evaluation.checks = evaluation.request.checks.map(({ name }) => ({
|
|
1673
|
+
name, verdict: 'unknown', evidence: 'External provider tool trace is unavailable; behavior assertions cannot be established from final text.',
|
|
1674
|
+
}));
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
catch (error) {
|
|
1678
|
+
evidence.evaluation = {
|
|
1679
|
+
complete: false, checks: [], observations: evaluation.observations,
|
|
1680
|
+
snapshots: evaluation.snapshots, decisions: evaluation.decisions,
|
|
1681
|
+
fixtureActions: evaluation.fixtureActions, measurementStart: evaluation.measurementStart,
|
|
1682
|
+
};
|
|
1683
|
+
await writeWorkflowArtifacts(input.input.outputDir, redactCodexEvalValue({ evidence, trace, modelOutput: processResult.stdout, usage }, input.codexRuntime));
|
|
1684
|
+
throw error;
|
|
1685
|
+
}
|
|
1686
|
+
const totals = [usage, ...judgeUsage].map(standardUsage);
|
|
1687
|
+
evidence.usage = totals.every((value) => value !== null) ? {
|
|
1688
|
+
inputTokens: totals.reduce((sum, value) => sum + value.inputTokens, 0),
|
|
1689
|
+
outputTokens: totals.reduce((sum, value) => sum + value.outputTokens, 0),
|
|
1690
|
+
} : null;
|
|
1691
|
+
}
|
|
1692
|
+
return redactCodexEvalValue({ evidence, trace, modelOutput: processResult.stdout, usage: evidence.usage }, input.codexRuntime);
|
|
1693
|
+
}
|
|
1694
|
+
finally {
|
|
1695
|
+
try {
|
|
1696
|
+
if (!cleaned)
|
|
1697
|
+
await temporaryRoot.cleanup();
|
|
1698
|
+
}
|
|
1699
|
+
finally {
|
|
1700
|
+
control.dispose();
|
|
1701
|
+
}
|
|
1702
|
+
}
|
|
1703
|
+
},
|
|
1704
|
+
};
|
|
1481
1705
|
const defaultTransport = {
|
|
1482
1706
|
async run(input) {
|
|
1483
1707
|
const control = new CodexEvalAttemptControl({
|
|
@@ -1489,6 +1713,7 @@ const defaultTransport = {
|
|
|
1489
1713
|
const runtimeRoot = await fs.realpath(temporaryRoot.root);
|
|
1490
1714
|
const codexHome = path.join(runtimeRoot, 'codex-home');
|
|
1491
1715
|
const env = buildEngineEnvironment(input.sourceEnv, runtimeRoot, codexHome, input.codexRuntime);
|
|
1716
|
+
env.AW_SUBAGENT_CODEX_BINARY = input.codexBin;
|
|
1492
1717
|
let session;
|
|
1493
1718
|
let cleanupConfirmed = false;
|
|
1494
1719
|
let codexHomeRemoved = false;
|
|
@@ -1513,7 +1738,7 @@ const defaultTransport = {
|
|
|
1513
1738
|
throw new Error('workflow semantic grader did not complete its read-only checks.');
|
|
1514
1739
|
judgeUsage.push(result.usage);
|
|
1515
1740
|
return parseConversationGraderOutput(result.output);
|
|
1516
|
-
}) : undefined;
|
|
1741
|
+
}, workflowFixtureRunner(input, control)) : undefined;
|
|
1517
1742
|
let removeHandler;
|
|
1518
1743
|
let removeFailureHandler;
|
|
1519
1744
|
try {
|
|
@@ -1524,6 +1749,7 @@ const defaultTransport = {
|
|
|
1524
1749
|
trustedProject: input.input.workspacePath,
|
|
1525
1750
|
}),
|
|
1526
1751
|
]);
|
|
1752
|
+
await evaluation?.runSetupActions();
|
|
1527
1753
|
const before = await snapshotWorkspace(input.input.workspacePath);
|
|
1528
1754
|
let containment;
|
|
1529
1755
|
if (evaluation) {
|
|
@@ -1537,6 +1763,7 @@ const defaultTransport = {
|
|
|
1537
1763
|
}
|
|
1538
1764
|
await assertHostReadContainmentAvailable(containment);
|
|
1539
1765
|
}
|
|
1766
|
+
const configOverrides = workflowConfig(input.request, input.input.workspacePath);
|
|
1540
1767
|
session = new EvalAppServerSession({
|
|
1541
1768
|
codexBin: input.codexBin,
|
|
1542
1769
|
cwd: input.input.workspacePath,
|
|
@@ -1545,7 +1772,7 @@ const defaultTransport = {
|
|
|
1545
1772
|
sensitiveEnvironmentNames: input.codexRuntime.sensitiveEnvironmentNames,
|
|
1546
1773
|
isolation: 'standard',
|
|
1547
1774
|
processManagement: input.processManagement,
|
|
1548
|
-
configOverrides
|
|
1775
|
+
configOverrides,
|
|
1549
1776
|
...(containment ? { hostReadContainmentProfile: containment } : {}),
|
|
1550
1777
|
});
|
|
1551
1778
|
await session.initialize(control.rpcTimeout('initialize'));
|
|
@@ -1723,6 +1950,13 @@ const defaultTransport = {
|
|
|
1723
1950
|
collaborationCalls: rollout.collaborationCalls,
|
|
1724
1951
|
leafCalls: rollout.leafCalls,
|
|
1725
1952
|
cleanup: { isolatedCodexHomeRemoved: true },
|
|
1953
|
+
launch: {
|
|
1954
|
+
instructionChannel: 'developer', developerInstructions: input.request.developerInstructions,
|
|
1955
|
+
instructionsRevision: createHash('sha256').update(input.request.developerInstructions).digest('hex'),
|
|
1956
|
+
model: input.request.model, reasoningEffort: input.request.reasoningEffort ?? null,
|
|
1957
|
+
sandbox: input.request.sandbox, roles: input.request.roles, configOverrides,
|
|
1958
|
+
hostRoleAdoption: 'unknown',
|
|
1959
|
+
},
|
|
1726
1960
|
};
|
|
1727
1961
|
if (evaluation) {
|
|
1728
1962
|
// Subject processes are stopped before final snapshots and independent grading.
|
|
@@ -1733,6 +1967,7 @@ const defaultTransport = {
|
|
|
1733
1967
|
evidence.evaluation = {
|
|
1734
1968
|
complete: false, checks: [], observations: evaluation.observations,
|
|
1735
1969
|
snapshots: evaluation.snapshots, decisions: evaluation.decisions,
|
|
1970
|
+
fixtureActions: evaluation.fixtureActions,
|
|
1736
1971
|
measurementStart: evaluation.measurementStart,
|
|
1737
1972
|
};
|
|
1738
1973
|
await writeWorkflowArtifacts(input.input.outputDir, {
|
|
@@ -1868,13 +2103,13 @@ export async function executeCodexWorkflowProvider(options) {
|
|
|
1868
2103
|
control.throwIfStopped('prepare');
|
|
1869
2104
|
throw error;
|
|
1870
2105
|
}
|
|
1871
|
-
const request = await parseCodexWorkflowRequest(prepared, options.provider.allowedModels, paths.workspacePath);
|
|
1872
|
-
if (request.model === null && request.multiAgent.protocol === 'v1') {
|
|
2106
|
+
const request = await parseCodexWorkflowRequest(prepared, options.provider.allowedModels, paths.workspacePath, paths.fixturesPath);
|
|
2107
|
+
if (!request.transport && request.model === null && request.multiAgent.protocol === 'v1') {
|
|
1873
2108
|
request.model = 'gpt-5.6-luna';
|
|
1874
2109
|
}
|
|
1875
2110
|
let execution;
|
|
1876
2111
|
try {
|
|
1877
|
-
execution = await (options.transport ?? defaultTransport).run({
|
|
2112
|
+
execution = await (options.transport ?? (request.transport ? instructionV2Transport : defaultTransport)).run({
|
|
1878
2113
|
request,
|
|
1879
2114
|
input: { ...options.input, ...paths, timeoutMs: control.remaining('Codex execution') },
|
|
1880
2115
|
evalRoot: paths.evalRoot,
|
|
@@ -1883,6 +2118,7 @@ export async function executeCodexWorkflowProvider(options) {
|
|
|
1883
2118
|
sourceEnv,
|
|
1884
2119
|
timeoutMs: control.remaining('Codex execution'),
|
|
1885
2120
|
processManagement,
|
|
2121
|
+
...(options.processTree ? { processTree: options.processTree } : {}),
|
|
1886
2122
|
...(options.protectedEvalRoots ? { protectedEvalRoots: options.protectedEvalRoots } : {}),
|
|
1887
2123
|
signal: control.signal,
|
|
1888
2124
|
});
|
|
@@ -1891,13 +2127,16 @@ export async function executeCodexWorkflowProvider(options) {
|
|
|
1891
2127
|
control.throwIfStopped('Codex execution');
|
|
1892
2128
|
throw error;
|
|
1893
2129
|
}
|
|
1894
|
-
control.throwIfStopped('evidence collection');
|
|
1895
2130
|
const sanitized = redactCodexEvalValue(execution, options.codexRuntime);
|
|
1896
2131
|
const usage = standardUsage(sanitized.usage);
|
|
1897
|
-
if (!usage || !standardUsage(sanitized.evidence.usage)) {
|
|
2132
|
+
if (!request.transport && (!usage || !standardUsage(sanitized.evidence.usage))) {
|
|
1898
2133
|
throw new Error('codex-workflow completed without required token usage evidence.');
|
|
1899
2134
|
}
|
|
1900
2135
|
await writeWorkflowArtifacts(paths.outputDir, sanitized);
|
|
2136
|
+
control.throwIfStopped('evidence collection');
|
|
2137
|
+
if (sanitized.evidence.completion.status !== 'completed') {
|
|
2138
|
+
throw new Error(`instruction-v2 workflow execution is ${sanitized.evidence.completion.status}; no grade was accepted.`);
|
|
2139
|
+
}
|
|
1901
2140
|
const beforeGrade = await artifactDigests(paths.outputDir);
|
|
1902
2141
|
let gradeValue;
|
|
1903
2142
|
try {
|