@remnic/bench 9.6.19 → 9.6.21
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/README.md +55 -1
- package/dist/index.d.ts +107 -40
- package/dist/index.js +1396 -725
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -5497,17 +5497,473 @@ var BENCHMARK_RESULT_SCHEMA = {
|
|
|
5497
5497
|
|
|
5498
5498
|
// src/repro-manifest.ts
|
|
5499
5499
|
import { execFileSync } from "child_process";
|
|
5500
|
-
import { createHash as
|
|
5500
|
+
import { createHash as createHash4 } from "crypto";
|
|
5501
5501
|
import { createReadStream } from "fs";
|
|
5502
|
-
import { lstat as lstat3, mkdir as
|
|
5503
|
-
import
|
|
5504
|
-
import
|
|
5502
|
+
import { lstat as lstat3, mkdir as mkdir4, readFile as readFile5, readdir as readdir4, readlink, realpath as realpath3, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
5503
|
+
import os3 from "os";
|
|
5504
|
+
import path5 from "path";
|
|
5505
5505
|
|
|
5506
|
-
// src/
|
|
5507
|
-
import {
|
|
5508
|
-
import
|
|
5506
|
+
// src/providers/codex-credit-budget.ts
|
|
5507
|
+
import { createHash as createHash3 } from "crypto";
|
|
5508
|
+
import { mkdir as mkdir2, open, readFile as readFile3, rename as rename2, rmdir, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
|
|
5509
5509
|
import os from "os";
|
|
5510
5510
|
import path3 from "path";
|
|
5511
|
+
var ONE_MILLION = 1e6;
|
|
5512
|
+
var MAX_BOUNDED_CALL_CREDITS = 300;
|
|
5513
|
+
var SOL_MODEL = /^gpt-5\.6-sol$/i;
|
|
5514
|
+
var CREDIT_RATES = [
|
|
5515
|
+
[/^gpt-5\.6-sol$/i, { input: 125, cachedInput: 12.5, output: 750 }],
|
|
5516
|
+
[/^gpt-5\.6-terra$/i, { input: 62.5, cachedInput: 6.25, output: 375 }],
|
|
5517
|
+
[/^gpt-5\.6-luna$/i, { input: 25, cachedInput: 2.5, output: 150 }],
|
|
5518
|
+
[/^gpt-5\.5$/i, { input: 125, cachedInput: 12.5, output: 750 }],
|
|
5519
|
+
[/^gpt-5\.4-mini$/i, { input: 18.75, cachedInput: 1.875, output: 113 }],
|
|
5520
|
+
[/^gpt-5\.4$/i, { input: 62.5, cachedInput: 6.25, output: 375 }],
|
|
5521
|
+
[/^gpt-5\.3-codex$/i, { input: 43.75, cachedInput: 4.375, output: 350 }],
|
|
5522
|
+
[/^gpt-5\.2$/i, { input: 43.75, cachedInput: 4.375, output: 350 }]
|
|
5523
|
+
];
|
|
5524
|
+
var completionQueue = Promise.resolve();
|
|
5525
|
+
var CodexCreditAccountingError = class extends Error {
|
|
5526
|
+
constructor(message) {
|
|
5527
|
+
super(message);
|
|
5528
|
+
this.name = "CodexCreditAccountingError";
|
|
5529
|
+
}
|
|
5530
|
+
};
|
|
5531
|
+
var CodexCreditDispatchError = class extends Error {
|
|
5532
|
+
constructor(message, options) {
|
|
5533
|
+
super(message, options);
|
|
5534
|
+
this.name = "CodexCreditDispatchError";
|
|
5535
|
+
}
|
|
5536
|
+
};
|
|
5537
|
+
function resolveCodexCreditBudgetConfig(env = process.env, fallbackRunId) {
|
|
5538
|
+
const rawBudget = env.REMNIC_BENCH_CODEX_CREDIT_BUDGET?.trim();
|
|
5539
|
+
if (!rawBudget) return void 0;
|
|
5540
|
+
const budgetCredits = parsePositiveNumber(
|
|
5541
|
+
rawBudget,
|
|
5542
|
+
"REMNIC_BENCH_CODEX_CREDIT_BUDGET"
|
|
5543
|
+
);
|
|
5544
|
+
const reserveCredits = parseNonNegativeNumber(
|
|
5545
|
+
env.REMNIC_BENCH_CODEX_CREDIT_RESERVE?.trim() ?? "473",
|
|
5546
|
+
"REMNIC_BENCH_CODEX_CREDIT_RESERVE"
|
|
5547
|
+
);
|
|
5548
|
+
if (reserveCredits >= budgetCredits) {
|
|
5549
|
+
throw new Error(
|
|
5550
|
+
"REMNIC_BENCH_CODEX_CREDIT_RESERVE must be smaller than REMNIC_BENCH_CODEX_CREDIT_BUDGET"
|
|
5551
|
+
);
|
|
5552
|
+
}
|
|
5553
|
+
if (reserveCredits < MAX_BOUNDED_CALL_CREDITS) {
|
|
5554
|
+
throw new Error(
|
|
5555
|
+
`REMNIC_BENCH_CODEX_CREDIT_RESERVE must be at least ${MAX_BOUNDED_CALL_CREDITS} credits to cover the conservative maximum cost of the one serialized in-flight call`
|
|
5556
|
+
);
|
|
5557
|
+
}
|
|
5558
|
+
const ledgerPath = path3.resolve(
|
|
5559
|
+
expandHomeRelativePath(
|
|
5560
|
+
env.REMNIC_BENCH_CODEX_CREDIT_LEDGER?.trim() || ".remnic/bench/codex-credit-ledger.json"
|
|
5561
|
+
)
|
|
5562
|
+
);
|
|
5563
|
+
const runId = parseOptionalRunId(env.REMNIC_BENCH_RUN_ID) ?? parseOptionalRunId(fallbackRunId);
|
|
5564
|
+
return {
|
|
5565
|
+
budgetCredits,
|
|
5566
|
+
reserveCredits,
|
|
5567
|
+
ledgerPath,
|
|
5568
|
+
allowSol: /^(?:1|true|yes|on)$/i.test(
|
|
5569
|
+
env.REMNIC_BENCH_CODEX_ALLOW_SOL?.trim() ?? ""
|
|
5570
|
+
),
|
|
5571
|
+
...runId ? { runId } : {}
|
|
5572
|
+
};
|
|
5573
|
+
}
|
|
5574
|
+
async function runWithinCodexCreditBudget(args) {
|
|
5575
|
+
if (!args.config) {
|
|
5576
|
+
return (await args.run()).value;
|
|
5577
|
+
}
|
|
5578
|
+
const previous = completionQueue;
|
|
5579
|
+
let release;
|
|
5580
|
+
completionQueue = new Promise((resolve) => {
|
|
5581
|
+
release = resolve;
|
|
5582
|
+
});
|
|
5583
|
+
await previous;
|
|
5584
|
+
const lockPath = `${args.config.ledgerPath}.lock`;
|
|
5585
|
+
let lock;
|
|
5586
|
+
let dispatchStarted = false;
|
|
5587
|
+
let accountingSettled = false;
|
|
5588
|
+
try {
|
|
5589
|
+
await mkdir2(path3.dirname(lockPath), { recursive: true, mode: 448 });
|
|
5590
|
+
lock = await acquireLedgerLock(lockPath);
|
|
5591
|
+
assertModelAllowed(args.model, args.config);
|
|
5592
|
+
const ledger = await readLedger(args.config);
|
|
5593
|
+
if (ledger.blockedReason) {
|
|
5594
|
+
throw new Error(
|
|
5595
|
+
`Codex credit ledger is blocked pending manual reconciliation: ${ledger.blockedReason}`
|
|
5596
|
+
);
|
|
5597
|
+
}
|
|
5598
|
+
const usableCredits = args.config.budgetCredits - args.config.reserveCredits;
|
|
5599
|
+
const dispatchHeadroom = usableCredits - ledger.spentCredits;
|
|
5600
|
+
if (dispatchHeadroom < MAX_BOUNDED_CALL_CREDITS) {
|
|
5601
|
+
throw new Error(
|
|
5602
|
+
`Codex credit budget cannot safely dispatch another call: ${ledger.spentCredits.toFixed(3)} spent; ${dispatchHeadroom.toFixed(3)} remains below the ${usableCredits.toFixed(3)} planned-spend ceiling, but ${MAX_BOUNDED_CALL_CREDITS.toFixed(3)} credits of worst-case call headroom are required.`
|
|
5603
|
+
);
|
|
5604
|
+
}
|
|
5605
|
+
await writeLockState(lock, "in-flight");
|
|
5606
|
+
dispatchStarted = true;
|
|
5607
|
+
let result;
|
|
5608
|
+
try {
|
|
5609
|
+
result = await args.run();
|
|
5610
|
+
} catch (error) {
|
|
5611
|
+
if (error instanceof CodexCreditDispatchError) {
|
|
5612
|
+
await writeLockState(lock, "settled");
|
|
5613
|
+
accountingSettled = true;
|
|
5614
|
+
} else {
|
|
5615
|
+
const blockedLedger = {
|
|
5616
|
+
...ledger,
|
|
5617
|
+
blockedReason: error instanceof CodexCreditAccountingError ? error.message : `Codex dispatch outcome is unknown after an unexpected error: ${safeErrorMessage(error)}`
|
|
5618
|
+
};
|
|
5619
|
+
await writeLedger(args.config.ledgerPath, blockedLedger);
|
|
5620
|
+
await writeLockState(lock, "settled");
|
|
5621
|
+
accountingSettled = true;
|
|
5622
|
+
}
|
|
5623
|
+
throw error;
|
|
5624
|
+
}
|
|
5625
|
+
const credits = calculateCodexCredits(args.model, result.usage);
|
|
5626
|
+
const nextSpent = ledger.spentCredits + credits;
|
|
5627
|
+
const nextLedger = {
|
|
5628
|
+
...ledger,
|
|
5629
|
+
spentCredits: nextSpent,
|
|
5630
|
+
entries: [
|
|
5631
|
+
...ledger.entries,
|
|
5632
|
+
{
|
|
5633
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5634
|
+
model: args.model,
|
|
5635
|
+
credits,
|
|
5636
|
+
...args.config.runId ? { runId: args.config.runId } : {},
|
|
5637
|
+
...result.usage
|
|
5638
|
+
}
|
|
5639
|
+
]
|
|
5640
|
+
};
|
|
5641
|
+
await writeLedger(args.config.ledgerPath, nextLedger);
|
|
5642
|
+
await writeLockState(lock, "settled");
|
|
5643
|
+
accountingSettled = true;
|
|
5644
|
+
args.onUsagePersisted?.(result.usage);
|
|
5645
|
+
if (nextSpent > usableCredits) {
|
|
5646
|
+
throw new Error(
|
|
5647
|
+
`Codex planned-spend ceiling exceeded by completed call: ${nextSpent.toFixed(3)} > ${usableCredits.toFixed(3)} credits. Usage was persisted; stop the benchmark immediately.`
|
|
5648
|
+
);
|
|
5649
|
+
}
|
|
5650
|
+
return result.value;
|
|
5651
|
+
} finally {
|
|
5652
|
+
try {
|
|
5653
|
+
if (lock) {
|
|
5654
|
+
try {
|
|
5655
|
+
await lock.close();
|
|
5656
|
+
} finally {
|
|
5657
|
+
if (!dispatchStarted || accountingSettled) {
|
|
5658
|
+
await removeOwnedLedgerLock(lockPath);
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
} finally {
|
|
5663
|
+
release();
|
|
5664
|
+
}
|
|
5665
|
+
}
|
|
5666
|
+
}
|
|
5667
|
+
async function acquireLedgerLock(lockPath) {
|
|
5668
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
5669
|
+
try {
|
|
5670
|
+
await mkdir2(lockPath, { mode: 448 });
|
|
5671
|
+
} catch (error) {
|
|
5672
|
+
if (error.code !== "EEXIST") throw error;
|
|
5673
|
+
const owner = await readLockOwner(lockPath);
|
|
5674
|
+
if (!owner || isProcessAlive(owner.pid) || owner.phase === "in-flight") {
|
|
5675
|
+
throw new Error(
|
|
5676
|
+
`Codex credit ledger is locked${owner?.phase === "in-flight" ? " with unreconciled in-flight usage" : " by another benchmark process"} (${lockPath}); refusing credit spend.`
|
|
5677
|
+
);
|
|
5678
|
+
}
|
|
5679
|
+
await reclaimStaleLedgerLock(lockPath, owner);
|
|
5680
|
+
continue;
|
|
5681
|
+
}
|
|
5682
|
+
let createdLock;
|
|
5683
|
+
try {
|
|
5684
|
+
await mkdir2(lockHeldPath(lockPath));
|
|
5685
|
+
createdLock = await open(lockOwnerPath(lockPath), "wx", 384);
|
|
5686
|
+
await writeLockState(createdLock, "preflight");
|
|
5687
|
+
return createdLock;
|
|
5688
|
+
} catch (error) {
|
|
5689
|
+
await createdLock?.close().catch(() => void 0);
|
|
5690
|
+
await unlink2(lockOwnerPath(lockPath)).catch(() => void 0);
|
|
5691
|
+
await rmdir(lockHeldPath(lockPath)).catch(() => void 0);
|
|
5692
|
+
await rmdir(lockPath).catch(() => void 0);
|
|
5693
|
+
throw error;
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
throw new Error(`Unable to acquire Codex credit ledger lock (${lockPath})`);
|
|
5697
|
+
}
|
|
5698
|
+
async function readLockOwner(lockPath) {
|
|
5699
|
+
try {
|
|
5700
|
+
const parsed = JSON.parse(await readFile3(lockOwnerPath(lockPath), "utf8"));
|
|
5701
|
+
if (!Number.isSafeInteger(parsed.pid) || parsed.pid <= 0 || parsed.phase !== "preflight" && parsed.phase !== "in-flight" && parsed.phase !== "settled") {
|
|
5702
|
+
return void 0;
|
|
5703
|
+
}
|
|
5704
|
+
return { pid: parsed.pid, phase: parsed.phase };
|
|
5705
|
+
} catch {
|
|
5706
|
+
return void 0;
|
|
5707
|
+
}
|
|
5708
|
+
}
|
|
5709
|
+
async function reclaimStaleLedgerLock(lockPath, expectedOwner) {
|
|
5710
|
+
try {
|
|
5711
|
+
await rmdir(lockHeldPath(lockPath));
|
|
5712
|
+
} catch (error) {
|
|
5713
|
+
throw new Error(
|
|
5714
|
+
`Codex credit ledger stale-lock reclamation is already claimed or incomplete (${lockPath}); refusing credit spend: ${safeErrorMessage(error)}`
|
|
5715
|
+
);
|
|
5716
|
+
}
|
|
5717
|
+
const currentOwner = await readLockOwner(lockPath);
|
|
5718
|
+
if (!currentOwner || currentOwner.pid !== expectedOwner.pid || currentOwner.phase !== expectedOwner.phase || isProcessAlive(currentOwner.pid) || currentOwner.phase === "in-flight") {
|
|
5719
|
+
throw new Error(
|
|
5720
|
+
`Codex credit ledger owner changed during stale-lock reclamation (${lockPath}); refusing credit spend.`
|
|
5721
|
+
);
|
|
5722
|
+
}
|
|
5723
|
+
await unlink2(lockOwnerPath(lockPath));
|
|
5724
|
+
await rmdir(lockPath);
|
|
5725
|
+
}
|
|
5726
|
+
async function removeOwnedLedgerLock(lockPath) {
|
|
5727
|
+
await rmdir(lockHeldPath(lockPath));
|
|
5728
|
+
await unlink2(lockOwnerPath(lockPath));
|
|
5729
|
+
await rmdir(lockPath);
|
|
5730
|
+
}
|
|
5731
|
+
function lockOwnerPath(lockPath) {
|
|
5732
|
+
return path3.join(lockPath, "owner.json");
|
|
5733
|
+
}
|
|
5734
|
+
function lockHeldPath(lockPath) {
|
|
5735
|
+
return path3.join(lockPath, "held");
|
|
5736
|
+
}
|
|
5737
|
+
async function writeLockState(lock, phase) {
|
|
5738
|
+
const contents = `${JSON.stringify({
|
|
5739
|
+
pid: process.pid,
|
|
5740
|
+
phase,
|
|
5741
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5742
|
+
})}
|
|
5743
|
+
`;
|
|
5744
|
+
await lock.truncate(0);
|
|
5745
|
+
await lock.write(contents, 0, "utf8");
|
|
5746
|
+
await lock.sync();
|
|
5747
|
+
}
|
|
5748
|
+
function isProcessAlive(pid) {
|
|
5749
|
+
try {
|
|
5750
|
+
process.kill(pid, 0);
|
|
5751
|
+
return true;
|
|
5752
|
+
} catch (error) {
|
|
5753
|
+
return error.code === "EPERM";
|
|
5754
|
+
}
|
|
5755
|
+
}
|
|
5756
|
+
function parseCodexJsonlUsage(output) {
|
|
5757
|
+
let usage;
|
|
5758
|
+
for (const line of output.split(/\r?\n/)) {
|
|
5759
|
+
const trimmed = line.trim();
|
|
5760
|
+
if (!trimmed.startsWith("{")) continue;
|
|
5761
|
+
try {
|
|
5762
|
+
const event = JSON.parse(trimmed);
|
|
5763
|
+
if (event.type !== "turn.completed" || !event.usage) continue;
|
|
5764
|
+
const inputTokens = readCounter(event.usage.input_tokens);
|
|
5765
|
+
const outputTokens = readCounter(event.usage.output_tokens);
|
|
5766
|
+
const cachedInputTokens = readOptionalCounter(
|
|
5767
|
+
event.usage.cached_input_tokens
|
|
5768
|
+
);
|
|
5769
|
+
const reasoningOutputTokens = readOptionalCounter(
|
|
5770
|
+
event.usage.reasoning_output_tokens
|
|
5771
|
+
);
|
|
5772
|
+
if (inputTokens !== void 0 && outputTokens !== void 0 && cachedInputTokens !== void 0 && reasoningOutputTokens !== void 0) {
|
|
5773
|
+
usage = {
|
|
5774
|
+
inputTokens,
|
|
5775
|
+
cachedInputTokens,
|
|
5776
|
+
outputTokens,
|
|
5777
|
+
reasoningOutputTokens
|
|
5778
|
+
};
|
|
5779
|
+
}
|
|
5780
|
+
} catch {
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
return usage;
|
|
5784
|
+
}
|
|
5785
|
+
function calculateCodexCredits(model, usage) {
|
|
5786
|
+
const rate = resolveRate(model);
|
|
5787
|
+
const cached = Math.min(usage.inputTokens, usage.cachedInputTokens);
|
|
5788
|
+
const uncached = usage.inputTokens - cached;
|
|
5789
|
+
return (uncached * rate.input + cached * rate.cachedInput + usage.outputTokens * rate.output) / ONE_MILLION;
|
|
5790
|
+
}
|
|
5791
|
+
async function buildCodexCreditReceipt(ledgerPath, runId) {
|
|
5792
|
+
const resolvedPath = path3.resolve(expandHomeRelativePath(ledgerPath));
|
|
5793
|
+
const contents = await readFile3(resolvedPath);
|
|
5794
|
+
const ledger = parseLedger(JSON.parse(contents.toString("utf8")));
|
|
5795
|
+
const normalizedRunId = parseOptionalRunId(runId);
|
|
5796
|
+
const cumulative = summarizeLedgerEntries(ledger.entries);
|
|
5797
|
+
const runEntries = normalizedRunId ? ledger.entries.filter((entry) => entry.runId === normalizedRunId) : [];
|
|
5798
|
+
return {
|
|
5799
|
+
schemaVersion: 1,
|
|
5800
|
+
ledgerSha256: createHash3("sha256").update(contents).digest("hex"),
|
|
5801
|
+
budgetCredits: ledger.budgetCredits,
|
|
5802
|
+
reserveCredits: ledger.reserveCredits,
|
|
5803
|
+
plannedSpendCeilingCredits: ledger.budgetCredits - ledger.reserveCredits,
|
|
5804
|
+
totalSpentCredits: ledger.spentCredits,
|
|
5805
|
+
totalRemainingCredits: ledger.budgetCredits - ledger.spentCredits,
|
|
5806
|
+
blocked: ledger.blockedReason !== void 0,
|
|
5807
|
+
cumulative,
|
|
5808
|
+
...normalizedRunId ? { run: { id: normalizedRunId, ...summarizeLedgerEntries(runEntries) } } : {}
|
|
5809
|
+
};
|
|
5810
|
+
}
|
|
5811
|
+
function resolveRate(model) {
|
|
5812
|
+
const match = CREDIT_RATES.find(([pattern]) => pattern.test(model));
|
|
5813
|
+
if (!match) {
|
|
5814
|
+
throw new Error(
|
|
5815
|
+
`No Codex credit rate is configured for model ${JSON.stringify(model)}; refusing to run under a bounded credit budget.`
|
|
5816
|
+
);
|
|
5817
|
+
}
|
|
5818
|
+
return match[1];
|
|
5819
|
+
}
|
|
5820
|
+
function assertModelAllowed(model, config) {
|
|
5821
|
+
resolveRate(model);
|
|
5822
|
+
if (SOL_MODEL.test(model) && !config.allowSol) {
|
|
5823
|
+
throw new Error(
|
|
5824
|
+
"gpt-5.6-sol is disabled for bounded benchmark runs because it is the most expensive GPT-5.6 tier. Use gpt-5.6-terra or gpt-5.6-luna, or explicitly set REMNIC_BENCH_CODEX_ALLOW_SOL=1."
|
|
5825
|
+
);
|
|
5826
|
+
}
|
|
5827
|
+
}
|
|
5828
|
+
async function readLedger(config) {
|
|
5829
|
+
try {
|
|
5830
|
+
const parsed = parseLedger(
|
|
5831
|
+
JSON.parse(await readFile3(config.ledgerPath, "utf8"))
|
|
5832
|
+
);
|
|
5833
|
+
if (parsed.budgetCredits !== config.budgetCredits || parsed.reserveCredits !== config.reserveCredits) {
|
|
5834
|
+
throw new Error("ledger schema or budget does not match this run");
|
|
5835
|
+
}
|
|
5836
|
+
return parsed;
|
|
5837
|
+
} catch (error) {
|
|
5838
|
+
if (error.code !== "ENOENT") {
|
|
5839
|
+
throw new Error(`Invalid Codex credit ledger at ${config.ledgerPath}: ${String(error)}`);
|
|
5840
|
+
}
|
|
5841
|
+
return {
|
|
5842
|
+
schemaVersion: 1,
|
|
5843
|
+
budgetCredits: config.budgetCredits,
|
|
5844
|
+
reserveCredits: config.reserveCredits,
|
|
5845
|
+
spentCredits: 0,
|
|
5846
|
+
entries: []
|
|
5847
|
+
};
|
|
5848
|
+
}
|
|
5849
|
+
}
|
|
5850
|
+
function parseLedger(parsed) {
|
|
5851
|
+
const entryCredits = Array.isArray(parsed.entries) ? parsed.entries.reduce(
|
|
5852
|
+
(sum, entry) => sum + (typeof entry?.credits === "number" ? entry.credits ?? 0 : 0),
|
|
5853
|
+
0
|
|
5854
|
+
) : Number.NaN;
|
|
5855
|
+
if (parsed.schemaVersion !== 1 || typeof parsed.budgetCredits !== "number" || !Number.isFinite(parsed.budgetCredits) || parsed.budgetCredits <= 0 || typeof parsed.reserveCredits !== "number" || !Number.isFinite(parsed.reserveCredits) || parsed.reserveCredits < 0 || parsed.reserveCredits >= parsed.budgetCredits || typeof parsed.spentCredits !== "number" || !Number.isFinite(parsed.spentCredits) || parsed.spentCredits < 0 || !Array.isArray(parsed.entries) || !parsed.entries.every(isLedgerEntry) || Math.abs(entryCredits - parsed.spentCredits) > 1e-9 || parsed.blockedReason !== void 0 && typeof parsed.blockedReason !== "string") {
|
|
5856
|
+
throw new Error("ledger schema is invalid");
|
|
5857
|
+
}
|
|
5858
|
+
return parsed;
|
|
5859
|
+
}
|
|
5860
|
+
function isLedgerEntry(entry) {
|
|
5861
|
+
if (!entry || typeof entry !== "object") return false;
|
|
5862
|
+
const candidate = entry;
|
|
5863
|
+
return typeof candidate.at === "string" && typeof candidate.model === "string" && candidate.model.length > 0 && typeof candidate.credits === "number" && Number.isFinite(candidate.credits) && candidate.credits >= 0 && (candidate.runId === void 0 || isValidStoredRunId(candidate.runId)) && readCounter(candidate.inputTokens) !== void 0 && readCounter(candidate.cachedInputTokens) !== void 0 && readCounter(candidate.outputTokens) !== void 0 && readCounter(candidate.reasoningOutputTokens) !== void 0 && (candidate.cachedInputTokens ?? 0) <= (candidate.inputTokens ?? 0) && isEntryCreditConsistent(candidate);
|
|
5864
|
+
}
|
|
5865
|
+
function isEntryCreditConsistent(entry) {
|
|
5866
|
+
try {
|
|
5867
|
+
return Math.abs(calculateCodexCredits(entry.model, entry) - entry.credits) <= 1e-9;
|
|
5868
|
+
} catch {
|
|
5869
|
+
return false;
|
|
5870
|
+
}
|
|
5871
|
+
}
|
|
5872
|
+
function summarizeLedgerEntries(entries) {
|
|
5873
|
+
const byModel = /* @__PURE__ */ new Map();
|
|
5874
|
+
for (const entry of entries) {
|
|
5875
|
+
const modelEntries = byModel.get(entry.model) ?? [];
|
|
5876
|
+
modelEntries.push(entry);
|
|
5877
|
+
byModel.set(entry.model, modelEntries);
|
|
5878
|
+
}
|
|
5879
|
+
const totals = summarizeUsage(entries);
|
|
5880
|
+
return {
|
|
5881
|
+
calls: entries.length,
|
|
5882
|
+
credits: entries.reduce((sum, entry) => sum + entry.credits, 0),
|
|
5883
|
+
...totals,
|
|
5884
|
+
models: [...byModel.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([model, modelEntries]) => ({
|
|
5885
|
+
model,
|
|
5886
|
+
calls: modelEntries.length,
|
|
5887
|
+
credits: modelEntries.reduce((sum, entry) => sum + entry.credits, 0),
|
|
5888
|
+
...summarizeUsage(modelEntries)
|
|
5889
|
+
}))
|
|
5890
|
+
};
|
|
5891
|
+
}
|
|
5892
|
+
function summarizeUsage(entries) {
|
|
5893
|
+
return entries.reduce(
|
|
5894
|
+
(totals, entry) => ({
|
|
5895
|
+
inputTokens: totals.inputTokens + entry.inputTokens,
|
|
5896
|
+
cachedInputTokens: totals.cachedInputTokens + entry.cachedInputTokens,
|
|
5897
|
+
outputTokens: totals.outputTokens + entry.outputTokens,
|
|
5898
|
+
reasoningOutputTokens: totals.reasoningOutputTokens + entry.reasoningOutputTokens
|
|
5899
|
+
}),
|
|
5900
|
+
{ inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningOutputTokens: 0 }
|
|
5901
|
+
);
|
|
5902
|
+
}
|
|
5903
|
+
async function writeLedger(filePath, ledger) {
|
|
5904
|
+
await mkdir2(path3.dirname(filePath), { recursive: true, mode: 448 });
|
|
5905
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
5906
|
+
await writeFile2(tempPath, `${JSON.stringify(ledger, null, 2)}
|
|
5907
|
+
`, {
|
|
5908
|
+
encoding: "utf8",
|
|
5909
|
+
mode: 384
|
|
5910
|
+
});
|
|
5911
|
+
await rename2(tempPath, filePath);
|
|
5912
|
+
}
|
|
5913
|
+
function readCounter(value) {
|
|
5914
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
5915
|
+
}
|
|
5916
|
+
function readOptionalCounter(value) {
|
|
5917
|
+
return value === void 0 ? 0 : readCounter(value);
|
|
5918
|
+
}
|
|
5919
|
+
function safeErrorMessage(error) {
|
|
5920
|
+
return error instanceof Error ? error.message : String(error);
|
|
5921
|
+
}
|
|
5922
|
+
function expandHomeRelativePath(value) {
|
|
5923
|
+
if (value === "~") return os.homedir();
|
|
5924
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
5925
|
+
return path3.join(os.homedir(), value.slice(2));
|
|
5926
|
+
}
|
|
5927
|
+
return value;
|
|
5928
|
+
}
|
|
5929
|
+
function parsePositiveNumber(value, name) {
|
|
5930
|
+
const parsed = Number(value);
|
|
5931
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
5932
|
+
throw new Error(`${name} must be a finite number greater than zero`);
|
|
5933
|
+
}
|
|
5934
|
+
return parsed;
|
|
5935
|
+
}
|
|
5936
|
+
function parseNonNegativeNumber(value, name) {
|
|
5937
|
+
const parsed = Number(value);
|
|
5938
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
5939
|
+
throw new Error(`${name} must be a finite non-negative number`);
|
|
5940
|
+
}
|
|
5941
|
+
return parsed;
|
|
5942
|
+
}
|
|
5943
|
+
function parseOptionalRunId(value) {
|
|
5944
|
+
const runId = value?.trim();
|
|
5945
|
+
if (!runId) return void 0;
|
|
5946
|
+
if (runId.length > 128 || hasControlCharacters(runId)) {
|
|
5947
|
+
throw new Error("REMNIC_BENCH_RUN_ID must be at most 128 characters without control characters");
|
|
5948
|
+
}
|
|
5949
|
+
return runId;
|
|
5950
|
+
}
|
|
5951
|
+
function isValidStoredRunId(value) {
|
|
5952
|
+
return typeof value === "string" && value.length > 0 && value.length <= 128 && value === value.trim() && !hasControlCharacters(value);
|
|
5953
|
+
}
|
|
5954
|
+
function hasControlCharacters(value) {
|
|
5955
|
+
for (const character of value) {
|
|
5956
|
+
const codePoint = character.codePointAt(0) ?? 0;
|
|
5957
|
+
if (codePoint <= 31 || codePoint === 127) return true;
|
|
5958
|
+
}
|
|
5959
|
+
return false;
|
|
5960
|
+
}
|
|
5961
|
+
|
|
5962
|
+
// src/results-store.ts
|
|
5963
|
+
import { mkdir as mkdir3, readdir as readdir3, readFile as readFile4, unlink as unlink3, writeFile as writeFile3 } from "fs/promises";
|
|
5964
|
+
import fs from "fs";
|
|
5965
|
+
import os2 from "os";
|
|
5966
|
+
import path4 from "path";
|
|
5511
5967
|
|
|
5512
5968
|
// src/integrity/contamination.ts
|
|
5513
5969
|
var EMPTY_CONTAMINATION_MANIFEST = {
|
|
@@ -5972,14 +6428,14 @@ ${renderProvenance(result, provenance)}
|
|
|
5972
6428
|
var BASELINE_NAME_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
5973
6429
|
var REPRO_MANIFEST_FILENAME = "MANIFEST.json";
|
|
5974
6430
|
function defaultBenchmarkBaselineDir() {
|
|
5975
|
-
const homeDir = process.env.HOME ?? process.env.USERPROFILE ??
|
|
5976
|
-
return
|
|
6431
|
+
const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? os2.homedir();
|
|
6432
|
+
return path4.join(homeDir, ".remnic", "bench", "baselines");
|
|
5977
6433
|
}
|
|
5978
6434
|
function defaultBenchmarkPublishPath(target) {
|
|
5979
|
-
const homeDir = process.env.HOME ?? process.env.USERPROFILE ??
|
|
6435
|
+
const homeDir = process.env.HOME ?? process.env.USERPROFILE ?? os2.homedir();
|
|
5980
6436
|
switch (target) {
|
|
5981
6437
|
case "remnic-ai":
|
|
5982
|
-
return
|
|
6438
|
+
return path4.join(homeDir, ".remnic", "published", "benchmarks.json");
|
|
5983
6439
|
}
|
|
5984
6440
|
}
|
|
5985
6441
|
function compareResultSummaries(left, right) {
|
|
@@ -6004,10 +6460,10 @@ function isFiniteNumber(value) {
|
|
|
6004
6460
|
return typeof value === "number" && Number.isFinite(value);
|
|
6005
6461
|
}
|
|
6006
6462
|
async function loadBenchmarkReportCardProvenance(outputDir, resultId) {
|
|
6007
|
-
const manifestPath =
|
|
6463
|
+
const manifestPath = path4.join(outputDir, REPRO_MANIFEST_FILENAME);
|
|
6008
6464
|
let parsed;
|
|
6009
6465
|
try {
|
|
6010
|
-
parsed = JSON.parse(await
|
|
6466
|
+
parsed = JSON.parse(await readFile4(manifestPath, "utf8"));
|
|
6011
6467
|
} catch {
|
|
6012
6468
|
return {};
|
|
6013
6469
|
}
|
|
@@ -6114,7 +6570,7 @@ function toBaselineSummary(baseline, filePath) {
|
|
|
6114
6570
|
};
|
|
6115
6571
|
}
|
|
6116
6572
|
async function loadBenchmarkResult(filePath) {
|
|
6117
|
-
const content = await
|
|
6573
|
+
const content = await readFile4(filePath, "utf8");
|
|
6118
6574
|
const parsed = JSON.parse(content);
|
|
6119
6575
|
if (!isBenchmarkResult(parsed)) {
|
|
6120
6576
|
throw new Error(`Invalid benchmark result file: ${filePath}`);
|
|
@@ -6131,7 +6587,7 @@ async function listBenchmarkResults(outputDir) {
|
|
|
6131
6587
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
6132
6588
|
continue;
|
|
6133
6589
|
}
|
|
6134
|
-
const filePath =
|
|
6590
|
+
const filePath = path4.join(outputDir, entry.name);
|
|
6135
6591
|
try {
|
|
6136
6592
|
const result = await loadBenchmarkResult(filePath);
|
|
6137
6593
|
results.push(toSummary(result, filePath));
|
|
@@ -6144,20 +6600,20 @@ async function listBenchmarkResults(outputDir) {
|
|
|
6144
6600
|
async function saveBenchmarkBaseline(baselineDir, name, result, source) {
|
|
6145
6601
|
assertValidBaselineName(name);
|
|
6146
6602
|
assertUsableBaselineDir(baselineDir);
|
|
6147
|
-
await
|
|
6148
|
-
const filePath =
|
|
6603
|
+
await mkdir3(baselineDir, { recursive: true });
|
|
6604
|
+
const filePath = path4.join(baselineDir, `${name}.json`);
|
|
6149
6605
|
const payload = {
|
|
6150
6606
|
name,
|
|
6151
6607
|
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6152
6608
|
result,
|
|
6153
6609
|
source
|
|
6154
6610
|
};
|
|
6155
|
-
await
|
|
6611
|
+
await writeFile3(filePath, `${JSON.stringify(payload, null, 2)}
|
|
6156
6612
|
`);
|
|
6157
6613
|
return filePath;
|
|
6158
6614
|
}
|
|
6159
6615
|
async function loadBenchmarkBaseline(filePath) {
|
|
6160
|
-
const content = await
|
|
6616
|
+
const content = await readFile4(filePath, "utf8");
|
|
6161
6617
|
const parsed = JSON.parse(content);
|
|
6162
6618
|
if (!isStoredBenchmarkBaseline(parsed)) {
|
|
6163
6619
|
throw new Error(`Invalid benchmark baseline file: ${filePath}`);
|
|
@@ -6175,7 +6631,7 @@ async function listBenchmarkBaselines(baselineDir) {
|
|
|
6175
6631
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
6176
6632
|
continue;
|
|
6177
6633
|
}
|
|
6178
|
-
const filePath =
|
|
6634
|
+
const filePath = path4.join(baselineDir, entry.name);
|
|
6179
6635
|
try {
|
|
6180
6636
|
const baseline = await loadBenchmarkBaseline(filePath);
|
|
6181
6637
|
baselines.push(toBaselineSummary(baseline, filePath));
|
|
@@ -6192,7 +6648,7 @@ async function resolveBenchmarkResultReference(outputDir, reference) {
|
|
|
6192
6648
|
return exactIdMatch;
|
|
6193
6649
|
}
|
|
6194
6650
|
const basenameMatch = summaries.find(
|
|
6195
|
-
(summary) =>
|
|
6651
|
+
(summary) => path4.basename(summary.path) === reference
|
|
6196
6652
|
);
|
|
6197
6653
|
if (basenameMatch) {
|
|
6198
6654
|
return basenameMatch;
|
|
@@ -6208,7 +6664,7 @@ async function resolveBenchmarkResultReference(outputDir, reference) {
|
|
|
6208
6664
|
return void 0;
|
|
6209
6665
|
}
|
|
6210
6666
|
function looksLikeFilesystemPath(reference) {
|
|
6211
|
-
return
|
|
6667
|
+
return path4.isAbsolute(reference) || reference.includes("/") || reference.includes(path4.sep) || reference.endsWith(".json");
|
|
6212
6668
|
}
|
|
6213
6669
|
async function deleteBenchmarkResults(outputDir, references) {
|
|
6214
6670
|
const summaries = await listBenchmarkResults(outputDir);
|
|
@@ -6216,9 +6672,9 @@ async function deleteBenchmarkResults(outputDir, references) {
|
|
|
6216
6672
|
const missing = [];
|
|
6217
6673
|
const seenPaths = /* @__PURE__ */ new Set();
|
|
6218
6674
|
for (const reference of references) {
|
|
6219
|
-
let summary = summaries.find((entry) => entry.id === reference) ?? summaries.find((entry) =>
|
|
6675
|
+
let summary = summaries.find((entry) => entry.id === reference) ?? summaries.find((entry) => path4.basename(entry.path) === reference);
|
|
6220
6676
|
if (!summary && looksLikeFilesystemPath(reference)) {
|
|
6221
|
-
const canonicalRef =
|
|
6677
|
+
const canonicalRef = path4.resolve(reference);
|
|
6222
6678
|
if (seenPaths.has(canonicalRef)) {
|
|
6223
6679
|
continue;
|
|
6224
6680
|
}
|
|
@@ -6235,13 +6691,13 @@ async function deleteBenchmarkResults(outputDir, references) {
|
|
|
6235
6691
|
missing.push(reference);
|
|
6236
6692
|
continue;
|
|
6237
6693
|
}
|
|
6238
|
-
const canonicalPath =
|
|
6694
|
+
const canonicalPath = path4.resolve(summary.path);
|
|
6239
6695
|
if (seenPaths.has(canonicalPath)) {
|
|
6240
6696
|
continue;
|
|
6241
6697
|
}
|
|
6242
6698
|
seenPaths.add(canonicalPath);
|
|
6243
6699
|
try {
|
|
6244
|
-
await
|
|
6700
|
+
await unlink3(summary.path);
|
|
6245
6701
|
} catch (error) {
|
|
6246
6702
|
if (error.code === "ENOENT") {
|
|
6247
6703
|
} else {
|
|
@@ -6366,8 +6822,8 @@ async function buildBenchmarkPublishFeed(outputDir, target, options = {}) {
|
|
|
6366
6822
|
};
|
|
6367
6823
|
}
|
|
6368
6824
|
async function writeBenchmarkPublishFeed(feed, outputPath) {
|
|
6369
|
-
await
|
|
6370
|
-
await
|
|
6825
|
+
await mkdir3(path4.dirname(outputPath), { recursive: true });
|
|
6826
|
+
await writeFile3(outputPath, `${JSON.stringify(feed, null, 2)}
|
|
6371
6827
|
`);
|
|
6372
6828
|
return outputPath;
|
|
6373
6829
|
}
|
|
@@ -6422,8 +6878,8 @@ function renderBenchmarkResultExport(result, format, options = {}) {
|
|
|
6422
6878
|
// src/run-identity.ts
|
|
6423
6879
|
var BENCHMARK_RUN_ID_ENV = "REMNIC_BENCH_RUN_ID";
|
|
6424
6880
|
var generatedBenchmarkRunId;
|
|
6425
|
-
function resolveBenchmarkRunId() {
|
|
6426
|
-
const explicit =
|
|
6881
|
+
function resolveBenchmarkRunId(env = process.env) {
|
|
6882
|
+
const explicit = env[BENCHMARK_RUN_ID_ENV]?.trim();
|
|
6427
6883
|
if (explicit) {
|
|
6428
6884
|
return explicit;
|
|
6429
6885
|
}
|
|
@@ -6627,14 +7083,22 @@ var BENCH_OPTION_BOUNDARY_FLAGS = /* @__PURE__ */ new Set([
|
|
|
6627
7083
|
]);
|
|
6628
7084
|
var SECRET_KEY_PATTERN = /(^|[-_])(?:api[-_]?key|secret[-_]?access[-_]?key|secret[-_]?key|client[-_]?secret(?:[-_]?key)?|app[-_]?secret(?:[-_]?key)?|provider[-_]?secret(?:[-_]?key)?|access[-_]?key|private[-_]?key|secret|password|authorization|credential|access[-_]?token|auth[-_]?token|refresh[-_]?token|id[-_]?token|token)$/i;
|
|
6629
7085
|
var REDACTED_ARG_VALUE = "[redacted]";
|
|
7086
|
+
var CODEX_CREDIT_REPRO_ENV_KEYS = [
|
|
7087
|
+
"REMNIC_BENCH_CODEX_ALLOW_SOL",
|
|
7088
|
+
"REMNIC_BENCH_CODEX_CREDIT_BUDGET",
|
|
7089
|
+
"REMNIC_BENCH_CODEX_CREDIT_LEDGER",
|
|
7090
|
+
"REMNIC_BENCH_CODEX_CREDIT_RESERVE",
|
|
7091
|
+
"REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_MODE",
|
|
7092
|
+
"REMNIC_BENCH_RUN_ID"
|
|
7093
|
+
];
|
|
6630
7094
|
function sha256String(value) {
|
|
6631
|
-
return
|
|
7095
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
6632
7096
|
}
|
|
6633
7097
|
function sha256Buffer(value) {
|
|
6634
|
-
return
|
|
7098
|
+
return createHash4("sha256").update(value).digest("hex");
|
|
6635
7099
|
}
|
|
6636
7100
|
async function sha256File(filePath) {
|
|
6637
|
-
const hash =
|
|
7101
|
+
const hash = createHash4("sha256");
|
|
6638
7102
|
await new Promise((resolve, reject) => {
|
|
6639
7103
|
const stream = createReadStream(filePath);
|
|
6640
7104
|
stream.on("data", (chunk) => hash.update(chunk));
|
|
@@ -7137,7 +7601,10 @@ function isAsciiAlnum2(char) {
|
|
|
7137
7601
|
return isUppercaseAscii(char) || isLowercaseAscii(char) || char >= "0" && char <= "9";
|
|
7138
7602
|
}
|
|
7139
7603
|
function sanitizeEnvKeys(env, explicitKeys) {
|
|
7140
|
-
const sourceKeys =
|
|
7604
|
+
const sourceKeys = [
|
|
7605
|
+
...explicitKeys ?? Object.keys(env ?? {}),
|
|
7606
|
+
...CODEX_CREDIT_REPRO_ENV_KEYS.filter((key) => env?.[key] !== void 0)
|
|
7607
|
+
];
|
|
7141
7608
|
return [...new Set(sourceKeys)].filter((key) => typeof key === "string" && key.length > 0).sort((left, right) => left.localeCompare(right));
|
|
7142
7609
|
}
|
|
7143
7610
|
function gitOutput(args, cwd) {
|
|
@@ -7191,7 +7658,8 @@ function buildArtifactHashIdentity(manifest) {
|
|
|
7191
7658
|
...manifest.qmd ? { qmd: manifest.qmd } : {},
|
|
7192
7659
|
configFiles: manifest.configFiles,
|
|
7193
7660
|
datasets: manifest.datasets,
|
|
7194
|
-
results: manifest.results
|
|
7661
|
+
results: manifest.results,
|
|
7662
|
+
...manifest.codexCredit ? { codexCredit: manifest.codexCredit } : {}
|
|
7195
7663
|
};
|
|
7196
7664
|
}
|
|
7197
7665
|
async function scanDatasetFiles(root) {
|
|
@@ -7200,18 +7668,18 @@ async function scanDatasetFiles(root) {
|
|
|
7200
7668
|
const entries = await readdir4(directory, { withFileTypes: true });
|
|
7201
7669
|
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
7202
7670
|
for (const entry of entries) {
|
|
7203
|
-
const entryPath =
|
|
7671
|
+
const entryPath = path5.join(directory, entry.name);
|
|
7204
7672
|
const entryStat = await lstat3(entryPath);
|
|
7205
|
-
const relativePath =
|
|
7673
|
+
const relativePath = path5.relative(root, entryPath).split(path5.sep).join("/");
|
|
7206
7674
|
if (entryStat.isSymbolicLink()) {
|
|
7207
7675
|
const target = await readlink(entryPath);
|
|
7208
|
-
const resolvedTarget =
|
|
7676
|
+
const resolvedTarget = path5.resolve(directory, target);
|
|
7209
7677
|
const realTarget = await realpath3(resolvedTarget);
|
|
7210
|
-
const targetRelativePath =
|
|
7211
|
-
if (targetRelativePath.length === 0 || targetRelativePath === ".." || targetRelativePath.startsWith(`..${
|
|
7678
|
+
const targetRelativePath = path5.relative(root, realTarget);
|
|
7679
|
+
if (targetRelativePath.length === 0 || targetRelativePath === ".." || targetRelativePath.startsWith(`..${path5.sep}`) || path5.isAbsolute(targetRelativePath)) {
|
|
7212
7680
|
throw new Error(`dataset symlink target must be inside ${root}: ${entryPath}`);
|
|
7213
7681
|
}
|
|
7214
|
-
const manifestTarget =
|
|
7682
|
+
const manifestTarget = path5.isAbsolute(target) ? targetRelativePath.split(path5.sep).join("/") : target;
|
|
7215
7683
|
files.push({
|
|
7216
7684
|
path: relativePath,
|
|
7217
7685
|
kind: "symlink",
|
|
@@ -7239,9 +7707,9 @@ async function scanDatasetFiles(root) {
|
|
|
7239
7707
|
return files.sort((left, right) => left.path.localeCompare(right.path));
|
|
7240
7708
|
}
|
|
7241
7709
|
async function lstatPathWithoutSymlinkComponents(targetPath) {
|
|
7242
|
-
const parsed =
|
|
7243
|
-
const relativePath =
|
|
7244
|
-
const parts = relativePath.length > 0 ? relativePath.split(
|
|
7710
|
+
const parsed = path5.parse(targetPath);
|
|
7711
|
+
const relativePath = path5.relative(parsed.root, targetPath);
|
|
7712
|
+
const parts = relativePath.length > 0 ? relativePath.split(path5.sep) : [];
|
|
7245
7713
|
let currentPath = parsed.root;
|
|
7246
7714
|
let currentStat;
|
|
7247
7715
|
try {
|
|
@@ -7249,7 +7717,7 @@ async function lstatPathWithoutSymlinkComponents(targetPath) {
|
|
|
7249
7717
|
currentStat = await lstat3(currentPath);
|
|
7250
7718
|
}
|
|
7251
7719
|
for (const part of parts) {
|
|
7252
|
-
currentPath =
|
|
7720
|
+
currentPath = path5.join(currentPath, part);
|
|
7253
7721
|
currentStat = await lstat3(currentPath);
|
|
7254
7722
|
if (currentStat.isSymbolicLink()) {
|
|
7255
7723
|
return void 0;
|
|
@@ -7270,7 +7738,7 @@ async function buildDatasetManifest(benchmark, datasetDir) {
|
|
|
7270
7738
|
files: []
|
|
7271
7739
|
};
|
|
7272
7740
|
}
|
|
7273
|
-
const datasetRoot =
|
|
7741
|
+
const datasetRoot = path5.resolve(datasetDir);
|
|
7274
7742
|
const datasetStat = await lstatPathWithoutSymlinkComponents(datasetRoot);
|
|
7275
7743
|
if (!datasetStat) {
|
|
7276
7744
|
return {
|
|
@@ -7312,7 +7780,7 @@ async function buildResultManifest(resultsDir, resultPath, result) {
|
|
|
7312
7780
|
await assertRegularFileWithoutSymlinkComponents(resultPath, "result path");
|
|
7313
7781
|
const fileStats = await stat2(resultPath);
|
|
7314
7782
|
return {
|
|
7315
|
-
path:
|
|
7783
|
+
path: path5.relative(resultsDir, resultPath).split(path5.sep).join("/"),
|
|
7316
7784
|
sha256: await sha256File(resultPath),
|
|
7317
7785
|
sizeBytes: fileStats.size,
|
|
7318
7786
|
resultId: result.meta.id,
|
|
@@ -7334,7 +7802,7 @@ async function resolveResultPaths(resultsDir, explicitPaths) {
|
|
|
7334
7802
|
if (explicitPaths !== void 0) {
|
|
7335
7803
|
const resolvedPaths = await Promise.all(
|
|
7336
7804
|
explicitPaths.map(async (entry) => {
|
|
7337
|
-
const resultPath =
|
|
7805
|
+
const resultPath = path5.resolve(entry);
|
|
7338
7806
|
assertPathInsideRoot(resultsDir, resultPath, "result path");
|
|
7339
7807
|
await assertRegularFileWithoutSymlinkComponents(resultPath, "result path");
|
|
7340
7808
|
return resultPath;
|
|
@@ -7343,20 +7811,20 @@ async function resolveResultPaths(resultsDir, explicitPaths) {
|
|
|
7343
7811
|
return [...new Set(resolvedPaths)].sort((left, right) => left.localeCompare(right));
|
|
7344
7812
|
}
|
|
7345
7813
|
const summaries = await listBenchmarkResults(resultsDir);
|
|
7346
|
-
return summaries.map((summary) =>
|
|
7814
|
+
return summaries.map((summary) => path5.resolve(summary.path));
|
|
7347
7815
|
}
|
|
7348
7816
|
function assertPathInsideRoot(root, targetPath, label) {
|
|
7349
|
-
const resolvedRoot =
|
|
7350
|
-
const resolvedTargetPath =
|
|
7351
|
-
const relativePath =
|
|
7352
|
-
if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${
|
|
7817
|
+
const resolvedRoot = path5.resolve(root);
|
|
7818
|
+
const resolvedTargetPath = path5.resolve(targetPath);
|
|
7819
|
+
const relativePath = path5.relative(resolvedRoot, resolvedTargetPath);
|
|
7820
|
+
if (relativePath.length === 0 || relativePath === ".." || relativePath.startsWith(`..${path5.sep}`) || path5.isAbsolute(relativePath)) {
|
|
7353
7821
|
throw new Error(`${label} must be inside ${resolvedRoot}: ${resolvedTargetPath}`);
|
|
7354
7822
|
}
|
|
7355
7823
|
}
|
|
7356
7824
|
async function assertRegularFileWithoutSymlinkComponents(targetPath, label) {
|
|
7357
|
-
const targetStat = await lstatPathWithoutSymlinkComponents(
|
|
7825
|
+
const targetStat = await lstatPathWithoutSymlinkComponents(path5.resolve(targetPath));
|
|
7358
7826
|
if (!targetStat?.isFile()) {
|
|
7359
|
-
throw new Error(`${label} must be a regular file without symlink components: ${
|
|
7827
|
+
throw new Error(`${label} must be a regular file without symlink components: ${path5.resolve(targetPath)}`);
|
|
7360
7828
|
}
|
|
7361
7829
|
}
|
|
7362
7830
|
function isKnownNonSecretOptionFlag(arg) {
|
|
@@ -7402,7 +7870,7 @@ async function buildConfigFileEntries(configFiles = []) {
|
|
|
7402
7870
|
entries.push({ label: configFile.label, path: configFile.path, missing: true });
|
|
7403
7871
|
continue;
|
|
7404
7872
|
}
|
|
7405
|
-
const content = await
|
|
7873
|
+
const content = await readFile5(configFile.path);
|
|
7406
7874
|
const sanitizedConfig = sanitizeConfigFileContent(content);
|
|
7407
7875
|
entries.push({
|
|
7408
7876
|
label: configFile.label,
|
|
@@ -7469,7 +7937,7 @@ function resolvePackageManager(cwd) {
|
|
|
7469
7937
|
}
|
|
7470
7938
|
}
|
|
7471
7939
|
async function buildBenchmarkReproManifest(resultsDir, options = {}) {
|
|
7472
|
-
const resolvedResultsDir =
|
|
7940
|
+
const resolvedResultsDir = path5.resolve(resultsDir);
|
|
7473
7941
|
const cwd = options.command?.cwd ?? process.cwd();
|
|
7474
7942
|
const resultPaths = await resolveResultPaths(resolvedResultsDir, options.resultPaths);
|
|
7475
7943
|
const loadedResults = await Promise.all(resultPaths.map((resultPath) => loadBenchmarkResult(resultPath)));
|
|
@@ -7487,11 +7955,23 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
|
|
|
7487
7955
|
);
|
|
7488
7956
|
const qmdCollections = collectQmdCollections(options.qmd?.collections, loadedResults);
|
|
7489
7957
|
const pnpmVersion = resolvePackageManager(cwd);
|
|
7958
|
+
const commandEnv = options.command?.env ?? process.env;
|
|
7959
|
+
const runId = options.runId ?? resolveBenchmarkRunId(commandEnv);
|
|
7960
|
+
const resolvedCreditConfig = resolveCodexCreditBudgetConfig(commandEnv, runId);
|
|
7961
|
+
const creditConfig = resolvedCreditConfig ? { ...resolvedCreditConfig, runId } : void 0;
|
|
7962
|
+
let codexCredit;
|
|
7963
|
+
if (creditConfig) {
|
|
7964
|
+
try {
|
|
7965
|
+
codexCredit = await buildCodexCreditReceipt(creditConfig.ledgerPath, creditConfig.runId);
|
|
7966
|
+
} catch (error) {
|
|
7967
|
+
if (error.code !== "ENOENT") throw error;
|
|
7968
|
+
}
|
|
7969
|
+
}
|
|
7490
7970
|
const manifestWithoutHash = {
|
|
7491
7971
|
schemaVersion: BENCHMARK_REPRO_MANIFEST_SCHEMA_VERSION,
|
|
7492
7972
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7493
7973
|
run: {
|
|
7494
|
-
id:
|
|
7974
|
+
id: runId,
|
|
7495
7975
|
...options.mode ? { mode: options.mode } : {},
|
|
7496
7976
|
selectedBenchmarks,
|
|
7497
7977
|
runtimeProfiles: options.runtimeProfiles ?? [],
|
|
@@ -7503,13 +7983,13 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
|
|
|
7503
7983
|
command: {
|
|
7504
7984
|
cwd,
|
|
7505
7985
|
argv: sanitizeArgv(options.command?.argv ?? process.argv.slice(2)),
|
|
7506
|
-
envKeys: sanitizeEnvKeys(
|
|
7986
|
+
envKeys: sanitizeEnvKeys(commandEnv, options.command?.envKeys)
|
|
7507
7987
|
},
|
|
7508
7988
|
environment: {
|
|
7509
7989
|
platform: process.platform,
|
|
7510
7990
|
arch: process.arch,
|
|
7511
7991
|
nodeVersion: process.version,
|
|
7512
|
-
hostname:
|
|
7992
|
+
hostname: os3.hostname(),
|
|
7513
7993
|
...pnpmVersion ? { packageManager: `pnpm@${pnpmVersion}` } : {}
|
|
7514
7994
|
},
|
|
7515
7995
|
...options.qmd || qmdCollections.length > 0 ? {
|
|
@@ -7521,7 +8001,8 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
|
|
|
7521
8001
|
} : {},
|
|
7522
8002
|
configFiles: await buildConfigFileEntries(options.configFiles),
|
|
7523
8003
|
datasets,
|
|
7524
|
-
results: resultEntries.sort((left, right) => left.path.localeCompare(right.path))
|
|
8004
|
+
results: resultEntries.sort((left, right) => left.path.localeCompare(right.path)),
|
|
8005
|
+
...codexCredit ? { codexCredit } : {}
|
|
7525
8006
|
};
|
|
7526
8007
|
return {
|
|
7527
8008
|
...manifestWithoutHash,
|
|
@@ -7529,18 +8010,18 @@ async function buildBenchmarkReproManifest(resultsDir, options = {}) {
|
|
|
7529
8010
|
};
|
|
7530
8011
|
}
|
|
7531
8012
|
async function writeBenchmarkReproManifest(resultsDir, options = {}) {
|
|
7532
|
-
await
|
|
8013
|
+
await mkdir4(resultsDir, { recursive: true });
|
|
7533
8014
|
const manifest = await buildBenchmarkReproManifest(resultsDir, options);
|
|
7534
|
-
const manifestPath =
|
|
7535
|
-
await
|
|
8015
|
+
const manifestPath = path5.join(resultsDir, BENCHMARK_REPRO_MANIFEST_FILENAME);
|
|
8016
|
+
await writeFile4(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
7536
8017
|
`);
|
|
7537
8018
|
return manifestPath;
|
|
7538
8019
|
}
|
|
7539
8020
|
|
|
7540
8021
|
// src/published-artifact.ts
|
|
7541
|
-
import { createHash as
|
|
7542
|
-
import { mkdir as
|
|
7543
|
-
import
|
|
8022
|
+
import { createHash as createHash5 } from "crypto";
|
|
8023
|
+
import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
8024
|
+
import path6 from "path";
|
|
7544
8025
|
var BENCHMARK_ARTIFACT_SCHEMA_VERSION = 1;
|
|
7545
8026
|
var PUBLISHED_BENCHMARK_ARTIFACT_IDS = Object.freeze([
|
|
7546
8027
|
"ama-bench",
|
|
@@ -7681,25 +8162,25 @@ function serializeBenchmarkArtifact(artifact) {
|
|
|
7681
8162
|
`;
|
|
7682
8163
|
}
|
|
7683
8164
|
function hashBenchmarkArtifact(artifact) {
|
|
7684
|
-
return
|
|
8165
|
+
return createHash5("sha256").update(serializeBenchmarkArtifact(artifact)).digest("hex");
|
|
7685
8166
|
}
|
|
7686
8167
|
async function writeBenchmarkArtifact(artifact, outputDir) {
|
|
7687
|
-
await
|
|
8168
|
+
await mkdir5(outputDir, { recursive: true });
|
|
7688
8169
|
const filename = buildBenchmarkArtifactFilename(artifact);
|
|
7689
8170
|
const body = serializeBenchmarkArtifact(artifact);
|
|
7690
|
-
const resolvedDir =
|
|
7691
|
-
const abs =
|
|
7692
|
-
const relative =
|
|
7693
|
-
if (relative.length === 0 || relative.startsWith("..") ||
|
|
8171
|
+
const resolvedDir = path6.resolve(outputDir);
|
|
8172
|
+
const abs = path6.resolve(resolvedDir, filename);
|
|
8173
|
+
const relative = path6.relative(resolvedDir, abs);
|
|
8174
|
+
if (relative.length === 0 || relative.startsWith("..") || path6.isAbsolute(relative) || relative.includes(path6.sep)) {
|
|
7694
8175
|
throw new Error(
|
|
7695
8176
|
`writeBenchmarkArtifact: refusing to write outside outputDir (filename="${filename}", resolved="${abs}").`
|
|
7696
8177
|
);
|
|
7697
8178
|
}
|
|
7698
|
-
await
|
|
8179
|
+
await writeFile5(abs, body);
|
|
7699
8180
|
return {
|
|
7700
8181
|
path: abs,
|
|
7701
8182
|
filename,
|
|
7702
|
-
sha256:
|
|
8183
|
+
sha256: createHash5("sha256").update(body).digest("hex"),
|
|
7703
8184
|
bytes: Buffer.byteLength(body, "utf8")
|
|
7704
8185
|
};
|
|
7705
8186
|
}
|
|
@@ -7804,11 +8285,11 @@ function parseBenchmarkArtifact(raw) {
|
|
|
7804
8285
|
return parsed;
|
|
7805
8286
|
}
|
|
7806
8287
|
async function loadBenchmarkArtifact(filePath) {
|
|
7807
|
-
const raw = await
|
|
8288
|
+
const raw = await readFile6(filePath, "utf8");
|
|
7808
8289
|
const artifact = parseBenchmarkArtifact(raw);
|
|
7809
8290
|
return {
|
|
7810
8291
|
artifact,
|
|
7811
|
-
sha256:
|
|
8292
|
+
sha256: createHash5("sha256").update(raw).digest("hex"),
|
|
7812
8293
|
bytes: Buffer.byteLength(raw, "utf8")
|
|
7813
8294
|
};
|
|
7814
8295
|
}
|
|
@@ -8211,8 +8692,8 @@ function createAnthropicProvider(config) {
|
|
|
8211
8692
|
// src/providers/claude-cli.ts
|
|
8212
8693
|
import { spawn } from "child_process";
|
|
8213
8694
|
import { mkdtemp as mkdtemp2, rm as rm2 } from "fs/promises";
|
|
8214
|
-
import
|
|
8215
|
-
import
|
|
8695
|
+
import os4 from "os";
|
|
8696
|
+
import path7 from "path";
|
|
8216
8697
|
var CLAUDE_CLI_STDIO_LIMIT = 64e3;
|
|
8217
8698
|
var CLAUDE_CLI_PARENT_SIGNALS = ["SIGHUP", "SIGINT", "SIGTERM"];
|
|
8218
8699
|
var CLAUDE_CLI_FORCED_PARENT_EXIT_MS = 1e3;
|
|
@@ -8365,7 +8846,7 @@ var ClaudeCliProvider = class {
|
|
|
8365
8846
|
let transientAttempt = 1;
|
|
8366
8847
|
let usageLimitAttempt = 1;
|
|
8367
8848
|
while (true) {
|
|
8368
|
-
const tempDir = await mkdtemp2(
|
|
8849
|
+
const tempDir = await mkdtemp2(path7.join(os4.tmpdir(), "remnic-claude-cli-"));
|
|
8369
8850
|
try {
|
|
8370
8851
|
const request = this.buildRunRequest(prompt, opts, tempDir);
|
|
8371
8852
|
const result = await this.runClaudeCli(request);
|
|
@@ -8577,14 +9058,14 @@ function resolveClaudeCliExecutable(config) {
|
|
|
8577
9058
|
if (trimmed.length === 0) {
|
|
8578
9059
|
throw new Error(`${CLAUDE_CLI_EXECUTABLE_ENV} / claude-cli executable must not be empty`);
|
|
8579
9060
|
}
|
|
8580
|
-
return
|
|
9061
|
+
return expandHomeRelativePath2(trimmed);
|
|
8581
9062
|
}
|
|
8582
|
-
function
|
|
9063
|
+
function expandHomeRelativePath2(value) {
|
|
8583
9064
|
if (value === "~") {
|
|
8584
|
-
return
|
|
9065
|
+
return os4.homedir();
|
|
8585
9066
|
}
|
|
8586
9067
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
8587
|
-
return
|
|
9068
|
+
return path7.join(os4.homedir(), value.slice(2));
|
|
8588
9069
|
}
|
|
8589
9070
|
return value;
|
|
8590
9071
|
}
|
|
@@ -8971,12 +9452,203 @@ function createClaudeCliProvider(config, deps) {
|
|
|
8971
9452
|
|
|
8972
9453
|
// src/providers/codex-cli.ts
|
|
8973
9454
|
import { spawn as spawn2 } from "child_process";
|
|
8974
|
-
import { createHash as
|
|
8975
|
-
import { mkdir as
|
|
8976
|
-
import
|
|
8977
|
-
import
|
|
9455
|
+
import { createHash as createHash6, randomUUID } from "crypto";
|
|
9456
|
+
import { mkdir as mkdir6, mkdtemp as mkdtemp3, readFile as readFile7, rm as rm3, writeFile as writeFile6 } from "fs/promises";
|
|
9457
|
+
import os5 from "os";
|
|
9458
|
+
import path8 from "path";
|
|
9459
|
+
|
|
9460
|
+
// src/judges/memcorrect-rubrics.ts
|
|
9461
|
+
var OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION = "openai-responses-bench-v1";
|
|
9462
|
+
var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION = "memcorrect-correction-acceptance-v1";
|
|
9463
|
+
var MEMCORRECT_STALE_HARM_RUBRIC_VERSION = "memcorrect-stale-memory-harm-v1";
|
|
9464
|
+
var GENERAL_ANSWER_JUDGE_RUBRIC = [
|
|
9465
|
+
"Grade the predicted benchmark answer against the reference answer.",
|
|
9466
|
+
"A score of 1 means fully correct, 0 means fully incorrect, and values between 0 and 1 mean partially correct.",
|
|
9467
|
+
"Do not reward unsupported claims. Ignore harmless wording and formatting differences."
|
|
9468
|
+
].join(" ");
|
|
9469
|
+
var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC = [
|
|
9470
|
+
"Decide whether the memory system accepted the user's correction.",
|
|
9471
|
+
"Pass only when the corrected fact is reflected and the retired fact is not asserted as current.",
|
|
9472
|
+
"A quotation or correction-history record that clearly marks the retired fact as obsolete is not stale recall.",
|
|
9473
|
+
"Use a score of 1 for accepted, 0 for not accepted, and a fractional score only when the evidence is genuinely ambiguous."
|
|
9474
|
+
].join(" ");
|
|
9475
|
+
var MEMCORRECT_STALE_HARM_RUBRIC = [
|
|
9476
|
+
"Decide whether the memory system avoided stale-memory harm after a correction.",
|
|
9477
|
+
"Pass only when the answer does not present the retired fact as current and does not act on it.",
|
|
9478
|
+
"Correction provenance may mention the retired fact only when it is explicitly identified as obsolete.",
|
|
9479
|
+
"Use a score of 1 when no stale harm is present, 0 when stale information affected the answer, and a fractional score only for genuinely ambiguous evidence."
|
|
9480
|
+
].join(" ");
|
|
9481
|
+
|
|
9482
|
+
// src/providers/structured-judge.ts
|
|
9483
|
+
var VERDICT_JSON_SCHEMA = {
|
|
9484
|
+
type: "object",
|
|
9485
|
+
additionalProperties: false,
|
|
9486
|
+
required: ["score", "decision", "reason"],
|
|
9487
|
+
properties: {
|
|
9488
|
+
score: { type: "number", minimum: 0, maximum: 1 },
|
|
9489
|
+
decision: { type: "string", enum: ["pass", "partial", "fail"] },
|
|
9490
|
+
reason: { type: "string" }
|
|
9491
|
+
}
|
|
9492
|
+
};
|
|
9493
|
+
var ASSISTANT_RUBRIC_JSON_SCHEMA = {
|
|
9494
|
+
type: "object",
|
|
9495
|
+
additionalProperties: false,
|
|
9496
|
+
required: ["identity_accuracy", "stance_coherence", "novelty", "calibration", "notes"],
|
|
9497
|
+
properties: {
|
|
9498
|
+
identity_accuracy: { type: "number", minimum: 0, maximum: 5 },
|
|
9499
|
+
stance_coherence: { type: "number", minimum: 0, maximum: 5 },
|
|
9500
|
+
novelty: { type: "number", minimum: 0, maximum: 5 },
|
|
9501
|
+
calibration: { type: "number", minimum: 0, maximum: 5 },
|
|
9502
|
+
notes: { type: "string" }
|
|
9503
|
+
}
|
|
9504
|
+
};
|
|
9505
|
+
var StructuredJudgeError = class extends Error {
|
|
9506
|
+
code;
|
|
9507
|
+
retryable;
|
|
9508
|
+
httpStatus;
|
|
9509
|
+
telemetry;
|
|
9510
|
+
constructor(failure) {
|
|
9511
|
+
super(failure.error.message);
|
|
9512
|
+
this.name = "StructuredJudgeError";
|
|
9513
|
+
this.code = failure.error.code;
|
|
9514
|
+
this.retryable = failure.error.retryable;
|
|
9515
|
+
this.httpStatus = failure.error.httpStatus;
|
|
9516
|
+
this.telemetry = failure.telemetry;
|
|
9517
|
+
}
|
|
9518
|
+
};
|
|
9519
|
+
function isStructuredJudgeProvider(provider) {
|
|
9520
|
+
const candidate = provider;
|
|
9521
|
+
return typeof candidate.judge === "function" && typeof candidate.evaluateAssistantRubric === "function";
|
|
9522
|
+
}
|
|
9523
|
+
function createStructuredBenchJudge(provider, rubricVersion = OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION) {
|
|
9524
|
+
const scoreWithMetrics = async (question, predicted, expected, control) => unwrapJudgeResult(
|
|
9525
|
+
provider,
|
|
9526
|
+
await provider.judge({
|
|
9527
|
+
rubric: GENERAL_ANSWER_JUDGE_RUBRIC,
|
|
9528
|
+
rubricVersion,
|
|
9529
|
+
input: [`QUESTION: ${question}`, `REFERENCE_ANSWER: ${expected}`, `PREDICTED_ANSWER: ${predicted}`].join(
|
|
9530
|
+
"\n\n"
|
|
9531
|
+
),
|
|
9532
|
+
signal: control?.signal
|
|
9533
|
+
})
|
|
9534
|
+
);
|
|
9535
|
+
const scoreBinaryPrompt = async (prompt, control) => {
|
|
9536
|
+
const result = await provider.judge({
|
|
9537
|
+
rubric: `${GENERAL_ANSWER_JUDGE_RUBRIC} This evaluator is binary: score must be exactly 0 or 1.`,
|
|
9538
|
+
rubricVersion,
|
|
9539
|
+
input: prompt,
|
|
9540
|
+
signal: control?.signal
|
|
9541
|
+
});
|
|
9542
|
+
if (result.ok && result.verdict.score !== 0 && result.verdict.score !== 1) {
|
|
9543
|
+
throwJudgeFailure(provider, {
|
|
9544
|
+
ok: false,
|
|
9545
|
+
error: {
|
|
9546
|
+
code: "malformed_verdict",
|
|
9547
|
+
message: "Structured judge returned a non-binary verdict for a binary rubric.",
|
|
9548
|
+
retryable: false
|
|
9549
|
+
},
|
|
9550
|
+
telemetry: { ...result.telemetry, errorCode: "malformed_verdict" }
|
|
9551
|
+
});
|
|
9552
|
+
}
|
|
9553
|
+
return unwrapJudgeResult(provider, result);
|
|
9554
|
+
};
|
|
9555
|
+
const judgeSpecialized = async (request, rubric, control) => {
|
|
9556
|
+
const result = await provider.judge({
|
|
9557
|
+
rubric: rubric === "correction" ? MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC : MEMCORRECT_STALE_HARM_RUBRIC,
|
|
9558
|
+
rubricVersion: rubric === "correction" ? MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION : MEMCORRECT_STALE_HARM_RUBRIC_VERSION,
|
|
9559
|
+
input: serializeMemCorrectJudgeRequest(request),
|
|
9560
|
+
signal: control?.signal
|
|
9561
|
+
});
|
|
9562
|
+
if (!result.ok) {
|
|
9563
|
+
throwJudgeFailure(provider, result);
|
|
9564
|
+
}
|
|
9565
|
+
const base = unwrapJudgeResult(provider, result);
|
|
9566
|
+
return {
|
|
9567
|
+
...base,
|
|
9568
|
+
decision: result.verdict.decision,
|
|
9569
|
+
reason: result.verdict.reason,
|
|
9570
|
+
rubricVersion: result.telemetry.rubricVersion
|
|
9571
|
+
};
|
|
9572
|
+
};
|
|
9573
|
+
return {
|
|
9574
|
+
async score(question, predicted, expected, control) {
|
|
9575
|
+
return (await scoreWithMetrics(question, predicted, expected, control)).score;
|
|
9576
|
+
},
|
|
9577
|
+
scoreWithMetrics,
|
|
9578
|
+
scoreBinaryPrompt,
|
|
9579
|
+
judgeMemCorrectCorrectionAcceptance: (request, control) => judgeSpecialized(request, "correction", control),
|
|
9580
|
+
judgeMemCorrectStaleMemoryHarm: (request, control) => judgeSpecialized(request, "stale_harm", control)
|
|
9581
|
+
};
|
|
9582
|
+
}
|
|
9583
|
+
function parseStructuredJudgeVerdict(text) {
|
|
9584
|
+
let parsed;
|
|
9585
|
+
try {
|
|
9586
|
+
parsed = JSON.parse(text);
|
|
9587
|
+
} catch {
|
|
9588
|
+
return null;
|
|
9589
|
+
}
|
|
9590
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
9591
|
+
const candidate = parsed;
|
|
9592
|
+
if (Object.keys(candidate).sort().join(",") !== "decision,reason,score") return null;
|
|
9593
|
+
if (typeof candidate.score !== "number" || !Number.isFinite(candidate.score) || candidate.score < 0 || candidate.score > 1 || candidate.decision !== "pass" && candidate.decision !== "partial" && candidate.decision !== "fail" || typeof candidate.reason !== "string" || candidate.reason.trim().length === 0) {
|
|
9594
|
+
return null;
|
|
9595
|
+
}
|
|
9596
|
+
return {
|
|
9597
|
+
score: candidate.score,
|
|
9598
|
+
decision: candidate.decision,
|
|
9599
|
+
reason: candidate.reason.trim()
|
|
9600
|
+
};
|
|
9601
|
+
}
|
|
9602
|
+
function isValidAssistantRubric(text) {
|
|
9603
|
+
let parsed;
|
|
9604
|
+
try {
|
|
9605
|
+
parsed = JSON.parse(text);
|
|
9606
|
+
} catch {
|
|
9607
|
+
return false;
|
|
9608
|
+
}
|
|
9609
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
|
|
9610
|
+
const candidate = parsed;
|
|
9611
|
+
if (Object.keys(candidate).sort().join(",") !== "calibration,identity_accuracy,notes,novelty,stance_coherence") {
|
|
9612
|
+
return false;
|
|
9613
|
+
}
|
|
9614
|
+
return ["identity_accuracy", "stance_coherence", "novelty", "calibration"].every(
|
|
9615
|
+
(key) => typeof candidate[key] === "number" && Number.isFinite(candidate[key]) && candidate[key] >= 0 && candidate[key] <= 5
|
|
9616
|
+
) && typeof candidate.notes === "string";
|
|
9617
|
+
}
|
|
9618
|
+
function serializeMemCorrectJudgeRequest(request) {
|
|
9619
|
+
return JSON.stringify({
|
|
9620
|
+
taskId: request.taskId,
|
|
9621
|
+
query: request.query,
|
|
9622
|
+
retiredContent: request.retiredContent,
|
|
9623
|
+
correctedContent: request.correctedContent,
|
|
9624
|
+
evidence: {
|
|
9625
|
+
postCorrectionRecall: request.postCorrectionRecall,
|
|
9626
|
+
postMaintenanceRecall: request.postMaintenanceRecall,
|
|
9627
|
+
postReingestRecall: request.postReingestRecall
|
|
9628
|
+
}
|
|
9629
|
+
});
|
|
9630
|
+
}
|
|
9631
|
+
function unwrapJudgeResult(provider, result) {
|
|
9632
|
+
if (!result.ok) {
|
|
9633
|
+
throwJudgeFailure(provider, result);
|
|
9634
|
+
}
|
|
9635
|
+
return {
|
|
9636
|
+
score: result.verdict.score,
|
|
9637
|
+
tokens: {
|
|
9638
|
+
input: result.telemetry.inputTokens,
|
|
9639
|
+
output: result.telemetry.outputTokens
|
|
9640
|
+
},
|
|
9641
|
+
latencyMs: result.telemetry.latencyMs,
|
|
9642
|
+
model: result.telemetry.model
|
|
9643
|
+
};
|
|
9644
|
+
}
|
|
9645
|
+
function throwJudgeFailure(provider, failure) {
|
|
9646
|
+
throw provider.createJudgeError?.(failure) ?? new StructuredJudgeError(failure);
|
|
9647
|
+
}
|
|
9648
|
+
|
|
9649
|
+
// src/providers/codex-cli.ts
|
|
8978
9650
|
var DEFAULT_REASONING_EFFORT = "xhigh";
|
|
8979
|
-
var DEFAULT_SERVICE_TIER = "
|
|
9651
|
+
var DEFAULT_SERVICE_TIER = "default";
|
|
8980
9652
|
var CODEX_CLI_STDIO_LIMIT = 64e3;
|
|
8981
9653
|
var CODEX_CLI_PARENT_SIGNALS = [
|
|
8982
9654
|
"SIGHUP",
|
|
@@ -8987,12 +9659,8 @@ var CODEX_CLI_FORCED_PARENT_EXIT_MS = 1e3;
|
|
|
8987
9659
|
var CODEX_CLI_DIAGNOSTICS_DIR_ENV = "REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_DIR";
|
|
8988
9660
|
var CODEX_CLI_DIAGNOSTICS_MODE_ENV = "REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_MODE";
|
|
8989
9661
|
var CODEX_CLI_EXECUTABLE_ENV = "REMNIC_BENCH_CODEX_CLI_EXECUTABLE";
|
|
8990
|
-
var CODEX_CLI_TRANSPORT_ENV = "REMNIC_BENCH_CODEX_CLI_TRANSPORT";
|
|
8991
9662
|
var CODEX_CLI_VERSION_TIMEOUT_MS = 5e3;
|
|
8992
|
-
var
|
|
8993
|
-
var OPENAI_API_KEY_ENV = "OPENAI_API_KEY";
|
|
8994
|
-
var OPENAI_BASE_URL_ENV = "OPENAI_BASE_URL";
|
|
8995
|
-
var OPENAI_RESPONSES_BASE_URL = "https://api.openai.com/v1";
|
|
9663
|
+
var CODEX_CLI_PRE_START_ABORT_MESSAGE = "Codex CLI aborted before start.";
|
|
8996
9664
|
var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
8997
9665
|
"ALL_PROXY",
|
|
8998
9666
|
"APPDATA",
|
|
@@ -9010,9 +9678,6 @@ var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
|
9010
9678
|
"NODE_EXTRA_CA_CERTS",
|
|
9011
9679
|
"NO_PROXY",
|
|
9012
9680
|
"NUMBER_OF_PROCESSORS",
|
|
9013
|
-
OPENAI_BASE_URL_ENV,
|
|
9014
|
-
"OPENAI_ORGANIZATION",
|
|
9015
|
-
"OPENAI_PROJECT",
|
|
9016
9681
|
"OS",
|
|
9017
9682
|
"PATH",
|
|
9018
9683
|
"PATHEXT",
|
|
@@ -9040,7 +9705,7 @@ var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
|
9040
9705
|
]);
|
|
9041
9706
|
var activeCodexCliChildPids = /* @__PURE__ */ new Set();
|
|
9042
9707
|
var codexCliParentCleanupInstalled = false;
|
|
9043
|
-
var
|
|
9708
|
+
var codexCliLoginStatusCache = /* @__PURE__ */ new Map();
|
|
9044
9709
|
var CodexCliProvider = class {
|
|
9045
9710
|
provider = "codex-cli";
|
|
9046
9711
|
id;
|
|
@@ -9048,7 +9713,8 @@ var CodexCliProvider = class {
|
|
|
9048
9713
|
config;
|
|
9049
9714
|
runCodexCli;
|
|
9050
9715
|
runCodexVersion;
|
|
9051
|
-
|
|
9716
|
+
runCodexLoginStatus;
|
|
9717
|
+
requiresExactUsage;
|
|
9052
9718
|
usage = {
|
|
9053
9719
|
inputTokens: 0,
|
|
9054
9720
|
outputTokens: 0,
|
|
@@ -9058,23 +9724,31 @@ var CodexCliProvider = class {
|
|
|
9058
9724
|
this.config = config;
|
|
9059
9725
|
this.runCodexCli = deps.runCodexCli ?? runCodexCliCommand;
|
|
9060
9726
|
this.runCodexVersion = deps.runCodexVersion ?? runCodexVersionCommand;
|
|
9061
|
-
this.
|
|
9727
|
+
this.runCodexLoginStatus = deps.runCodexLoginStatus ?? runCodexLoginStatusCommand;
|
|
9728
|
+
this.requiresExactUsage = deps.runCodexCli === void 0;
|
|
9062
9729
|
this.id = `codex-cli:${config.model}`;
|
|
9063
9730
|
this.name = config.model;
|
|
9064
9731
|
}
|
|
9065
9732
|
async complete(prompt, opts = {}) {
|
|
9733
|
+
if (opts.signal?.aborted) {
|
|
9734
|
+
throw codexCliAbortError(opts.signal);
|
|
9735
|
+
}
|
|
9066
9736
|
const startedAt = performance.now();
|
|
9067
|
-
|
|
9068
|
-
|
|
9737
|
+
const creditBudget = resolveCodexCreditBudgetConfig(
|
|
9738
|
+
process.env,
|
|
9739
|
+
resolveBenchmarkRunId()
|
|
9740
|
+
);
|
|
9741
|
+
if (creditBudget) {
|
|
9742
|
+
await this.assertChatGptCreditAuth();
|
|
9069
9743
|
}
|
|
9070
9744
|
const maxAttempts = normalizeCodexCliMaxAttempts(
|
|
9071
|
-
this.config.retryOptions?.maxAttempts
|
|
9745
|
+
creditBudget ? 1 : this.config.retryOptions?.maxAttempts
|
|
9072
9746
|
);
|
|
9073
9747
|
let lastError;
|
|
9074
9748
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
9075
|
-
const tempDir = await mkdtemp3(
|
|
9076
|
-
const workspacePath =
|
|
9077
|
-
const outputPath =
|
|
9749
|
+
const tempDir = await mkdtemp3(path8.join(os5.tmpdir(), "remnic-codex-cli-"));
|
|
9750
|
+
const workspacePath = path8.join(tempDir, "workspace");
|
|
9751
|
+
const outputPath = path8.join(tempDir, "last-message.txt");
|
|
9078
9752
|
let diagnostics;
|
|
9079
9753
|
let diagnosticsFinished = false;
|
|
9080
9754
|
const finishDiagnostics = async (outcome) => {
|
|
@@ -9085,7 +9759,7 @@ var CodexCliProvider = class {
|
|
|
9085
9759
|
await finishCodexCliDiagnostics(diagnostics, startedAt, outcome);
|
|
9086
9760
|
};
|
|
9087
9761
|
try {
|
|
9088
|
-
await
|
|
9762
|
+
await mkdir6(workspacePath, { recursive: true });
|
|
9089
9763
|
const request = this.buildRunRequest(prompt, opts, workspacePath, outputPath);
|
|
9090
9764
|
diagnostics = await startCodexCliDiagnostics({
|
|
9091
9765
|
config: this.config,
|
|
@@ -9094,12 +9768,48 @@ var CodexCliProvider = class {
|
|
|
9094
9768
|
serviceTier: DEFAULT_SERVICE_TIER,
|
|
9095
9769
|
retry: { attempt, maxAttempts }
|
|
9096
9770
|
});
|
|
9097
|
-
const result = await
|
|
9771
|
+
const result = creditBudget ? await runWithinCodexCreditBudget({
|
|
9772
|
+
config: creditBudget,
|
|
9773
|
+
model: this.config.model,
|
|
9774
|
+
onUsagePersisted: (usage) => {
|
|
9775
|
+
this.recordUsage(usage.inputTokens, usage.outputTokens);
|
|
9776
|
+
},
|
|
9777
|
+
run: async () => {
|
|
9778
|
+
if (opts.signal?.aborted) {
|
|
9779
|
+
throw codexCliPreStartAbortError(opts.signal);
|
|
9780
|
+
}
|
|
9781
|
+
let value;
|
|
9782
|
+
try {
|
|
9783
|
+
value = await this.runCodexCli(request);
|
|
9784
|
+
} catch (error) {
|
|
9785
|
+
if (error instanceof CodexCreditDispatchError || error instanceof CodexCreditAccountingError) {
|
|
9786
|
+
throw error;
|
|
9787
|
+
}
|
|
9788
|
+
throw new CodexCreditAccountingError(
|
|
9789
|
+
`Codex CLI failed after dispatch; account balance must be reconciled before resuming: ${safeErrorMessage2(error)}`
|
|
9790
|
+
);
|
|
9791
|
+
}
|
|
9792
|
+
const usage = parseCodexJsonlUsage(
|
|
9793
|
+
`${value.stdout}
|
|
9794
|
+
${value.stderr}`
|
|
9795
|
+
);
|
|
9796
|
+
if (!usage) {
|
|
9797
|
+
throw new CodexCreditAccountingError(
|
|
9798
|
+
`Codex CLI exited ${value.status ?? "without a status"} without exact turn.completed usage; account balance must be reconciled before resuming.`
|
|
9799
|
+
);
|
|
9800
|
+
}
|
|
9801
|
+
return { value, usage };
|
|
9802
|
+
}
|
|
9803
|
+
}) : await this.runCodexCli(request);
|
|
9804
|
+
const exactUsage = parseCodexJsonlUsage(
|
|
9805
|
+
`${result.stdout}
|
|
9806
|
+
${result.stderr}`
|
|
9807
|
+
);
|
|
9808
|
+
if (!creditBudget && exactUsage) {
|
|
9809
|
+
this.recordUsage(exactUsage.inputTokens, exactUsage.outputTokens);
|
|
9810
|
+
}
|
|
9098
9811
|
if (result.status !== 0) {
|
|
9099
|
-
const
|
|
9100
|
-
const error = new Error(
|
|
9101
|
-
`Codex CLI completion failed (${exitLabel}): ${summarizeProcessOutput2(result.stderr, result.stdout)}`
|
|
9102
|
-
);
|
|
9812
|
+
const error = codexCliResultError(result);
|
|
9103
9813
|
if (attempt < maxAttempts && isRetryableCodexCliResult(result)) {
|
|
9104
9814
|
lastError = error;
|
|
9105
9815
|
await finishDiagnostics({
|
|
@@ -9126,12 +9836,14 @@ var CodexCliProvider = class {
|
|
|
9126
9836
|
throw error;
|
|
9127
9837
|
}
|
|
9128
9838
|
await finishDiagnostics({ result });
|
|
9129
|
-
const
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9839
|
+
const nativeUsage = exactUsage ?? (this.requiresExactUsage ? requireCodexJsonlUsage(result) : readCodexUsage(result, text));
|
|
9840
|
+
const tokens = {
|
|
9841
|
+
input: nativeUsage.inputTokens,
|
|
9842
|
+
output: nativeUsage.outputTokens
|
|
9843
|
+
};
|
|
9844
|
+
if (!creditBudget && !exactUsage) {
|
|
9845
|
+
this.recordUsage(tokens.input, tokens.output);
|
|
9846
|
+
}
|
|
9135
9847
|
return {
|
|
9136
9848
|
text,
|
|
9137
9849
|
tokens,
|
|
@@ -9139,15 +9851,93 @@ ${result.stdout}`,
|
|
|
9139
9851
|
model: this.config.model
|
|
9140
9852
|
};
|
|
9141
9853
|
} catch (error) {
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9854
|
+
const surfacedError = unwrapCodexCliPreStartAbort(error);
|
|
9855
|
+
lastError = surfacedError;
|
|
9856
|
+
await finishDiagnostics({ error: surfacedError });
|
|
9857
|
+
throw surfacedError;
|
|
9145
9858
|
} finally {
|
|
9146
9859
|
await rm3(tempDir, { force: true, recursive: true });
|
|
9147
9860
|
}
|
|
9148
9861
|
}
|
|
9149
9862
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
9150
9863
|
}
|
|
9864
|
+
async judge(request) {
|
|
9865
|
+
const startedAt = performance.now();
|
|
9866
|
+
try {
|
|
9867
|
+
const completion = await this.complete(request.input, {
|
|
9868
|
+
systemPrompt: buildCodexStructuredJudgePrompt(request.rubric),
|
|
9869
|
+
temperature: 0,
|
|
9870
|
+
maxTokens: request.maxTokens ?? 256,
|
|
9871
|
+
signal: request.signal
|
|
9872
|
+
});
|
|
9873
|
+
const telemetry = {
|
|
9874
|
+
model: completion.model,
|
|
9875
|
+
rubricVersion: request.rubricVersion,
|
|
9876
|
+
inputTokens: completion.tokens.input,
|
|
9877
|
+
outputTokens: completion.tokens.output,
|
|
9878
|
+
latencyMs: completion.latencyMs
|
|
9879
|
+
};
|
|
9880
|
+
const verdict = parseStructuredJudgeVerdict(completion.text);
|
|
9881
|
+
if (!verdict) {
|
|
9882
|
+
return {
|
|
9883
|
+
ok: false,
|
|
9884
|
+
error: {
|
|
9885
|
+
code: "malformed_verdict",
|
|
9886
|
+
message: "Codex CLI returned a verdict that failed schema validation.",
|
|
9887
|
+
retryable: false
|
|
9888
|
+
},
|
|
9889
|
+
telemetry: { ...telemetry, errorCode: "malformed_verdict" }
|
|
9890
|
+
};
|
|
9891
|
+
}
|
|
9892
|
+
return { ok: true, verdict, telemetry };
|
|
9893
|
+
} catch (error) {
|
|
9894
|
+
const aborted = isCodexStructuredJudgeAbort(error, request.signal);
|
|
9895
|
+
const errorCode = aborted ? "aborted" : "transport_error";
|
|
9896
|
+
return {
|
|
9897
|
+
ok: false,
|
|
9898
|
+
error: {
|
|
9899
|
+
code: errorCode,
|
|
9900
|
+
message: aborted ? "Codex CLI judging was aborted by the caller." : `Codex CLI judging failed (${structuredJudgeErrorName(error)}).`,
|
|
9901
|
+
retryable: false
|
|
9902
|
+
},
|
|
9903
|
+
telemetry: {
|
|
9904
|
+
model: this.config.model,
|
|
9905
|
+
rubricVersion: request.rubricVersion,
|
|
9906
|
+
inputTokens: 0,
|
|
9907
|
+
outputTokens: 0,
|
|
9908
|
+
latencyMs: Math.round(performance.now() - startedAt),
|
|
9909
|
+
errorCode
|
|
9910
|
+
}
|
|
9911
|
+
};
|
|
9912
|
+
}
|
|
9913
|
+
}
|
|
9914
|
+
async evaluateAssistantRubric(request) {
|
|
9915
|
+
const rubricVersion = `sealed:${request.rubricId}`;
|
|
9916
|
+
const completion = await this.complete(request.user, {
|
|
9917
|
+
systemPrompt: buildCodexAssistantRubricPrompt(request.system),
|
|
9918
|
+
temperature: 0,
|
|
9919
|
+
maxTokens: 512
|
|
9920
|
+
});
|
|
9921
|
+
if (isValidAssistantRubric(completion.text)) {
|
|
9922
|
+
return completion.text;
|
|
9923
|
+
}
|
|
9924
|
+
throw new StructuredJudgeError({
|
|
9925
|
+
ok: false,
|
|
9926
|
+
error: {
|
|
9927
|
+
code: "malformed_verdict",
|
|
9928
|
+
message: "Codex CLI returned an invalid sealed assistant-rubric verdict.",
|
|
9929
|
+
retryable: false
|
|
9930
|
+
},
|
|
9931
|
+
telemetry: {
|
|
9932
|
+
model: completion.model,
|
|
9933
|
+
rubricVersion,
|
|
9934
|
+
inputTokens: completion.tokens.input,
|
|
9935
|
+
outputTokens: completion.tokens.output,
|
|
9936
|
+
latencyMs: completion.latencyMs,
|
|
9937
|
+
errorCode: "malformed_verdict"
|
|
9938
|
+
}
|
|
9939
|
+
});
|
|
9940
|
+
}
|
|
9151
9941
|
async discover() {
|
|
9152
9942
|
const version = await this.runCodexVersion(
|
|
9153
9943
|
resolveCodexCliExecutable(this.config),
|
|
@@ -9177,6 +9967,26 @@ ${result.stdout}`,
|
|
|
9177
9967
|
totalTokens: 0
|
|
9178
9968
|
};
|
|
9179
9969
|
}
|
|
9970
|
+
async assertChatGptCreditAuth() {
|
|
9971
|
+
const executable = resolveCodexCliExecutable(this.config);
|
|
9972
|
+
const env = buildIsolatedCodexEnv();
|
|
9973
|
+
const cacheKey = `${executable}\0${env.CODEX_HOME ?? env.HOME ?? ""}`;
|
|
9974
|
+
let check = codexCliLoginStatusCache.get(cacheKey);
|
|
9975
|
+
if (!check) {
|
|
9976
|
+
check = this.runCodexLoginStatus(executable, env).then((result) => {
|
|
9977
|
+
const output = `${result.stdout}
|
|
9978
|
+
${result.stderr}`.trim();
|
|
9979
|
+
if (result.status !== 0 || !/logged in using chatgpt/i.test(output)) {
|
|
9980
|
+
throw new Error(
|
|
9981
|
+
`Bounded Codex credit runs require ChatGPT-backed Codex CLI authentication; \`codex login status\` reported: ${output || `exit ${result.status ?? "unknown"}`}`
|
|
9982
|
+
);
|
|
9983
|
+
}
|
|
9984
|
+
});
|
|
9985
|
+
codexCliLoginStatusCache.set(cacheKey, check);
|
|
9986
|
+
check.catch(() => codexCliLoginStatusCache.delete(cacheKey));
|
|
9987
|
+
}
|
|
9988
|
+
await check;
|
|
9989
|
+
}
|
|
9180
9990
|
recordUsage(inputTokens, outputTokens) {
|
|
9181
9991
|
this.usage = {
|
|
9182
9992
|
inputTokens: this.usage.inputTokens + inputTokens,
|
|
@@ -9184,126 +9994,57 @@ ${result.stdout}`,
|
|
|
9184
9994
|
totalTokens: this.usage.totalTokens + inputTokens + outputTokens
|
|
9185
9995
|
};
|
|
9186
9996
|
}
|
|
9187
|
-
async shouldUseResponsesFallback() {
|
|
9188
|
-
const transport = process.env[CODEX_CLI_TRANSPORT_ENV]?.trim().toLowerCase();
|
|
9189
|
-
if (transport === "cli") {
|
|
9190
|
-
return false;
|
|
9191
|
-
}
|
|
9192
|
-
if (transport === "responses") {
|
|
9193
|
-
return true;
|
|
9194
|
-
}
|
|
9195
|
-
if (!this.shouldProbeCliHealth || this.resolveOpenAiApiKey().length === 0) {
|
|
9196
|
-
return false;
|
|
9197
|
-
}
|
|
9198
|
-
return !await this.isCliHealthy();
|
|
9199
|
-
}
|
|
9200
|
-
async isCliHealthy() {
|
|
9201
|
-
const executable = resolveCodexCliExecutable(this.config);
|
|
9202
|
-
const env = buildIsolatedCodexEnv(this.config.apiKey);
|
|
9203
|
-
if (this.runCodexVersion !== runCodexVersionCommand) {
|
|
9204
|
-
return this.probeCliHealth(executable, env);
|
|
9205
|
-
}
|
|
9206
|
-
const cacheKey = `${executable}\0${env.PATH ?? ""}`;
|
|
9207
|
-
const cached = codexCliHealthCache.get(cacheKey);
|
|
9208
|
-
if (cached && Date.now() - cached.checkedAt < CODEX_CLI_HEALTH_CACHE_TTL_MS) {
|
|
9209
|
-
return cached.promise;
|
|
9210
|
-
}
|
|
9211
|
-
if (cached) {
|
|
9212
|
-
codexCliHealthCache.delete(cacheKey);
|
|
9213
|
-
}
|
|
9214
|
-
const promise = this.probeCliHealth(executable, env).then((healthy) => {
|
|
9215
|
-
if (!healthy) {
|
|
9216
|
-
codexCliHealthCache.delete(cacheKey);
|
|
9217
|
-
}
|
|
9218
|
-
return healthy;
|
|
9219
|
-
});
|
|
9220
|
-
codexCliHealthCache.set(cacheKey, { checkedAt: Date.now(), promise });
|
|
9221
|
-
return promise;
|
|
9222
|
-
}
|
|
9223
|
-
async probeCliHealth(executable, env) {
|
|
9224
|
-
try {
|
|
9225
|
-
const version = await this.runCodexVersion(executable, env);
|
|
9226
|
-
return version.status === 0;
|
|
9227
|
-
} catch {
|
|
9228
|
-
return false;
|
|
9229
|
-
}
|
|
9230
|
-
}
|
|
9231
|
-
resolveOpenAiApiKey() {
|
|
9232
|
-
return (this.config.apiKey ?? process.env[OPENAI_API_KEY_ENV] ?? "").trim();
|
|
9233
|
-
}
|
|
9234
|
-
async completeViaResponsesApi(prompt, opts, startedAt) {
|
|
9235
|
-
const apiKey = this.resolveOpenAiApiKey();
|
|
9236
|
-
if (apiKey.length === 0) {
|
|
9237
|
-
throw new Error(
|
|
9238
|
-
`Codex CLI fallback requires ${OPENAI_API_KEY_ENV} or codex-cli apiKey.`
|
|
9239
|
-
);
|
|
9240
|
-
}
|
|
9241
|
-
const serviceTier = responsesApiServiceTier(DEFAULT_SERVICE_TIER);
|
|
9242
|
-
const body = {
|
|
9243
|
-
model: this.config.model,
|
|
9244
|
-
instructions: buildResponsesInstructions(opts.systemPrompt),
|
|
9245
|
-
input: prompt,
|
|
9246
|
-
reasoning: {
|
|
9247
|
-
effort: this.config.reasoningEffort ?? DEFAULT_REASONING_EFFORT
|
|
9248
|
-
},
|
|
9249
|
-
...serviceTier ? { service_tier: serviceTier } : {},
|
|
9250
|
-
max_output_tokens: Math.max(1, Math.floor(opts.maxTokens ?? 1024)),
|
|
9251
|
-
store: false
|
|
9252
|
-
};
|
|
9253
|
-
const response = await retryFetch(
|
|
9254
|
-
this.responsesApiUrl(),
|
|
9255
|
-
{
|
|
9256
|
-
method: "POST",
|
|
9257
|
-
headers: {
|
|
9258
|
-
"content-type": "application/json",
|
|
9259
|
-
authorization: `Bearer ${apiKey}`
|
|
9260
|
-
},
|
|
9261
|
-
signal: opts.signal,
|
|
9262
|
-
body: JSON.stringify(body)
|
|
9263
|
-
},
|
|
9264
|
-
this.config.retryOptions
|
|
9265
|
-
);
|
|
9266
|
-
if (!response.ok) {
|
|
9267
|
-
throw new Error(
|
|
9268
|
-
`Codex CLI Responses API fallback failed: ${response.status} ${response.statusText}${await readResponseErrorBody(response)}`
|
|
9269
|
-
);
|
|
9270
|
-
}
|
|
9271
|
-
const payload = await response.json();
|
|
9272
|
-
const text = extractResponsesOutputText(payload).trim();
|
|
9273
|
-
if (text.length === 0) {
|
|
9274
|
-
throw new Error("Codex CLI Responses API fallback returned no text.");
|
|
9275
|
-
}
|
|
9276
|
-
const inputTokens = payload.usage?.input_tokens ?? 0;
|
|
9277
|
-
const outputTokens = payload.usage?.output_tokens ?? 0;
|
|
9278
|
-
this.recordUsage(inputTokens, outputTokens);
|
|
9279
|
-
return {
|
|
9280
|
-
text,
|
|
9281
|
-
tokens: { input: inputTokens, output: outputTokens },
|
|
9282
|
-
latencyMs: Math.round(performance.now() - startedAt),
|
|
9283
|
-
model: payload.model ?? this.config.model
|
|
9284
|
-
};
|
|
9285
|
-
}
|
|
9286
|
-
responsesApiUrl() {
|
|
9287
|
-
const baseUrl = (this.config.baseUrl ?? OPENAI_RESPONSES_BASE_URL).replace(
|
|
9288
|
-
/\/$/,
|
|
9289
|
-
""
|
|
9290
|
-
);
|
|
9291
|
-
return baseUrl.endsWith("/v1") ? `${baseUrl}/responses` : `${baseUrl}/v1/responses`;
|
|
9292
|
-
}
|
|
9293
9997
|
buildRunRequest(prompt, opts, workspacePath, outputPath) {
|
|
9294
9998
|
const reasoningEffort = this.config.reasoningEffort ?? DEFAULT_REASONING_EFFORT;
|
|
9295
9999
|
const args = [
|
|
9296
10000
|
"exec",
|
|
10001
|
+
"--strict-config",
|
|
9297
10002
|
"--model",
|
|
9298
10003
|
this.config.model,
|
|
9299
10004
|
"--config",
|
|
9300
10005
|
`model_reasoning_effort=${tomlString(reasoningEffort)}`,
|
|
9301
10006
|
"--config",
|
|
9302
|
-
`service_tier=${tomlString(DEFAULT_SERVICE_TIER)}`,
|
|
9303
|
-
"--config",
|
|
9304
10007
|
'approval_policy="never"',
|
|
10008
|
+
"--config",
|
|
10009
|
+
'web_search="disabled"',
|
|
10010
|
+
"--disable",
|
|
10011
|
+
"hooks",
|
|
10012
|
+
"--disable",
|
|
10013
|
+
"shell_tool",
|
|
10014
|
+
"--disable",
|
|
10015
|
+
"unified_exec",
|
|
10016
|
+
"--disable",
|
|
10017
|
+
"apps",
|
|
10018
|
+
"--disable",
|
|
10019
|
+
"plugins",
|
|
10020
|
+
"--disable",
|
|
10021
|
+
"remote_plugin",
|
|
10022
|
+
"--disable",
|
|
10023
|
+
"multi_agent",
|
|
10024
|
+
"--disable",
|
|
10025
|
+
"browser_use",
|
|
10026
|
+
"--disable",
|
|
10027
|
+
"browser_use_external",
|
|
10028
|
+
"--disable",
|
|
10029
|
+
"browser_use_full_cdp_access",
|
|
10030
|
+
"--disable",
|
|
10031
|
+
"computer_use",
|
|
10032
|
+
"--disable",
|
|
10033
|
+
"image_generation",
|
|
10034
|
+
"--disable",
|
|
10035
|
+
"in_app_browser",
|
|
10036
|
+
"--disable",
|
|
10037
|
+
"goals",
|
|
10038
|
+
"--disable",
|
|
10039
|
+
"memories",
|
|
10040
|
+
"--disable",
|
|
10041
|
+
"chronicle",
|
|
9305
10042
|
"--disable",
|
|
9306
|
-
"
|
|
10043
|
+
"tool_suggest",
|
|
10044
|
+
"--disable",
|
|
10045
|
+
"workspace_dependencies",
|
|
10046
|
+
"--disable",
|
|
10047
|
+
"shell_snapshot",
|
|
9307
10048
|
"--ephemeral",
|
|
9308
10049
|
"--ignore-user-config",
|
|
9309
10050
|
"--ignore-rules",
|
|
@@ -9312,6 +10053,7 @@ ${result.stdout}`,
|
|
|
9312
10053
|
"--cd",
|
|
9313
10054
|
workspacePath,
|
|
9314
10055
|
"--skip-git-repo-check",
|
|
10056
|
+
"--json",
|
|
9315
10057
|
"--output-last-message",
|
|
9316
10058
|
outputPath,
|
|
9317
10059
|
"-"
|
|
@@ -9324,50 +10066,10 @@ ${result.stdout}`,
|
|
|
9324
10066
|
workspacePath,
|
|
9325
10067
|
timeoutMs: this.config.retryOptions?.timeoutMs,
|
|
9326
10068
|
signal: opts.signal,
|
|
9327
|
-
env: buildIsolatedCodexEnv(
|
|
10069
|
+
env: buildIsolatedCodexEnv()
|
|
9328
10070
|
};
|
|
9329
10071
|
}
|
|
9330
10072
|
};
|
|
9331
|
-
function responsesApiServiceTier(serviceTier) {
|
|
9332
|
-
if (serviceTier === "auto" || serviceTier === "default" || serviceTier === "flex" || serviceTier === "scale" || serviceTier === "priority") {
|
|
9333
|
-
return serviceTier;
|
|
9334
|
-
}
|
|
9335
|
-
return void 0;
|
|
9336
|
-
}
|
|
9337
|
-
function buildResponsesInstructions(systemPrompt) {
|
|
9338
|
-
return [
|
|
9339
|
-
"You are acting as a benchmark LLM completion endpoint, not as a coding agent.",
|
|
9340
|
-
"Use only the user input and the benchmark system instructions.",
|
|
9341
|
-
"Do not inspect files, run commands, browse, use tools, or use persisted memory.",
|
|
9342
|
-
"Return only the final answer text. If the request asks for JSON, return raw JSON only.",
|
|
9343
|
-
...systemPrompt?.trim() ? ["", systemPrompt.trim()] : []
|
|
9344
|
-
].join("\n");
|
|
9345
|
-
}
|
|
9346
|
-
async function readResponseErrorBody(response) {
|
|
9347
|
-
try {
|
|
9348
|
-
const body = await response.text();
|
|
9349
|
-
return body.trim().length > 0 ? ` \u2014 ${body.slice(0, 1e3)}` : "";
|
|
9350
|
-
} catch {
|
|
9351
|
-
return "";
|
|
9352
|
-
}
|
|
9353
|
-
}
|
|
9354
|
-
function extractResponsesOutputText(payload) {
|
|
9355
|
-
if (typeof payload.output_text === "string" && payload.output_text.length > 0) {
|
|
9356
|
-
return payload.output_text;
|
|
9357
|
-
}
|
|
9358
|
-
const parts = [];
|
|
9359
|
-
for (const item of payload.output ?? []) {
|
|
9360
|
-
if (typeof item.text === "string" && item.text.length > 0) {
|
|
9361
|
-
parts.push(item.text);
|
|
9362
|
-
}
|
|
9363
|
-
for (const content of item.content ?? []) {
|
|
9364
|
-
if (typeof content.text === "string" && content.text.length > 0 && (content.type === void 0 || content.type.endsWith("_text"))) {
|
|
9365
|
-
parts.push(content.text);
|
|
9366
|
-
}
|
|
9367
|
-
}
|
|
9368
|
-
}
|
|
9369
|
-
return parts.join("\n");
|
|
9370
|
-
}
|
|
9371
10073
|
function runCodexVersionCommand(executable, env) {
|
|
9372
10074
|
return new Promise((resolve, reject) => {
|
|
9373
10075
|
const child = spawn2(executable, ["--version"], {
|
|
@@ -9425,6 +10127,58 @@ Codex CLI --version timed out after ${CODEX_CLI_VERSION_TIMEOUT_MS}ms.`
|
|
|
9425
10127
|
});
|
|
9426
10128
|
});
|
|
9427
10129
|
}
|
|
10130
|
+
function runCodexLoginStatusCommand(executable, env) {
|
|
10131
|
+
return new Promise((resolve, reject) => {
|
|
10132
|
+
const child = spawn2(executable, ["login", "status"], {
|
|
10133
|
+
env,
|
|
10134
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
10135
|
+
detached: process.platform !== "win32",
|
|
10136
|
+
windowsHide: true
|
|
10137
|
+
});
|
|
10138
|
+
let stdout = "";
|
|
10139
|
+
let stderr = "";
|
|
10140
|
+
let killTimeout;
|
|
10141
|
+
const terminate = (signal) => {
|
|
10142
|
+
if (child.pid && process.platform !== "win32") {
|
|
10143
|
+
try {
|
|
10144
|
+
process.kill(-child.pid, signal);
|
|
10145
|
+
return;
|
|
10146
|
+
} catch {
|
|
10147
|
+
}
|
|
10148
|
+
}
|
|
10149
|
+
child.kill(signal);
|
|
10150
|
+
};
|
|
10151
|
+
const timeout = setTimeout(() => {
|
|
10152
|
+
stderr = appendBounded2(
|
|
10153
|
+
stderr,
|
|
10154
|
+
`
|
|
10155
|
+
Codex CLI login status timed out after ${CODEX_CLI_VERSION_TIMEOUT_MS}ms.`
|
|
10156
|
+
);
|
|
10157
|
+
terminate("SIGTERM");
|
|
10158
|
+
killTimeout = setTimeout(() => terminate("SIGKILL"), 1e3);
|
|
10159
|
+
killTimeout.unref();
|
|
10160
|
+
}, CODEX_CLI_VERSION_TIMEOUT_MS);
|
|
10161
|
+
timeout.unref();
|
|
10162
|
+
child.stdout?.setEncoding("utf8");
|
|
10163
|
+
child.stderr?.setEncoding("utf8");
|
|
10164
|
+
child.stdout?.on("data", (chunk) => {
|
|
10165
|
+
stdout = appendBounded2(stdout, chunk);
|
|
10166
|
+
});
|
|
10167
|
+
child.stderr?.on("data", (chunk) => {
|
|
10168
|
+
stderr = appendBounded2(stderr, chunk);
|
|
10169
|
+
});
|
|
10170
|
+
child.on("error", (error) => {
|
|
10171
|
+
clearTimeout(timeout);
|
|
10172
|
+
if (killTimeout) clearTimeout(killTimeout);
|
|
10173
|
+
reject(error);
|
|
10174
|
+
});
|
|
10175
|
+
child.on("close", (status) => {
|
|
10176
|
+
clearTimeout(timeout);
|
|
10177
|
+
if (killTimeout) clearTimeout(killTimeout);
|
|
10178
|
+
resolve({ status, stdout, stderr });
|
|
10179
|
+
});
|
|
10180
|
+
});
|
|
10181
|
+
}
|
|
9428
10182
|
function resolveCodexCliExecutable(config) {
|
|
9429
10183
|
const configured = config.executable ?? process.env[CODEX_CLI_EXECUTABLE_ENV];
|
|
9430
10184
|
if (configured === void 0) {
|
|
@@ -9436,7 +10190,7 @@ function resolveCodexCliExecutable(config) {
|
|
|
9436
10190
|
`${CODEX_CLI_EXECUTABLE_ENV} / codex-cli executable must not be empty`
|
|
9437
10191
|
);
|
|
9438
10192
|
}
|
|
9439
|
-
return
|
|
10193
|
+
return expandHomeRelativePath3(trimmed);
|
|
9440
10194
|
}
|
|
9441
10195
|
function buildCodexCompletionPrompt(userPrompt, systemPrompt) {
|
|
9442
10196
|
const payload = {
|
|
@@ -9454,21 +10208,13 @@ function buildCodexCompletionPrompt(userPrompt, systemPrompt) {
|
|
|
9454
10208
|
JSON.stringify(payload, null, 2)
|
|
9455
10209
|
].join("\n");
|
|
9456
10210
|
}
|
|
9457
|
-
function buildIsolatedCodexEnv(
|
|
10211
|
+
function buildIsolatedCodexEnv() {
|
|
9458
10212
|
const env = {};
|
|
9459
10213
|
for (const [key, value] of Object.entries(process.env)) {
|
|
9460
10214
|
if (value !== void 0 && isAllowedCodexRuntimeEnvKey(key)) {
|
|
9461
10215
|
env[key] = value;
|
|
9462
10216
|
}
|
|
9463
10217
|
}
|
|
9464
|
-
const resolvedApiKey = (apiKey ?? process.env[OPENAI_API_KEY_ENV] ?? "").trim();
|
|
9465
|
-
if (resolvedApiKey.length > 0) {
|
|
9466
|
-
env[OPENAI_API_KEY_ENV] = resolvedApiKey;
|
|
9467
|
-
}
|
|
9468
|
-
const resolvedBaseUrl = (baseUrl ?? process.env[OPENAI_BASE_URL_ENV] ?? "").trim();
|
|
9469
|
-
if (resolvedBaseUrl.length > 0) {
|
|
9470
|
-
env[OPENAI_BASE_URL_ENV] = resolvedBaseUrl;
|
|
9471
|
-
}
|
|
9472
10218
|
return env;
|
|
9473
10219
|
}
|
|
9474
10220
|
function isAllowedCodexRuntimeEnvKey(key) {
|
|
@@ -9481,7 +10227,7 @@ async function startCodexCliDiagnostics(args) {
|
|
|
9481
10227
|
return void 0;
|
|
9482
10228
|
}
|
|
9483
10229
|
try {
|
|
9484
|
-
await
|
|
10230
|
+
await mkdir6(diagnosticsDir, { recursive: true, mode: 448 });
|
|
9485
10231
|
const id = `${Date.now()}-${process.pid}-${randomUUID()}`;
|
|
9486
10232
|
const promptStats = inspectCodexCompletionPrompt(args.request.input);
|
|
9487
10233
|
const mode = resolveCodexCliDiagnosticsMode(args.config);
|
|
@@ -9494,10 +10240,10 @@ async function startCodexCliDiagnostics(args) {
|
|
|
9494
10240
|
model: args.config.model,
|
|
9495
10241
|
reasoningEffort: args.reasoningEffort,
|
|
9496
10242
|
serviceTier: args.serviceTier,
|
|
9497
|
-
executable:
|
|
10243
|
+
executable: path8.basename(args.request.executable),
|
|
9498
10244
|
...args.request.timeoutMs ? { timeoutMs: args.request.timeoutMs } : {},
|
|
9499
|
-
workspaceBasename:
|
|
9500
|
-
outputBasename:
|
|
10245
|
+
workspaceBasename: path8.basename(args.request.workspacePath),
|
|
10246
|
+
outputBasename: path8.basename(args.request.outputPath),
|
|
9501
10247
|
prompt: promptStats,
|
|
9502
10248
|
command: {
|
|
9503
10249
|
args: redactCodexCliArgs(args.request.args)
|
|
@@ -9505,7 +10251,7 @@ async function startCodexCliDiagnostics(args) {
|
|
|
9505
10251
|
retry: args.retry,
|
|
9506
10252
|
...mode === "full" ? { fullPrompt: args.request.input } : {}
|
|
9507
10253
|
};
|
|
9508
|
-
const filePath =
|
|
10254
|
+
const filePath = path8.join(diagnosticsDir, `${id}.json`);
|
|
9509
10255
|
await writeCodexCliDiagnosticRecord(filePath, record);
|
|
9510
10256
|
return { path: filePath, record };
|
|
9511
10257
|
} catch {
|
|
@@ -9548,7 +10294,7 @@ async function finishCodexCliDiagnostics(handle, startedAt, outcome) {
|
|
|
9548
10294
|
}
|
|
9549
10295
|
}
|
|
9550
10296
|
async function writeCodexCliDiagnosticRecord(filePath, record) {
|
|
9551
|
-
await
|
|
10297
|
+
await writeFile6(filePath, `${JSON.stringify(record, null, 2)}
|
|
9552
10298
|
`, {
|
|
9553
10299
|
encoding: "utf8",
|
|
9554
10300
|
mode: 384
|
|
@@ -9557,14 +10303,14 @@ async function writeCodexCliDiagnosticRecord(filePath, record) {
|
|
|
9557
10303
|
function resolveCodexCliDiagnosticsDir(config) {
|
|
9558
10304
|
const dir = config.diagnosticsDir ?? process.env[CODEX_CLI_DIAGNOSTICS_DIR_ENV];
|
|
9559
10305
|
const trimmed = typeof dir === "string" ? dir.trim() : "";
|
|
9560
|
-
return trimmed.length > 0 ?
|
|
10306
|
+
return trimmed.length > 0 ? path8.resolve(expandHomeRelativePath3(trimmed)) : void 0;
|
|
9561
10307
|
}
|
|
9562
|
-
function
|
|
10308
|
+
function expandHomeRelativePath3(value) {
|
|
9563
10309
|
if (value === "~") {
|
|
9564
|
-
return
|
|
10310
|
+
return os5.homedir();
|
|
9565
10311
|
}
|
|
9566
10312
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
9567
|
-
return
|
|
10313
|
+
return path8.join(os5.homedir(), value.slice(2));
|
|
9568
10314
|
}
|
|
9569
10315
|
return value;
|
|
9570
10316
|
}
|
|
@@ -9574,7 +10320,7 @@ function resolveCodexCliDiagnosticsMode(config) {
|
|
|
9574
10320
|
}
|
|
9575
10321
|
function inspectCodexCompletionPrompt(prompt) {
|
|
9576
10322
|
const stats = {
|
|
9577
|
-
sha256:
|
|
10323
|
+
sha256: createHash6("sha256").update(prompt).digest("hex"),
|
|
9578
10324
|
chars: prompt.length,
|
|
9579
10325
|
lines: prompt.length === 0 ? 0 : prompt.split("\n").length
|
|
9580
10326
|
};
|
|
@@ -9614,13 +10360,7 @@ function redactCodexCliArgs(args) {
|
|
|
9614
10360
|
function runCodexCliCommand(request) {
|
|
9615
10361
|
return new Promise((resolve, reject) => {
|
|
9616
10362
|
if (request.signal?.aborted) {
|
|
9617
|
-
|
|
9618
|
-
status: 124,
|
|
9619
|
-
signal: null,
|
|
9620
|
-
stdout: "",
|
|
9621
|
-
stderr: "Codex CLI aborted before start.",
|
|
9622
|
-
outputText: ""
|
|
9623
|
-
});
|
|
10363
|
+
reject(codexCliPreStartAbortError(request.signal));
|
|
9624
10364
|
return;
|
|
9625
10365
|
}
|
|
9626
10366
|
const child = spawn2(request.executable, request.args, {
|
|
@@ -9704,7 +10444,15 @@ Codex CLI stdin error: ${error.code ?? error.message}`
|
|
|
9704
10444
|
unregisterActiveCodexCliChild(child.pid);
|
|
9705
10445
|
}
|
|
9706
10446
|
request.signal?.removeEventListener("abort", onAbort);
|
|
9707
|
-
reject(
|
|
10447
|
+
reject(
|
|
10448
|
+
child.pid ? new Error(
|
|
10449
|
+
`Codex CLI failed after its process started: ${safeErrorMessage2(error)}`,
|
|
10450
|
+
{ cause: error }
|
|
10451
|
+
) : new CodexCreditDispatchError(
|
|
10452
|
+
`Codex CLI could not start: ${safeErrorMessage2(error)}`,
|
|
10453
|
+
{ cause: error }
|
|
10454
|
+
)
|
|
10455
|
+
);
|
|
9708
10456
|
});
|
|
9709
10457
|
child.on("close", async (status, signal) => {
|
|
9710
10458
|
if (timeout) {
|
|
@@ -9740,10 +10488,17 @@ Codex CLI timed out after ${request.timeoutMs}ms.`
|
|
|
9740
10488
|
return;
|
|
9741
10489
|
}
|
|
9742
10490
|
try {
|
|
9743
|
-
const outputText = await readCodexOutput(request.outputPath,
|
|
10491
|
+
const outputText = await readCodexOutput(request.outputPath, status);
|
|
9744
10492
|
resolve({ status, signal, stdout, stderr, outputText });
|
|
9745
10493
|
} catch (error) {
|
|
9746
|
-
|
|
10494
|
+
resolve({
|
|
10495
|
+
status,
|
|
10496
|
+
signal,
|
|
10497
|
+
stdout,
|
|
10498
|
+
stderr: appendBounded2(stderr, `
|
|
10499
|
+
${safeErrorMessage2(error)}`),
|
|
10500
|
+
outputText: ""
|
|
10501
|
+
});
|
|
9747
10502
|
}
|
|
9748
10503
|
});
|
|
9749
10504
|
try {
|
|
@@ -9817,13 +10572,21 @@ function signalExitCode2(signal) {
|
|
|
9817
10572
|
return 1;
|
|
9818
10573
|
}
|
|
9819
10574
|
}
|
|
9820
|
-
async function readCodexOutput(outputPath,
|
|
10575
|
+
async function readCodexOutput(outputPath, status) {
|
|
9821
10576
|
try {
|
|
9822
|
-
return await
|
|
9823
|
-
} catch {
|
|
9824
|
-
|
|
10577
|
+
return await readFile7(outputPath, "utf8");
|
|
10578
|
+
} catch (error) {
|
|
10579
|
+
if (status === 0) {
|
|
10580
|
+
throw new Error(
|
|
10581
|
+
`Codex CLI exited successfully but did not write --output-last-message: ${safeErrorMessage2(error)}`
|
|
10582
|
+
);
|
|
10583
|
+
}
|
|
10584
|
+
return "";
|
|
9825
10585
|
}
|
|
9826
10586
|
}
|
|
10587
|
+
function safeErrorMessage2(error) {
|
|
10588
|
+
return error instanceof Error ? error.message : String(error);
|
|
10589
|
+
}
|
|
9827
10590
|
function appendBounded2(existing, next) {
|
|
9828
10591
|
const combined = existing + next;
|
|
9829
10592
|
if (combined.length <= CODEX_CLI_STDIO_LIMIT) {
|
|
@@ -9894,64 +10657,118 @@ function codexCliAbortError(signal) {
|
|
|
9894
10657
|
}
|
|
9895
10658
|
return new DOMException("The operation was aborted.", "AbortError");
|
|
9896
10659
|
}
|
|
10660
|
+
function codexCliPreStartAbortError(signal) {
|
|
10661
|
+
return new CodexCreditDispatchError(CODEX_CLI_PRE_START_ABORT_MESSAGE, {
|
|
10662
|
+
cause: codexCliAbortError(signal)
|
|
10663
|
+
});
|
|
10664
|
+
}
|
|
10665
|
+
function unwrapCodexCliPreStartAbort(error) {
|
|
10666
|
+
return error instanceof CodexCreditDispatchError && error.message === CODEX_CLI_PRE_START_ABORT_MESSAGE && error.cause instanceof Error ? error.cause : error;
|
|
10667
|
+
}
|
|
9897
10668
|
function summarizeProcessOutput2(stderr, stdout) {
|
|
9898
10669
|
const summary = [stderr.trim(), stdout.trim()].filter((value) => value.length > 0).join("\n").trim();
|
|
9899
10670
|
return summary.length > 0 ? summary.slice(-1e3) : "no process output";
|
|
9900
10671
|
}
|
|
9901
|
-
function
|
|
9902
|
-
const
|
|
9903
|
-
|
|
9904
|
-
|
|
10672
|
+
function requireCodexJsonlUsage(result) {
|
|
10673
|
+
const usage = parseCodexJsonlUsage(`${result.stdout}
|
|
10674
|
+
${result.stderr}`);
|
|
10675
|
+
if (!usage) {
|
|
10676
|
+
throw new Error(
|
|
10677
|
+
`Codex CLI completion did not emit a valid turn.completed usage event: ${summarizeProcessOutput2(result.stderr, result.stdout)}`
|
|
10678
|
+
);
|
|
9905
10679
|
}
|
|
9906
|
-
|
|
9907
|
-
|
|
9908
|
-
|
|
10680
|
+
return usage;
|
|
10681
|
+
}
|
|
10682
|
+
function readCodexUsage(result, outputText) {
|
|
10683
|
+
const exact = parseCodexJsonlUsage(`${result.stdout}
|
|
10684
|
+
${result.stderr}`);
|
|
10685
|
+
if (exact) return exact;
|
|
10686
|
+
const legacy = parseCodexTokenUsage(
|
|
10687
|
+
`${result.stderr}
|
|
10688
|
+
${result.stdout}`,
|
|
10689
|
+
outputText
|
|
9909
10690
|
);
|
|
9910
10691
|
return {
|
|
9911
|
-
|
|
9912
|
-
|
|
10692
|
+
inputTokens: legacy.input,
|
|
10693
|
+
cachedInputTokens: 0,
|
|
10694
|
+
outputTokens: legacy.output,
|
|
10695
|
+
reasoningOutputTokens: 0
|
|
9913
10696
|
};
|
|
9914
10697
|
}
|
|
9915
|
-
function
|
|
9916
|
-
const matches = [...
|
|
10698
|
+
function parseCodexTokenUsage(output, outputText) {
|
|
10699
|
+
const matches = [...output.matchAll(/\btokens used\s+([0-9][0-9,]*)\b/gi)];
|
|
9917
10700
|
const raw = matches.at(-1)?.[1];
|
|
9918
|
-
if (!raw) {
|
|
9919
|
-
|
|
10701
|
+
if (!raw) return { input: 0, output: 0 };
|
|
10702
|
+
const totalTokens = Number(raw.replace(/,/g, ""));
|
|
10703
|
+
if (!Number.isSafeInteger(totalTokens) || totalTokens < 0) {
|
|
10704
|
+
return { input: 0, output: 0 };
|
|
9920
10705
|
}
|
|
9921
|
-
const
|
|
9922
|
-
|
|
10706
|
+
const outputTokens = Math.min(
|
|
10707
|
+
totalTokens,
|
|
10708
|
+
Math.max(1, Math.ceil(outputText.length / 4))
|
|
10709
|
+
);
|
|
10710
|
+
return { input: totalTokens - outputTokens, output: outputTokens };
|
|
10711
|
+
}
|
|
10712
|
+
function codexCliResultError(result) {
|
|
10713
|
+
const exitLabel = result.signal ? `signal ${result.signal}` : `exit ${result.status ?? "unknown"}`;
|
|
10714
|
+
return new Error(
|
|
10715
|
+
`Codex CLI completion failed (${exitLabel}): ${summarizeProcessOutput2(result.stderr, result.stdout)}`
|
|
10716
|
+
);
|
|
9923
10717
|
}
|
|
9924
10718
|
function tomlString(value) {
|
|
9925
10719
|
return JSON.stringify(value);
|
|
9926
10720
|
}
|
|
10721
|
+
function buildCodexStructuredJudgePrompt(rubric) {
|
|
10722
|
+
return [
|
|
10723
|
+
rubric,
|
|
10724
|
+
"Return raw JSON only, with exactly these keys:",
|
|
10725
|
+
'{"score":<number from 0 to 1>,"decision":"pass|partial|fail","reason":"non-empty concise reason"}',
|
|
10726
|
+
"Do not wrap the JSON in Markdown or add any other text."
|
|
10727
|
+
].join("\n\n");
|
|
10728
|
+
}
|
|
10729
|
+
function buildCodexAssistantRubricPrompt(systemPrompt) {
|
|
10730
|
+
return [
|
|
10731
|
+
systemPrompt,
|
|
10732
|
+
"Return raw JSON only, with exactly these keys:",
|
|
10733
|
+
'{"identity_accuracy":<0-5>,"stance_coherence":<0-5>,"novelty":<0-5>,"calibration":<0-5>,"notes":"string"}',
|
|
10734
|
+
"Every numeric value must be finite and within the inclusive range 0 to 5.",
|
|
10735
|
+
"Do not wrap the JSON in Markdown or add any other text."
|
|
10736
|
+
].join("\n\n");
|
|
10737
|
+
}
|
|
10738
|
+
function isCodexStructuredJudgeAbort(error, signal) {
|
|
10739
|
+
return signal?.aborted === true || error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
10740
|
+
}
|
|
10741
|
+
function structuredJudgeErrorName(error) {
|
|
10742
|
+
return error instanceof Error && error.name.trim().length > 0 ? error.name : "unknown error";
|
|
10743
|
+
}
|
|
9927
10744
|
function createCodexCliProvider(config, deps) {
|
|
9928
10745
|
return new CodexCliProvider(config, deps);
|
|
9929
10746
|
}
|
|
9930
10747
|
|
|
9931
10748
|
// src/reporter.ts
|
|
9932
10749
|
import { execSync } from "child_process";
|
|
9933
|
-
import { mkdir as
|
|
9934
|
-
import
|
|
10750
|
+
import { mkdir as mkdir8, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
10751
|
+
import path11 from "path";
|
|
9935
10752
|
|
|
9936
10753
|
// src/filename-safety.ts
|
|
9937
|
-
import
|
|
10754
|
+
import path9 from "path";
|
|
9938
10755
|
function sanitizeFilenameSegment(value) {
|
|
9939
10756
|
const sanitized = value.trim().replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
9940
10757
|
return sanitized.length > 0 ? sanitized : "unknown";
|
|
9941
10758
|
}
|
|
9942
10759
|
function resolveContainedPath(root, ...segments) {
|
|
9943
|
-
const outputRoot =
|
|
9944
|
-
const filePath =
|
|
9945
|
-
const relativePath =
|
|
9946
|
-
if (relativePath === ".." || relativePath.startsWith(`..${
|
|
10760
|
+
const outputRoot = path9.resolve(root);
|
|
10761
|
+
const filePath = path9.resolve(outputRoot, ...segments);
|
|
10762
|
+
const relativePath = path9.relative(outputRoot, filePath);
|
|
10763
|
+
if (relativePath === ".." || relativePath.startsWith(`..${path9.sep}`) || path9.isAbsolute(relativePath)) {
|
|
9947
10764
|
throw new Error(`Refusing to write benchmark artifact outside ${outputRoot}`);
|
|
9948
10765
|
}
|
|
9949
10766
|
return filePath;
|
|
9950
10767
|
}
|
|
9951
10768
|
|
|
9952
10769
|
// src/leaderboard-export.ts
|
|
9953
|
-
import { mkdir as
|
|
9954
|
-
import
|
|
10770
|
+
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
10771
|
+
import path10 from "path";
|
|
9955
10772
|
async function writeLeaderboardArtifactsForResult(result, outputDir) {
|
|
9956
10773
|
if (result.meta.benchmark === "ama-bench") {
|
|
9957
10774
|
return writeAmaBenchLeaderboard(result, outputDir);
|
|
@@ -9966,12 +10783,12 @@ async function writeAmaBenchLeaderboard(result, outputDir) {
|
|
|
9966
10783
|
if (rows.length === 0) {
|
|
9967
10784
|
return [];
|
|
9968
10785
|
}
|
|
9969
|
-
const outputRoot =
|
|
10786
|
+
const outputRoot = path10.resolve(outputDir);
|
|
9970
10787
|
const leaderboardDir = resolveContainedPath(outputRoot, "leaderboard");
|
|
9971
|
-
await
|
|
10788
|
+
await mkdir7(leaderboardDir, { recursive: true });
|
|
9972
10789
|
const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
|
|
9973
10790
|
const filePath = resolveContainedPath(leaderboardDir, `ama-bench-${timestamp}-answers.jsonl`);
|
|
9974
|
-
await
|
|
10791
|
+
await writeFile7(filePath, serializeJsonl(rows), "utf8");
|
|
9975
10792
|
return [
|
|
9976
10793
|
{
|
|
9977
10794
|
benchmark: "ama-bench",
|
|
@@ -9984,16 +10801,16 @@ async function writeAmaBenchLeaderboard(result, outputDir) {
|
|
|
9984
10801
|
async function writeMemCorrectLeaderboard(result, outputDir) {
|
|
9985
10802
|
const row = buildMemCorrectLeaderboardRow(result);
|
|
9986
10803
|
if (!row) return [];
|
|
9987
|
-
const outputRoot =
|
|
10804
|
+
const outputRoot = path10.resolve(outputDir);
|
|
9988
10805
|
const leaderboardDir = resolveContainedPath(outputRoot, "leaderboard");
|
|
9989
|
-
await
|
|
10806
|
+
await mkdir7(leaderboardDir, { recursive: true });
|
|
9990
10807
|
const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
|
|
9991
10808
|
const safeAdapter = sanitizeFilenameSegment(row.adapter);
|
|
9992
10809
|
const filePath = resolveContainedPath(
|
|
9993
10810
|
leaderboardDir,
|
|
9994
10811
|
`memcorrect-${safeAdapter}-${timestamp}.jsonl`
|
|
9995
10812
|
);
|
|
9996
|
-
await
|
|
10813
|
+
await writeFile7(filePath, `${JSON.stringify(row)}
|
|
9997
10814
|
`, "utf8");
|
|
9998
10815
|
return [
|
|
9999
10816
|
{
|
|
@@ -10352,8 +11169,8 @@ function replaceLoneSurrogates(value) {
|
|
|
10352
11169
|
return out;
|
|
10353
11170
|
}
|
|
10354
11171
|
async function writeBenchmarkResult(result, outputDir) {
|
|
10355
|
-
const outputRoot =
|
|
10356
|
-
await
|
|
11172
|
+
const outputRoot = path11.resolve(outputDir);
|
|
11173
|
+
await mkdir8(outputRoot, { recursive: true });
|
|
10357
11174
|
const safeBenchmark = sanitizeFilenameSegment(result.meta.benchmark);
|
|
10358
11175
|
const safeRemnicVersion = sanitizeFilenameSegment(result.meta.remnicVersion);
|
|
10359
11176
|
const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
|
|
@@ -10381,14 +11198,14 @@ async function writeBenchmarkResult(result, outputDir) {
|
|
|
10381
11198
|
}
|
|
10382
11199
|
};
|
|
10383
11200
|
const publicResult = sanitizeBenchmarkResultForJson(redactBenchmarkResultSecrets(resultWithArtifacts));
|
|
10384
|
-
await
|
|
11201
|
+
await writeFile8(filePath, `${JSON.stringify(publicResult, null, 2)}
|
|
10385
11202
|
`);
|
|
10386
11203
|
return filePath;
|
|
10387
11204
|
}
|
|
10388
11205
|
async function getRemnicVersion() {
|
|
10389
11206
|
try {
|
|
10390
11207
|
const packageJson = JSON.parse(
|
|
10391
|
-
await
|
|
11208
|
+
await readFile8(path11.resolve(import.meta.dirname, "../../../package.json"), "utf8")
|
|
10392
11209
|
);
|
|
10393
11210
|
return typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
10394
11211
|
} catch {
|
|
@@ -11641,52 +12458,8 @@ function asStringArray(value) {
|
|
|
11641
12458
|
// src/responders.ts
|
|
11642
12459
|
import { FallbackLlmClient } from "@remnic/core";
|
|
11643
12460
|
|
|
11644
|
-
// src/judges/memcorrect-rubrics.ts
|
|
11645
|
-
var OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION = "openai-responses-bench-v1";
|
|
11646
|
-
var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION = "memcorrect-correction-acceptance-v1";
|
|
11647
|
-
var MEMCORRECT_STALE_HARM_RUBRIC_VERSION = "memcorrect-stale-memory-harm-v1";
|
|
11648
|
-
var GENERAL_ANSWER_JUDGE_RUBRIC = [
|
|
11649
|
-
"Grade the predicted benchmark answer against the reference answer.",
|
|
11650
|
-
"A score of 1 means fully correct, 0 means fully incorrect, and values between 0 and 1 mean partially correct.",
|
|
11651
|
-
"Do not reward unsupported claims. Ignore harmless wording and formatting differences."
|
|
11652
|
-
].join(" ");
|
|
11653
|
-
var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC = [
|
|
11654
|
-
"Decide whether the memory system accepted the user's correction.",
|
|
11655
|
-
"Pass only when the corrected fact is reflected and the retired fact is not asserted as current.",
|
|
11656
|
-
"A quotation or correction-history record that clearly marks the retired fact as obsolete is not stale recall.",
|
|
11657
|
-
"Use a score of 1 for accepted, 0 for not accepted, and a fractional score only when the evidence is genuinely ambiguous."
|
|
11658
|
-
].join(" ");
|
|
11659
|
-
var MEMCORRECT_STALE_HARM_RUBRIC = [
|
|
11660
|
-
"Decide whether the memory system avoided stale-memory harm after a correction.",
|
|
11661
|
-
"Pass only when the answer does not present the retired fact as current and does not act on it.",
|
|
11662
|
-
"Correction provenance may mention the retired fact only when it is explicitly identified as obsolete.",
|
|
11663
|
-
"Use a score of 1 when no stale harm is present, 0 when stale information affected the answer, and a fractional score only for genuinely ambiguous evidence."
|
|
11664
|
-
].join(" ");
|
|
11665
|
-
|
|
11666
12461
|
// src/providers/openai-responses.ts
|
|
11667
12462
|
var DEFAULT_OPENAI_RESPONSES_JUDGE_MODEL = "gpt-5.6";
|
|
11668
|
-
var VERDICT_JSON_SCHEMA = {
|
|
11669
|
-
type: "object",
|
|
11670
|
-
additionalProperties: false,
|
|
11671
|
-
required: ["score", "decision", "reason"],
|
|
11672
|
-
properties: {
|
|
11673
|
-
score: { type: "number", minimum: 0, maximum: 1 },
|
|
11674
|
-
decision: { type: "string", enum: ["pass", "partial", "fail"] },
|
|
11675
|
-
reason: { type: "string" }
|
|
11676
|
-
}
|
|
11677
|
-
};
|
|
11678
|
-
var ASSISTANT_RUBRIC_JSON_SCHEMA = {
|
|
11679
|
-
type: "object",
|
|
11680
|
-
additionalProperties: false,
|
|
11681
|
-
required: ["identity_accuracy", "stance_coherence", "novelty", "calibration", "notes"],
|
|
11682
|
-
properties: {
|
|
11683
|
-
identity_accuracy: { type: "number", minimum: 0, maximum: 5 },
|
|
11684
|
-
stance_coherence: { type: "number", minimum: 0, maximum: 5 },
|
|
11685
|
-
novelty: { type: "number", minimum: 0, maximum: 5 },
|
|
11686
|
-
calibration: { type: "number", minimum: 0, maximum: 5 },
|
|
11687
|
-
notes: { type: "string" }
|
|
11688
|
-
}
|
|
11689
|
-
};
|
|
11690
12463
|
var OpenAiResponsesJudgeError = class extends Error {
|
|
11691
12464
|
code;
|
|
11692
12465
|
retryable;
|
|
@@ -11825,7 +12598,7 @@ var OpenAiResponsesProvider = class {
|
|
|
11825
12598
|
this.recordTelemetry(failure.telemetry);
|
|
11826
12599
|
return failure;
|
|
11827
12600
|
}
|
|
11828
|
-
const verdict =
|
|
12601
|
+
const verdict = parseStructuredJudgeVerdict(parsed.text);
|
|
11829
12602
|
if (!verdict) {
|
|
11830
12603
|
const failure = this.failure(
|
|
11831
12604
|
"malformed_verdict",
|
|
@@ -11879,7 +12652,7 @@ var OpenAiResponsesProvider = class {
|
|
|
11879
12652
|
this.recordTelemetry(parsed.telemetry);
|
|
11880
12653
|
throw new OpenAiResponsesJudgeError(parsed);
|
|
11881
12654
|
}
|
|
11882
|
-
if (parsed.text === null || !
|
|
12655
|
+
if (parsed.text === null || !isValidAssistantRubric(parsed.text)) {
|
|
11883
12656
|
const failure = this.failure(
|
|
11884
12657
|
"malformed_verdict",
|
|
11885
12658
|
"OpenAI Responses API returned an invalid sealed assistant-rubric verdict.",
|
|
@@ -11901,6 +12674,9 @@ var OpenAiResponsesProvider = class {
|
|
|
11901
12674
|
getTelemetryEvents() {
|
|
11902
12675
|
return this.telemetryEvents.map((event) => ({ ...event }));
|
|
11903
12676
|
}
|
|
12677
|
+
createJudgeError(failure) {
|
|
12678
|
+
return new OpenAiResponsesJudgeError(failure);
|
|
12679
|
+
}
|
|
11904
12680
|
async parseResponse(response, startedAt, rubricVersion) {
|
|
11905
12681
|
let payload;
|
|
11906
12682
|
try {
|
|
@@ -12052,61 +12828,10 @@ function createOpenAiResponsesProvider(config = {}) {
|
|
|
12052
12828
|
return new OpenAiResponsesProvider(config);
|
|
12053
12829
|
}
|
|
12054
12830
|
function createOpenAiResponsesBenchJudge(config = {}, provider = createOpenAiResponsesProvider(config)) {
|
|
12055
|
-
|
|
12056
|
-
|
|
12057
|
-
|
|
12058
|
-
|
|
12059
|
-
input: [
|
|
12060
|
-
`QUESTION: ${question}`,
|
|
12061
|
-
`REFERENCE_ANSWER: ${expected}`,
|
|
12062
|
-
`PREDICTED_ANSWER: ${predicted}`
|
|
12063
|
-
].join("\n\n"),
|
|
12064
|
-
signal: control?.signal
|
|
12065
|
-
});
|
|
12066
|
-
if (!result.ok) throw new OpenAiResponsesJudgeError(result);
|
|
12067
|
-
return toBenchJudgeResult(result);
|
|
12068
|
-
};
|
|
12069
|
-
const scoreBinaryPrompt = async (prompt, control) => {
|
|
12070
|
-
const result = await provider.judge({
|
|
12071
|
-
rubric: `${GENERAL_ANSWER_JUDGE_RUBRIC} This evaluator is binary: score must be exactly 0 or 1.`,
|
|
12072
|
-
rubricVersion: config.rubricVersion ?? OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION,
|
|
12073
|
-
input: prompt,
|
|
12074
|
-
signal: control?.signal
|
|
12075
|
-
});
|
|
12076
|
-
if (!result.ok) throw new OpenAiResponsesJudgeError(result);
|
|
12077
|
-
if (result.verdict.score !== 0 && result.verdict.score !== 1) {
|
|
12078
|
-
const failure = {
|
|
12079
|
-
ok: false,
|
|
12080
|
-
error: {
|
|
12081
|
-
code: "malformed_verdict",
|
|
12082
|
-
message: "OpenAI Responses API returned a non-binary verdict for a binary rubric.",
|
|
12083
|
-
retryable: false
|
|
12084
|
-
},
|
|
12085
|
-
telemetry: { ...result.telemetry, errorCode: "malformed_verdict" }
|
|
12086
|
-
};
|
|
12087
|
-
throw new OpenAiResponsesJudgeError(failure);
|
|
12088
|
-
}
|
|
12089
|
-
return toBenchJudgeResult(result);
|
|
12090
|
-
};
|
|
12091
|
-
const judgeSpecialized = async (request, rubric, control) => {
|
|
12092
|
-
const result = rubric === "correction" ? await judgeMemCorrectCorrectionAcceptance(provider, serializeMemCorrectJudgeRequest(request), control?.signal) : await judgeMemCorrectStaleMemoryHarm(provider, serializeMemCorrectJudgeRequest(request), control?.signal);
|
|
12093
|
-
if (!result.ok) throw new OpenAiResponsesJudgeError(result);
|
|
12094
|
-
return {
|
|
12095
|
-
...toBenchJudgeResult(result),
|
|
12096
|
-
decision: result.verdict.decision,
|
|
12097
|
-
reason: result.verdict.reason,
|
|
12098
|
-
rubricVersion: result.telemetry.rubricVersion
|
|
12099
|
-
};
|
|
12100
|
-
};
|
|
12101
|
-
return {
|
|
12102
|
-
async score(question, predicted, expected, control) {
|
|
12103
|
-
return (await scoreWithMetrics(question, predicted, expected, control)).score;
|
|
12104
|
-
},
|
|
12105
|
-
scoreWithMetrics,
|
|
12106
|
-
scoreBinaryPrompt,
|
|
12107
|
-
judgeMemCorrectCorrectionAcceptance: (request, control) => judgeSpecialized(request, "correction", control),
|
|
12108
|
-
judgeMemCorrectStaleMemoryHarm: (request, control) => judgeSpecialized(request, "stale_harm", control)
|
|
12109
|
-
};
|
|
12831
|
+
return createStructuredBenchJudge(
|
|
12832
|
+
provider,
|
|
12833
|
+
config.rubricVersion ?? OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION
|
|
12834
|
+
);
|
|
12110
12835
|
}
|
|
12111
12836
|
async function judgeMemCorrectCorrectionAcceptance(provider, input, signal) {
|
|
12112
12837
|
return provider.judge({
|
|
@@ -12124,17 +12849,6 @@ async function judgeMemCorrectStaleMemoryHarm(provider, input, signal) {
|
|
|
12124
12849
|
signal
|
|
12125
12850
|
});
|
|
12126
12851
|
}
|
|
12127
|
-
function toBenchJudgeResult(result) {
|
|
12128
|
-
return {
|
|
12129
|
-
score: result.verdict.score,
|
|
12130
|
-
tokens: {
|
|
12131
|
-
input: result.telemetry.inputTokens,
|
|
12132
|
-
output: result.telemetry.outputTokens
|
|
12133
|
-
},
|
|
12134
|
-
latencyMs: result.telemetry.latencyMs,
|
|
12135
|
-
model: result.telemetry.model
|
|
12136
|
-
};
|
|
12137
|
-
}
|
|
12138
12852
|
function normalizeModel(model) {
|
|
12139
12853
|
if (model === void 0) return DEFAULT_OPENAI_RESPONSES_JUDGE_MODEL;
|
|
12140
12854
|
const trimmed = model.trim();
|
|
@@ -12143,54 +12857,6 @@ function normalizeModel(model) {
|
|
|
12143
12857
|
}
|
|
12144
12858
|
return trimmed;
|
|
12145
12859
|
}
|
|
12146
|
-
function parseVerdict(text) {
|
|
12147
|
-
let parsed;
|
|
12148
|
-
try {
|
|
12149
|
-
parsed = JSON.parse(text);
|
|
12150
|
-
} catch {
|
|
12151
|
-
return null;
|
|
12152
|
-
}
|
|
12153
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
12154
|
-
const candidate = parsed;
|
|
12155
|
-
const keys = Object.keys(candidate).sort();
|
|
12156
|
-
if (keys.join(",") !== "decision,reason,score") return null;
|
|
12157
|
-
if (typeof candidate.score !== "number" || !Number.isFinite(candidate.score) || candidate.score < 0 || candidate.score > 1 || candidate.decision !== "pass" && candidate.decision !== "partial" && candidate.decision !== "fail" || typeof candidate.reason !== "string" || candidate.reason.trim().length === 0) {
|
|
12158
|
-
return null;
|
|
12159
|
-
}
|
|
12160
|
-
return {
|
|
12161
|
-
score: candidate.score,
|
|
12162
|
-
decision: candidate.decision,
|
|
12163
|
-
reason: candidate.reason.trim()
|
|
12164
|
-
};
|
|
12165
|
-
}
|
|
12166
|
-
function parseAssistantRubric(text) {
|
|
12167
|
-
let parsed;
|
|
12168
|
-
try {
|
|
12169
|
-
parsed = JSON.parse(text);
|
|
12170
|
-
} catch {
|
|
12171
|
-
return false;
|
|
12172
|
-
}
|
|
12173
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
|
|
12174
|
-
const candidate = parsed;
|
|
12175
|
-
const keys = Object.keys(candidate).sort();
|
|
12176
|
-
if (keys.join(",") !== "calibration,identity_accuracy,notes,novelty,stance_coherence") return false;
|
|
12177
|
-
return ["identity_accuracy", "stance_coherence", "novelty", "calibration"].every(
|
|
12178
|
-
(key) => typeof candidate[key] === "number" && Number.isFinite(candidate[key]) && candidate[key] >= 0 && candidate[key] <= 5
|
|
12179
|
-
) && typeof candidate.notes === "string";
|
|
12180
|
-
}
|
|
12181
|
-
function serializeMemCorrectJudgeRequest(request) {
|
|
12182
|
-
return JSON.stringify({
|
|
12183
|
-
taskId: request.taskId,
|
|
12184
|
-
query: request.query,
|
|
12185
|
-
retiredContent: request.retiredContent,
|
|
12186
|
-
correctedContent: request.correctedContent,
|
|
12187
|
-
evidence: {
|
|
12188
|
-
postCorrectionRecall: request.postCorrectionRecall,
|
|
12189
|
-
postMaintenanceRecall: request.postMaintenanceRecall,
|
|
12190
|
-
postReingestRecall: request.postReingestRecall
|
|
12191
|
-
}
|
|
12192
|
-
});
|
|
12193
|
-
}
|
|
12194
12860
|
function readOutputText(payload) {
|
|
12195
12861
|
const text = (payload.output ?? []).flatMap((item) => item.type === "message" ? item.content ?? [] : []).filter((part) => part.type === "output_text").map((part) => part.text ?? "").join("").trim();
|
|
12196
12862
|
return text.length > 0 ? text : null;
|
|
@@ -12715,10 +13381,11 @@ function createJudgeFromProvider(provider) {
|
|
|
12715
13381
|
}
|
|
12716
13382
|
function createProviderBackedJudge(config, providerInstance) {
|
|
12717
13383
|
validateProviderConfig(config, "judge");
|
|
12718
|
-
|
|
12719
|
-
|
|
13384
|
+
const provider = providerInstance ?? createJudgeProvider(config);
|
|
13385
|
+
if (isStructuredJudgeProvider(provider)) {
|
|
13386
|
+
return createStructuredBenchJudge(provider, config.rubricVersion);
|
|
12720
13387
|
}
|
|
12721
|
-
return createJudgeFromProvider(
|
|
13388
|
+
return createJudgeFromProvider(provider);
|
|
12722
13389
|
}
|
|
12723
13390
|
function createAmaBenchRecommendedJudgeFromProvider(provider) {
|
|
12724
13391
|
async function scoreWithMetrics(question, predicted, expected, control) {
|
|
@@ -12771,15 +13438,16 @@ function createStructuredJudgeFromProvider(provider) {
|
|
|
12771
13438
|
}
|
|
12772
13439
|
function createProviderBackedStructuredJudge(config, providerInstance) {
|
|
12773
13440
|
validateProviderConfig(config, "judge");
|
|
12774
|
-
|
|
12775
|
-
|
|
13441
|
+
const provider = providerInstance ?? createJudgeProvider(config);
|
|
13442
|
+
if (isStructuredJudgeProvider(provider)) {
|
|
12776
13443
|
return {
|
|
12777
13444
|
evaluate: (request) => provider.evaluateAssistantRubric(request)
|
|
12778
13445
|
};
|
|
12779
13446
|
}
|
|
12780
|
-
return createStructuredJudgeFromProvider(
|
|
12781
|
-
|
|
12782
|
-
|
|
13447
|
+
return createStructuredJudgeFromProvider(provider);
|
|
13448
|
+
}
|
|
13449
|
+
function createJudgeProvider(config) {
|
|
13450
|
+
return config.provider === "openai" ? createOpenAiResponsesProvider({ ...config, provider: "openai" }) : createProvider(config);
|
|
12783
13451
|
}
|
|
12784
13452
|
function createGatewayResponder(options) {
|
|
12785
13453
|
if (!options.gatewayConfig) {
|
|
@@ -13052,8 +13720,8 @@ function clampNormalizedScore(value) {
|
|
|
13052
13720
|
}
|
|
13053
13721
|
|
|
13054
13722
|
// src/runtime-profiles.ts
|
|
13055
|
-
import
|
|
13056
|
-
import { readFile as
|
|
13723
|
+
import path12 from "path";
|
|
13724
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
13057
13725
|
import {
|
|
13058
13726
|
resolvePluginEntry,
|
|
13059
13727
|
setCodexCliFallbackRunnerForProcess
|
|
@@ -13401,7 +14069,7 @@ function buildPromptSpecificRequirements(prompt) {
|
|
|
13401
14069
|
}
|
|
13402
14070
|
|
|
13403
14071
|
// src/local-lab/manifest.ts
|
|
13404
|
-
import { readFile as
|
|
14072
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
13405
14073
|
var LOCAL_LAB_PROVIDER_KINDS = [
|
|
13406
14074
|
"openai-compatible",
|
|
13407
14075
|
"ollama"
|
|
@@ -13438,7 +14106,7 @@ function parseLocalLabManifest(raw) {
|
|
|
13438
14106
|
async function loadLocalLabManifest(filePath) {
|
|
13439
14107
|
let text;
|
|
13440
14108
|
try {
|
|
13441
|
-
text = await
|
|
14109
|
+
text = await readFile9(filePath, "utf8");
|
|
13442
14110
|
} catch (error) {
|
|
13443
14111
|
const code = error?.code ?? "EUNKNOWN";
|
|
13444
14112
|
throw new Error(`local-lab manifest at ${filePath} could not be read (${code})`);
|
|
@@ -14099,14 +14767,14 @@ async function loadOpenclawRuntimeConfig(filePath) {
|
|
|
14099
14767
|
};
|
|
14100
14768
|
}
|
|
14101
14769
|
function deriveOpenclawRuntimeContext(configPath) {
|
|
14102
|
-
const rootDir =
|
|
14770
|
+
const rootDir = path12.dirname(path12.resolve(configPath));
|
|
14103
14771
|
return {
|
|
14104
|
-
agentDir:
|
|
14105
|
-
workspaceDir:
|
|
14772
|
+
agentDir: path12.join(rootDir, "agents", "main", "agent"),
|
|
14773
|
+
workspaceDir: path12.join(rootDir, "workspace")
|
|
14106
14774
|
};
|
|
14107
14775
|
}
|
|
14108
14776
|
async function loadJsonObject(filePath, label) {
|
|
14109
|
-
const raw = await
|
|
14777
|
+
const raw = await readFile10(filePath, "utf8");
|
|
14110
14778
|
let parsed;
|
|
14111
14779
|
try {
|
|
14112
14780
|
parsed = JSON.parse(raw);
|
|
@@ -14518,20 +15186,20 @@ async function resolveLocalLabRuntimeProfile(options) {
|
|
|
14518
15186
|
|
|
14519
15187
|
// src/benchmark.ts
|
|
14520
15188
|
import fs2 from "fs";
|
|
14521
|
-
import
|
|
14522
|
-
import { createHash as
|
|
15189
|
+
import path35 from "path";
|
|
15190
|
+
import { createHash as createHash12 } from "crypto";
|
|
14523
15191
|
import { expandTildePath as expandTildePath3 } from "@remnic/core";
|
|
14524
15192
|
|
|
14525
15193
|
// src/judges/judge-cache.ts
|
|
14526
|
-
import { createHash as
|
|
15194
|
+
import { createHash as createHash7, randomBytes as randomBytes2 } from "crypto";
|
|
14527
15195
|
import {
|
|
14528
|
-
mkdir as
|
|
14529
|
-
readFile as
|
|
14530
|
-
rename as
|
|
15196
|
+
mkdir as mkdir9,
|
|
15197
|
+
readFile as readFile11,
|
|
15198
|
+
rename as rename3,
|
|
14531
15199
|
rm as rm4,
|
|
14532
|
-
writeFile as
|
|
15200
|
+
writeFile as writeFile9
|
|
14533
15201
|
} from "fs/promises";
|
|
14534
|
-
import
|
|
15202
|
+
import path13 from "path";
|
|
14535
15203
|
var JUDGE_CACHE_PROTOCOL_VERSION = "judge-protocol-v1";
|
|
14536
15204
|
function stableStringify2(value) {
|
|
14537
15205
|
if (Array.isArray(value)) {
|
|
@@ -14562,12 +15230,12 @@ var JudgeCache = class {
|
|
|
14562
15230
|
inflight = /* @__PURE__ */ new Map();
|
|
14563
15231
|
cachedDirExists = false;
|
|
14564
15232
|
constructor(options) {
|
|
14565
|
-
this.dir =
|
|
15233
|
+
this.dir = path13.resolve(options.dir);
|
|
14566
15234
|
}
|
|
14567
15235
|
/** Compute the sha256-hex key for a set of parts. Pure, sync, side-effect-free. */
|
|
14568
15236
|
computeKey(parts) {
|
|
14569
|
-
const fieldDigest = (value) =>
|
|
14570
|
-
return
|
|
15237
|
+
const fieldDigest = (value) => createHash7("sha256").update(value).digest();
|
|
15238
|
+
return createHash7("sha256").update(fieldDigest(parts.benchmarkId)).update(fieldDigest(parts.datasetVersion)).update(fieldDigest(parts.questionId)).update(fieldDigest(parts.answerText)).update(fieldDigest(parts.judgePromptHash)).update(fieldDigest(parts.judgeModelId)).update(fieldDigest(parts.judgeParamsHash)).digest("hex");
|
|
14571
15239
|
}
|
|
14572
15240
|
/**
|
|
14573
15241
|
* Read a previously-stored verdict. Returns `undefined` on miss, corrupted
|
|
@@ -14587,7 +15255,7 @@ var JudgeCache = class {
|
|
|
14587
15255
|
const filePath = this.entryPath(key);
|
|
14588
15256
|
let raw;
|
|
14589
15257
|
try {
|
|
14590
|
-
raw = await
|
|
15258
|
+
raw = await readFile11(filePath, "utf8");
|
|
14591
15259
|
} catch {
|
|
14592
15260
|
return void 0;
|
|
14593
15261
|
}
|
|
@@ -14633,25 +15301,25 @@ var JudgeCache = class {
|
|
|
14633
15301
|
}
|
|
14634
15302
|
async writeOne(key, envelope) {
|
|
14635
15303
|
if (!this.cachedDirExists) {
|
|
14636
|
-
await
|
|
15304
|
+
await mkdir9(this.dir, { recursive: true });
|
|
14637
15305
|
this.cachedDirExists = true;
|
|
14638
15306
|
}
|
|
14639
15307
|
const filePath = this.entryPath(key);
|
|
14640
|
-
const tempPath =
|
|
15308
|
+
const tempPath = path13.join(
|
|
14641
15309
|
this.dir,
|
|
14642
15310
|
`.${key}.${randomBytes2(6).toString("hex")}.tmp`
|
|
14643
15311
|
);
|
|
14644
|
-
await
|
|
15312
|
+
await writeFile9(tempPath, `${JSON.stringify(envelope)}
|
|
14645
15313
|
`, "utf8");
|
|
14646
15314
|
try {
|
|
14647
|
-
await
|
|
15315
|
+
await rename3(tempPath, filePath);
|
|
14648
15316
|
} catch (error) {
|
|
14649
15317
|
await rm4(tempPath, { force: true }).catch(() => void 0);
|
|
14650
15318
|
throw error;
|
|
14651
15319
|
}
|
|
14652
15320
|
}
|
|
14653
15321
|
entryPath(key) {
|
|
14654
|
-
return
|
|
15322
|
+
return path13.join(this.dir, `${key}.json`);
|
|
14655
15323
|
}
|
|
14656
15324
|
};
|
|
14657
15325
|
function runJudgeWithCache(options) {
|
|
@@ -14762,7 +15430,7 @@ function runJudgeWithCache(options) {
|
|
|
14762
15430
|
// Binary prompts are content-sensitive: two distinct prompts of
|
|
14763
15431
|
// the same character length would collide on the previous
|
|
14764
15432
|
// `binary:N` key, so key on a sha256 prefix of the prompt body.
|
|
14765
|
-
questionId: `binary:${
|
|
15433
|
+
questionId: `binary:${createHash7("sha256").update(prompt).digest("hex").slice(0, 16)}`,
|
|
14766
15434
|
answerText: prompt,
|
|
14767
15435
|
judgePromptHash: keyExtras.judgePromptHash ?? "unknown-prompt",
|
|
14768
15436
|
judgeModelId: keyExtras.judgeModelId ?? "unknown-judge",
|
|
@@ -14841,8 +15509,8 @@ function isBenchJudgeResult(value) {
|
|
|
14841
15509
|
|
|
14842
15510
|
// src/benchmarks/published/ama-bench/runner.ts
|
|
14843
15511
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
14844
|
-
import { readFile as
|
|
14845
|
-
import
|
|
15512
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
15513
|
+
import path14 from "path";
|
|
14846
15514
|
|
|
14847
15515
|
// src/benchmarks/published/ama-bench/fixture.ts
|
|
14848
15516
|
var AMA_BENCH_SMOKE_FIXTURE = [
|
|
@@ -15417,10 +16085,10 @@ async function loadDataset(mode, datasetDir, limit) {
|
|
|
15417
16085
|
return episodes;
|
|
15418
16086
|
};
|
|
15419
16087
|
if (datasetDir) {
|
|
15420
|
-
const filePath =
|
|
16088
|
+
const filePath = path14.join(datasetDir, "open_end_qa_set.jsonl");
|
|
15421
16089
|
let raw;
|
|
15422
16090
|
try {
|
|
15423
|
-
raw = await
|
|
16091
|
+
raw = await readFile12(filePath, "utf8");
|
|
15424
16092
|
} catch (error) {
|
|
15425
16093
|
throw new Error(
|
|
15426
16094
|
`AMA-Bench dataset not found at ${filePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -15712,8 +16380,8 @@ function isValidQaPairs(value) {
|
|
|
15712
16380
|
|
|
15713
16381
|
// src/benchmarks/published/amemgym/runner.ts
|
|
15714
16382
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
15715
|
-
import { readFile as
|
|
15716
|
-
import
|
|
16383
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
16384
|
+
import path15 from "path";
|
|
15717
16385
|
|
|
15718
16386
|
// src/benchmarks/published/amemgym/fixture.ts
|
|
15719
16387
|
var AMEMGYM_SMOKE_FIXTURE = [
|
|
@@ -16242,7 +16910,7 @@ async function loadDataset2(mode, datasetDir, limit) {
|
|
|
16242
16910
|
const datasetErrors = [];
|
|
16243
16911
|
for (const filename of DATASET_FILENAMES) {
|
|
16244
16912
|
try {
|
|
16245
|
-
const raw = await
|
|
16913
|
+
const raw = await readFile13(path15.join(datasetDir, filename), "utf8");
|
|
16246
16914
|
const parsed = parseDataset(raw, filename, normalizedLimit);
|
|
16247
16915
|
return ensureDatasetProfiles(parsed);
|
|
16248
16916
|
} catch (error) {
|
|
@@ -16416,8 +17084,8 @@ function normalizeRole(role) {
|
|
|
16416
17084
|
|
|
16417
17085
|
// src/benchmarks/published/memory-arena/runner.ts
|
|
16418
17086
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
16419
|
-
import { readFile as
|
|
16420
|
-
import
|
|
17087
|
+
import { readFile as readFile14, readdir as readdir5, stat as stat3 } from "fs/promises";
|
|
17088
|
+
import path16 from "path";
|
|
16421
17089
|
import { expandTildePath as expandTildePath2 } from "@remnic/core";
|
|
16422
17090
|
|
|
16423
17091
|
// src/benchmarks/published/memory-arena/fixture.ts
|
|
@@ -16744,7 +17412,7 @@ async function loadDataset3(mode, datasetDir, limit) {
|
|
|
16744
17412
|
if (remainingLimit2 === 0) {
|
|
16745
17413
|
break;
|
|
16746
17414
|
}
|
|
16747
|
-
const raw = await
|
|
17415
|
+
const raw = await readFile14(path16.join(datasetDir, filename), "utf8");
|
|
16748
17416
|
const parsedTasks = [];
|
|
16749
17417
|
raw.split("\n").forEach((line, lineIndex) => {
|
|
16750
17418
|
if (line.trim().length === 0) {
|
|
@@ -17080,7 +17748,7 @@ async function loadMemoryArenaWebshopProductCatalog(datasetDir) {
|
|
|
17080
17748
|
`MemoryArena WebShop product sidecar is ${sourceStat.size} bytes; provide a compact JSON/JSONL sidecar smaller than ${MEMORY_ARENA_WEBSHOP_PRODUCTS_MAX_BYTES} bytes instead of the full WebShop catalog.`
|
|
17081
17749
|
);
|
|
17082
17750
|
}
|
|
17083
|
-
const raw = await
|
|
17751
|
+
const raw = await readFile14(sourcePath, "utf8");
|
|
17084
17752
|
const records = parseMemoryArenaWebshopSidecarRecords(raw, sourcePath);
|
|
17085
17753
|
const byAsin = /* @__PURE__ */ new Map();
|
|
17086
17754
|
for (const record of records) {
|
|
@@ -17100,14 +17768,14 @@ async function loadMemoryArenaWebshopProductCatalog(datasetDir) {
|
|
|
17100
17768
|
async function resolveMemoryArenaWebshopProductCatalogPath(datasetDir) {
|
|
17101
17769
|
const configuredPath = process.env[MEMORY_ARENA_WEBSHOP_PRODUCTS_ENV]?.trim();
|
|
17102
17770
|
if (configuredPath && configuredPath.length > 0) {
|
|
17103
|
-
return
|
|
17771
|
+
return path16.resolve(expandTildePath2(configuredPath));
|
|
17104
17772
|
}
|
|
17105
17773
|
if (datasetDir === void 0) {
|
|
17106
17774
|
return void 0;
|
|
17107
17775
|
}
|
|
17108
17776
|
const candidatePaths = [
|
|
17109
17777
|
...MEMORY_ARENA_WEBSHOP_PRODUCT_SIDECAR_FILENAMES
|
|
17110
|
-
].map((filename) =>
|
|
17778
|
+
].map((filename) => path16.join(datasetDir, filename));
|
|
17111
17779
|
for (const candidatePath of candidatePaths) {
|
|
17112
17780
|
try {
|
|
17113
17781
|
const candidateStat = await stat3(candidatePath);
|
|
@@ -18529,8 +19197,8 @@ function scoreSubtaskSuccess(scores) {
|
|
|
18529
19197
|
import { collectTemporalLexicalCues } from "@remnic/core";
|
|
18530
19198
|
|
|
18531
19199
|
// src/benchmarks/published/dataset-loader.ts
|
|
18532
|
-
import { readFile as
|
|
18533
|
-
import
|
|
19200
|
+
import { readFile as readFile15 } from "fs/promises";
|
|
19201
|
+
import path17 from "path";
|
|
18534
19202
|
|
|
18535
19203
|
// src/benchmarks/published/longmemeval/fixture.ts
|
|
18536
19204
|
var LONG_MEM_EVAL_SMOKE_FIXTURE = [
|
|
@@ -18633,10 +19301,10 @@ async function loadDataset4(options) {
|
|
|
18633
19301
|
const errors = [];
|
|
18634
19302
|
if (options.datasetDir) {
|
|
18635
19303
|
for (const filename of options.filenames) {
|
|
18636
|
-
const abs =
|
|
19304
|
+
const abs = path17.join(options.datasetDir, filename);
|
|
18637
19305
|
let raw;
|
|
18638
19306
|
try {
|
|
18639
|
-
raw = await
|
|
19307
|
+
raw = await readFile15(abs, "utf8");
|
|
18640
19308
|
} catch (error) {
|
|
18641
19309
|
errors.push(
|
|
18642
19310
|
`${filename}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -20743,7 +21411,7 @@ function normalizeQaArray(value, location) {
|
|
|
20743
21411
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
20744
21412
|
import { createReadStream as createReadStream2 } from "fs";
|
|
20745
21413
|
import { readdir as readdir6 } from "fs/promises";
|
|
20746
|
-
import
|
|
21414
|
+
import path18 from "path";
|
|
20747
21415
|
import { createInterface } from "readline/promises";
|
|
20748
21416
|
import {
|
|
20749
21417
|
asyncBufferFromFile,
|
|
@@ -21214,8 +21882,8 @@ async function listBeamDatasetFiles(datasetDir) {
|
|
|
21214
21882
|
return directFiles;
|
|
21215
21883
|
}
|
|
21216
21884
|
try {
|
|
21217
|
-
const nestedFilenames = await readdir6(
|
|
21218
|
-
return nestedFilenames.filter((filename) => isBeamDatasetFilename(filename)).map((filename) =>
|
|
21885
|
+
const nestedFilenames = await readdir6(path18.join(datasetDir, "data"));
|
|
21886
|
+
return nestedFilenames.filter((filename) => isBeamDatasetFilename(filename)).map((filename) => path18.join("data", filename));
|
|
21219
21887
|
} catch {
|
|
21220
21888
|
return [];
|
|
21221
21889
|
}
|
|
@@ -21242,7 +21910,7 @@ async function* iterateDatasetFiles(datasetDir, datasetFiles, limit) {
|
|
|
21242
21910
|
let remainingLimit = limit;
|
|
21243
21911
|
for (const filename of datasetFiles) {
|
|
21244
21912
|
const scale = inferScaleFromFilename(filename);
|
|
21245
|
-
const filePath =
|
|
21913
|
+
const filePath = path18.join(datasetDir, filename);
|
|
21246
21914
|
const conversations = filename.endsWith(".jsonl") ? streamJsonlDataset(filePath, filename, remainingLimit) : filename.endsWith(".parquet") ? streamParquetDataset(filePath, filename, remainingLimit) : streamJsonDataset(filePath, filename, remainingLimit);
|
|
21247
21915
|
for await (const conversation of conversations) {
|
|
21248
21916
|
yield {
|
|
@@ -22253,9 +22921,9 @@ var StructuredLiteralParser = class {
|
|
|
22253
22921
|
};
|
|
22254
22922
|
|
|
22255
22923
|
// src/benchmarks/published/personamem/runner.ts
|
|
22256
|
-
import { createHash as
|
|
22257
|
-
import { readFile as
|
|
22258
|
-
import
|
|
22924
|
+
import { createHash as createHash8, randomUUID as randomUUID7 } from "crypto";
|
|
22925
|
+
import { readFile as readFile16, realpath as realpath4 } from "fs/promises";
|
|
22926
|
+
import path19 from "path";
|
|
22259
22927
|
|
|
22260
22928
|
// src/benchmarks/published/personamem/fixture.ts
|
|
22261
22929
|
var PERSONAMEM_SMOKE_FIXTURE = [
|
|
@@ -22531,10 +23199,10 @@ async function loadDataset8(mode, datasetDir, limit) {
|
|
|
22531
23199
|
if (datasetDir) {
|
|
22532
23200
|
const datasetErrors = [];
|
|
22533
23201
|
for (const relativePath of DATASET_FILE_CANDIDATES) {
|
|
22534
|
-
const datasetPath =
|
|
23202
|
+
const datasetPath = path19.join(datasetDir, relativePath);
|
|
22535
23203
|
let raw;
|
|
22536
23204
|
try {
|
|
22537
|
-
raw = await
|
|
23205
|
+
raw = await readFile16(datasetPath, "utf8");
|
|
22538
23206
|
} catch (error) {
|
|
22539
23207
|
datasetErrors.push(
|
|
22540
23208
|
`${relativePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -22592,7 +23260,7 @@ async function hydrateSample(row, datasetRoot) {
|
|
|
22592
23260
|
datasetRoot,
|
|
22593
23261
|
row.chat_history_32k_link
|
|
22594
23262
|
);
|
|
22595
|
-
const chatHistoryRaw = await
|
|
23263
|
+
const chatHistoryRaw = await readFile16(chatHistoryPath, "utf8");
|
|
22596
23264
|
const chatHistory = parseChatHistory(
|
|
22597
23265
|
chatHistoryRaw,
|
|
22598
23266
|
row.chat_history_32k_link
|
|
@@ -22725,12 +23393,12 @@ function parseCsv(raw, limit) {
|
|
|
22725
23393
|
return rows;
|
|
22726
23394
|
}
|
|
22727
23395
|
async function resolveDatasetFilePath(datasetRoot, relativePath) {
|
|
22728
|
-
const rootPath =
|
|
23396
|
+
const rootPath = path19.resolve(datasetRoot);
|
|
22729
23397
|
const rootRealPath = await realpath4(rootPath);
|
|
22730
|
-
const candidatePath =
|
|
23398
|
+
const candidatePath = path19.resolve(rootPath, relativePath);
|
|
22731
23399
|
const candidateRealPath = await realpath4(candidatePath);
|
|
22732
|
-
const relativeToRoot =
|
|
22733
|
-
if (relativeToRoot.startsWith("..") ||
|
|
23400
|
+
const relativeToRoot = path19.relative(rootRealPath, candidateRealPath);
|
|
23401
|
+
if (relativeToRoot.startsWith("..") || path19.isAbsolute(relativeToRoot)) {
|
|
22734
23402
|
throw new Error(
|
|
22735
23403
|
`PersonaMem-v2 dataset file reference "${relativePath}" must stay within datasetDir.`
|
|
22736
23404
|
);
|
|
@@ -22858,7 +23526,7 @@ function buildMcqPrompt(sample, seed) {
|
|
|
22858
23526
|
function deterministicShuffle(values, seedMaterial) {
|
|
22859
23527
|
return values.map((value, index) => ({
|
|
22860
23528
|
value,
|
|
22861
|
-
key:
|
|
23529
|
+
key: createHash8("sha256").update(`${seedMaterial}:${index}:${value}`).digest("hex"),
|
|
22862
23530
|
index
|
|
22863
23531
|
})).sort((left, right) => {
|
|
22864
23532
|
const byKey = left.key.localeCompare(right.key);
|
|
@@ -23058,8 +23726,8 @@ function applyLimit6(items, limit) {
|
|
|
23058
23726
|
|
|
23059
23727
|
// src/benchmarks/published/membench/runner.ts
|
|
23060
23728
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
23061
|
-
import { readFile as
|
|
23062
|
-
import
|
|
23729
|
+
import { readFile as readFile17, readdir as readdir7 } from "fs/promises";
|
|
23730
|
+
import path20 from "path";
|
|
23063
23731
|
|
|
23064
23732
|
// src/benchmarks/published/membench/fixture.ts
|
|
23065
23733
|
var MEMBENCH_SMOKE_FIXTURE = [
|
|
@@ -23320,7 +23988,7 @@ async function loadDataset9(mode, datasetDir, limit) {
|
|
|
23320
23988
|
let remainingLimit = normalizedLimit;
|
|
23321
23989
|
for (const filename of filenames) {
|
|
23322
23990
|
try {
|
|
23323
|
-
const raw = await
|
|
23991
|
+
const raw = await readFile17(path20.join(datasetDir, filename), "utf8");
|
|
23324
23992
|
const parsed = filename.endsWith(".jsonl") ? parseJsonlDataset(raw, filename) : parseJsonDataset(raw, filename);
|
|
23325
23993
|
const limitedCases = remainingLimit === 0 ? [] : applyLimit7(parsed, remainingLimit);
|
|
23326
23994
|
if (limitedCases.length > 0) {
|
|
@@ -24187,8 +24855,8 @@ function isPlainObject4(value) {
|
|
|
24187
24855
|
|
|
24188
24856
|
// src/benchmarks/published/memoryagentbench/runner.ts
|
|
24189
24857
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
24190
|
-
import { access, readFile as
|
|
24191
|
-
import
|
|
24858
|
+
import { access, readFile as readFile18 } from "fs/promises";
|
|
24859
|
+
import path21 from "path";
|
|
24192
24860
|
|
|
24193
24861
|
// src/benchmarks/published/memoryagentbench/fixture.ts
|
|
24194
24862
|
var MEMORY_AGENT_BENCH_SMOKE_FIXTURE = [
|
|
@@ -25210,7 +25878,7 @@ async function loadRecSysEntityMapping(datasetDir) {
|
|
|
25210
25878
|
}
|
|
25211
25879
|
let parsed;
|
|
25212
25880
|
try {
|
|
25213
|
-
parsed = JSON.parse(await
|
|
25881
|
+
parsed = JSON.parse(await readFile18(candidate, "utf8"));
|
|
25214
25882
|
} catch (error) {
|
|
25215
25883
|
console.error(
|
|
25216
25884
|
` [WARN] MemoryAgentBench ReDial entity mapping ${candidate} is invalid JSON; trying the next candidate: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -25267,21 +25935,21 @@ function recsysEntityMappingCandidates(datasetDir) {
|
|
|
25267
25935
|
if (!datasetDir) {
|
|
25268
25936
|
return [];
|
|
25269
25937
|
}
|
|
25270
|
-
const absoluteDatasetDir =
|
|
25938
|
+
const absoluteDatasetDir = path21.resolve(datasetDir);
|
|
25271
25939
|
const roots = [
|
|
25272
25940
|
absoluteDatasetDir,
|
|
25273
|
-
|
|
25941
|
+
path21.dirname(absoluteDatasetDir)
|
|
25274
25942
|
];
|
|
25275
25943
|
const canonicalSuffixes = [
|
|
25276
|
-
|
|
25277
|
-
|
|
25944
|
+
path21.join("processed_data", "Recsys_Redial", "entity2id.json"),
|
|
25945
|
+
path21.join("Recsys_Redial", "entity2id.json")
|
|
25278
25946
|
];
|
|
25279
25947
|
const looseSuffixes = ["entity2id.json"];
|
|
25280
25948
|
return [
|
|
25281
25949
|
...roots.flatMap(
|
|
25282
|
-
(root) => canonicalSuffixes.map((suffix) =>
|
|
25950
|
+
(root) => canonicalSuffixes.map((suffix) => path21.join(root, suffix))
|
|
25283
25951
|
),
|
|
25284
|
-
...looseSuffixes.map((suffix) =>
|
|
25952
|
+
...looseSuffixes.map((suffix) => path21.join(absoluteDatasetDir, suffix))
|
|
25285
25953
|
];
|
|
25286
25954
|
}
|
|
25287
25955
|
async function fileExists(filePath) {
|
|
@@ -25318,7 +25986,7 @@ async function loadDataset10(mode, datasetDir, limit) {
|
|
|
25318
25986
|
const datasetErrors = [];
|
|
25319
25987
|
for (const filename of DATASET_BUNDLE_CANDIDATES) {
|
|
25320
25988
|
const parsed = await tryReadDatasetFile(
|
|
25321
|
-
|
|
25989
|
+
path21.join(datasetDir, filename),
|
|
25322
25990
|
filename,
|
|
25323
25991
|
datasetErrors
|
|
25324
25992
|
);
|
|
@@ -25335,7 +26003,7 @@ async function loadDataset10(mode, datasetDir, limit) {
|
|
|
25335
26003
|
let splitData;
|
|
25336
26004
|
for (const filename of splitConfig.candidates) {
|
|
25337
26005
|
try {
|
|
25338
|
-
splitData = await readDatasetFile(
|
|
26006
|
+
splitData = await readDatasetFile(path21.join(datasetDir, filename), filename);
|
|
25339
26007
|
break;
|
|
25340
26008
|
} catch (error) {
|
|
25341
26009
|
if (!isFileNotFoundError2(error)) {
|
|
@@ -25373,7 +26041,7 @@ async function loadDataset10(mode, datasetDir, limit) {
|
|
|
25373
26041
|
return ensureDatasetItems(applyLimit8(MEMORY_AGENT_BENCH_SMOKE_FIXTURE, normalizedLimit));
|
|
25374
26042
|
}
|
|
25375
26043
|
async function readDatasetFile(filePath, filename) {
|
|
25376
|
-
const raw = await
|
|
26044
|
+
const raw = await readFile18(filePath, "utf8");
|
|
25377
26045
|
const parsed = filename.endsWith(".jsonl") ? parseJsonLines(raw, filename) : parseJsonArray(raw, filename);
|
|
25378
26046
|
return parsed.map(
|
|
25379
26047
|
(item, index) => parseMemoryAgentBenchItem(item, `${filename} item ${index + 1}`)
|
|
@@ -25983,8 +26651,8 @@ function loadCases(mode, limit) {
|
|
|
25983
26651
|
|
|
25984
26652
|
// src/benchmarks/remnic/extraction-judge-calibration/runner.ts
|
|
25985
26653
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
25986
|
-
import
|
|
25987
|
-
import
|
|
26654
|
+
import os6 from "os";
|
|
26655
|
+
import path22 from "path";
|
|
25988
26656
|
import {
|
|
25989
26657
|
createVerdictCache,
|
|
25990
26658
|
judgeFactDurability,
|
|
@@ -26094,8 +26762,8 @@ var extractionJudgeCalibrationDefinition = {
|
|
|
26094
26762
|
async function runExtractionJudgeCalibrationBenchmark(options) {
|
|
26095
26763
|
const cases = loadCases2(options.mode, options.limit);
|
|
26096
26764
|
const config = parseConfig2({
|
|
26097
|
-
memoryDir:
|
|
26098
|
-
workspaceDir:
|
|
26765
|
+
memoryDir: path22.join(os6.tmpdir(), "remnic-bench-extraction-judge"),
|
|
26766
|
+
workspaceDir: path22.join(os6.tmpdir(), "remnic-bench-extraction-judge-workspace"),
|
|
26099
26767
|
openaiApiKey: "bench-test-key",
|
|
26100
26768
|
extractionJudgeEnabled: true,
|
|
26101
26769
|
extractionJudgeBatchSize: 4,
|
|
@@ -26643,8 +27311,8 @@ function constantAggregate2(value) {
|
|
|
26643
27311
|
}
|
|
26644
27312
|
|
|
26645
27313
|
// src/benchmarks/remnic/entity-consolidation/runner.ts
|
|
26646
|
-
import
|
|
26647
|
-
import
|
|
27314
|
+
import os7 from "os";
|
|
27315
|
+
import path23 from "path";
|
|
26648
27316
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
26649
27317
|
import { mkdtemp as mkdtemp4, rm as rm5 } from "fs/promises";
|
|
26650
27318
|
import { StorageManager } from "@remnic/core";
|
|
@@ -26807,7 +27475,7 @@ function loadCases4(mode, limit) {
|
|
|
26807
27475
|
return limited;
|
|
26808
27476
|
}
|
|
26809
27477
|
async function executeCase(sample) {
|
|
26810
|
-
const tmpDir = await mkdtemp4(
|
|
27478
|
+
const tmpDir = await mkdtemp4(path23.join(os7.tmpdir(), "remnic-bench-entity-consolidation-"));
|
|
26811
27479
|
try {
|
|
26812
27480
|
const storage = new StorageManager(tmpDir);
|
|
26813
27481
|
await storage.ensureDirectories();
|
|
@@ -26986,9 +27654,9 @@ function parseNonNegativeInt(rawValue) {
|
|
|
26986
27654
|
|
|
26987
27655
|
// src/benchmarks/remnic/page-versioning/runner.ts
|
|
26988
27656
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
26989
|
-
import { mkdir as
|
|
26990
|
-
import
|
|
26991
|
-
import
|
|
27657
|
+
import { mkdir as mkdir10, mkdtemp as mkdtemp5, readFile as readFile19, rm as rm6, writeFile as writeFile10 } from "fs/promises";
|
|
27658
|
+
import os8 from "os";
|
|
27659
|
+
import path24 from "path";
|
|
26992
27660
|
import {
|
|
26993
27661
|
createVersion,
|
|
26994
27662
|
diffVersions,
|
|
@@ -27152,21 +27820,21 @@ function loadCases5(mode, limit) {
|
|
|
27152
27820
|
return limited;
|
|
27153
27821
|
}
|
|
27154
27822
|
async function executeCase2(sample, dependencies) {
|
|
27155
|
-
const tmpDir = await mkdtemp5(
|
|
27823
|
+
const tmpDir = await mkdtemp5(path24.join(os8.tmpdir(), "remnic-bench-page-versioning-"));
|
|
27156
27824
|
try {
|
|
27157
|
-
const factsDir =
|
|
27158
|
-
const pagePath =
|
|
27159
|
-
await
|
|
27825
|
+
const factsDir = path24.join(tmpDir, "facts");
|
|
27826
|
+
const pagePath = path24.join(factsDir, `${sample.id}.md`);
|
|
27827
|
+
await mkdir10(factsDir, { recursive: true });
|
|
27160
27828
|
const config = versioningConfig();
|
|
27161
27829
|
switch (sample.scenario) {
|
|
27162
27830
|
case "revert-flow": {
|
|
27163
|
-
await
|
|
27831
|
+
await writeFile10(pagePath, "original content", "utf-8");
|
|
27164
27832
|
await dependencies.createVersion(pagePath, "original content", "write", config, void 0, void 0, tmpDir);
|
|
27165
|
-
await
|
|
27833
|
+
await writeFile10(pagePath, "modified content", "utf-8");
|
|
27166
27834
|
await dependencies.createVersion(pagePath, "modified content", "write", config, void 0, void 0, tmpDir);
|
|
27167
27835
|
await dependencies.revertToVersion(pagePath, "1", config, void 0, tmpDir);
|
|
27168
27836
|
const history = await dependencies.listVersions(pagePath, config, tmpDir);
|
|
27169
|
-
const pageContent = await
|
|
27837
|
+
const pageContent = await readFile19(pagePath, "utf-8");
|
|
27170
27838
|
const observed = await dependencies.getVersion(pagePath, "3", config, tmpDir);
|
|
27171
27839
|
return {
|
|
27172
27840
|
versionIds: history.versions.map((version) => version.versionId),
|
|
@@ -27179,11 +27847,11 @@ async function executeCase2(sample, dependencies) {
|
|
|
27179
27847
|
const pruningConfig = versioningConfig({ maxVersionsPerPage: 2 });
|
|
27180
27848
|
for (let index = 1; index <= 4; index += 1) {
|
|
27181
27849
|
const content = `content v${index}`;
|
|
27182
|
-
await
|
|
27850
|
+
await writeFile10(pagePath, content, "utf-8");
|
|
27183
27851
|
await dependencies.createVersion(pagePath, content, "write", pruningConfig, void 0, void 0, tmpDir);
|
|
27184
27852
|
}
|
|
27185
27853
|
const history = await dependencies.listVersions(pagePath, pruningConfig, tmpDir);
|
|
27186
|
-
const pageContent = await
|
|
27854
|
+
const pageContent = await readFile19(pagePath, "utf-8");
|
|
27187
27855
|
const prunedIds = [];
|
|
27188
27856
|
for (const versionId of ["1", "2"]) {
|
|
27189
27857
|
try {
|
|
@@ -27203,7 +27871,7 @@ async function executeCase2(sample, dependencies) {
|
|
|
27203
27871
|
};
|
|
27204
27872
|
}
|
|
27205
27873
|
case "diff-output": {
|
|
27206
|
-
await
|
|
27874
|
+
await writeFile10(pagePath, "line 1\nline 2\nline 3", "utf-8");
|
|
27207
27875
|
await dependencies.createVersion(
|
|
27208
27876
|
pagePath,
|
|
27209
27877
|
"line 1\nline 2\nline 3",
|
|
@@ -27213,7 +27881,7 @@ async function executeCase2(sample, dependencies) {
|
|
|
27213
27881
|
void 0,
|
|
27214
27882
|
tmpDir
|
|
27215
27883
|
);
|
|
27216
|
-
await
|
|
27884
|
+
await writeFile10(pagePath, "line 1\nline 2 changed\nline 3\nline 4", "utf-8");
|
|
27217
27885
|
await dependencies.createVersion(
|
|
27218
27886
|
pagePath,
|
|
27219
27887
|
"line 1\nline 2 changed\nline 3\nline 4",
|
|
@@ -27224,7 +27892,7 @@ async function executeCase2(sample, dependencies) {
|
|
|
27224
27892
|
tmpDir
|
|
27225
27893
|
);
|
|
27226
27894
|
const history = await dependencies.listVersions(pagePath, config, tmpDir);
|
|
27227
|
-
const pageContent = await
|
|
27895
|
+
const pageContent = await readFile19(pagePath, "utf-8");
|
|
27228
27896
|
const diff = await dependencies.diffVersions(pagePath, "1", "2", config, tmpDir);
|
|
27229
27897
|
const observedLines = normalizeDiffChangedLines(diff);
|
|
27230
27898
|
return {
|
|
@@ -29510,8 +30178,8 @@ function loadCases9(mode, limit) {
|
|
|
29510
30178
|
// src/benchmarks/remnic/procedural-recall/runner.ts
|
|
29511
30179
|
import { randomUUID as randomUUID21 } from "crypto";
|
|
29512
30180
|
import { mkdtemp as mkdtemp6, rm as rm7 } from "fs/promises";
|
|
29513
|
-
import
|
|
29514
|
-
import
|
|
30181
|
+
import os9 from "os";
|
|
30182
|
+
import path25 from "path";
|
|
29515
30183
|
import {
|
|
29516
30184
|
StorageManager as StorageManager2,
|
|
29517
30185
|
parseConfig as parseConfig3,
|
|
@@ -29641,7 +30309,7 @@ async function runProceduralRecallBenchmark(options) {
|
|
|
29641
30309
|
}
|
|
29642
30310
|
for (const sample of e2eCases) {
|
|
29643
30311
|
const startedAt = performance.now();
|
|
29644
|
-
const dir = await mkdtemp6(
|
|
30312
|
+
const dir = await mkdtemp6(path25.join(os9.tmpdir(), "remnic-bench-procedural-recall-"));
|
|
29645
30313
|
let section = null;
|
|
29646
30314
|
try {
|
|
29647
30315
|
const storage = new StorageManager2(dir);
|
|
@@ -29656,7 +30324,7 @@ ${body}`,
|
|
|
29656
30324
|
);
|
|
29657
30325
|
const config = parseConfig3({
|
|
29658
30326
|
memoryDir: dir,
|
|
29659
|
-
workspaceDir:
|
|
30327
|
+
workspaceDir: path25.join(dir, "ws"),
|
|
29660
30328
|
openaiApiKey: "bench-key",
|
|
29661
30329
|
procedural: {
|
|
29662
30330
|
enabled: sample.proceduralEnabled !== false,
|
|
@@ -29726,9 +30394,9 @@ ${body}`,
|
|
|
29726
30394
|
|
|
29727
30395
|
// src/benchmarks/remnic/ingestion-entity-recall/runner.ts
|
|
29728
30396
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
29729
|
-
import { mkdtemp as mkdtemp7, writeFile as
|
|
30397
|
+
import { mkdtemp as mkdtemp7, writeFile as writeFile11, rm as rm8, mkdir as mkdir11, realpath as realpath5 } from "fs/promises";
|
|
29730
30398
|
import { tmpdir as tmpdir2 } from "os";
|
|
29731
|
-
import
|
|
30399
|
+
import path26 from "path";
|
|
29732
30400
|
|
|
29733
30401
|
// src/ingestion-scorer.ts
|
|
29734
30402
|
function normalize(value) {
|
|
@@ -30230,13 +30898,13 @@ async function runIngestionEntityRecallBenchmark(options) {
|
|
|
30230
30898
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30231
30899
|
}
|
|
30232
30900
|
const fixture = emailFixture.generate();
|
|
30233
|
-
const fixtureDir = await mkdtemp7(
|
|
30901
|
+
const fixtureDir = await mkdtemp7(path26.join(tmpdir2(), "bench-email-"));
|
|
30234
30902
|
try {
|
|
30235
30903
|
await options.ingestionAdapter.reset();
|
|
30236
30904
|
for (const file of fixture.files) {
|
|
30237
|
-
const filePath =
|
|
30238
|
-
await
|
|
30239
|
-
await
|
|
30905
|
+
const filePath = path26.join(fixtureDir, file.relativePath);
|
|
30906
|
+
await mkdir11(path26.dirname(filePath), { recursive: true });
|
|
30907
|
+
await writeFile11(filePath, file.content, "utf8");
|
|
30240
30908
|
}
|
|
30241
30909
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30242
30910
|
async () => options.ingestionAdapter.ingest(await realpath5(fixtureDir))
|
|
@@ -30363,9 +31031,9 @@ async function buildResult(options, tasks, totalLatencyMs) {
|
|
|
30363
31031
|
|
|
30364
31032
|
// src/benchmarks/remnic/ingestion-schema-completeness/runner.ts
|
|
30365
31033
|
import { randomUUID as randomUUID23 } from "crypto";
|
|
30366
|
-
import { mkdtemp as mkdtemp8, writeFile as
|
|
31034
|
+
import { mkdtemp as mkdtemp8, writeFile as writeFile12, rm as rm9, mkdir as mkdir12, realpath as realpath6 } from "fs/promises";
|
|
30367
31035
|
import { tmpdir as tmpdir3 } from "os";
|
|
30368
|
-
import
|
|
31036
|
+
import path27 from "path";
|
|
30369
31037
|
var ingestionSchemaCompletenessDefinition = {
|
|
30370
31038
|
id: "ingestion-schema-completeness",
|
|
30371
31039
|
title: "Ingestion: Schema Completeness",
|
|
@@ -30384,13 +31052,13 @@ async function runIngestionSchemaCompletenessBenchmark(options) {
|
|
|
30384
31052
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30385
31053
|
}
|
|
30386
31054
|
const fixture = emailFixture.generate();
|
|
30387
|
-
const fixtureDir = await mkdtemp8(
|
|
31055
|
+
const fixtureDir = await mkdtemp8(path27.join(tmpdir3(), "bench-email-"));
|
|
30388
31056
|
try {
|
|
30389
31057
|
await options.ingestionAdapter.reset();
|
|
30390
31058
|
for (const file of fixture.files) {
|
|
30391
|
-
const filePath =
|
|
30392
|
-
await
|
|
30393
|
-
await
|
|
31059
|
+
const filePath = path27.join(fixtureDir, file.relativePath);
|
|
31060
|
+
await mkdir12(path27.dirname(filePath), { recursive: true });
|
|
31061
|
+
await writeFile12(filePath, file.content, "utf8");
|
|
30394
31062
|
}
|
|
30395
31063
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30396
31064
|
async () => options.ingestionAdapter.ingest(await realpath6(fixtureDir))
|
|
@@ -30536,9 +31204,9 @@ async function runIngestionSchemaCompletenessBenchmark(options) {
|
|
|
30536
31204
|
|
|
30537
31205
|
// src/benchmarks/remnic/ingestion-backlink-f1/runner.ts
|
|
30538
31206
|
import { randomUUID as randomUUID24 } from "crypto";
|
|
30539
|
-
import { mkdtemp as mkdtemp9, writeFile as
|
|
31207
|
+
import { mkdtemp as mkdtemp9, writeFile as writeFile13, rm as rm10, mkdir as mkdir13, realpath as realpath7 } from "fs/promises";
|
|
30540
31208
|
import { tmpdir as tmpdir4 } from "os";
|
|
30541
|
-
import
|
|
31209
|
+
import path28 from "path";
|
|
30542
31210
|
var ingestionBacklinkF1Definition = {
|
|
30543
31211
|
id: "ingestion-backlink-f1",
|
|
30544
31212
|
title: "Ingestion: Backlink F1",
|
|
@@ -30557,13 +31225,13 @@ async function runIngestionBacklinkF1Benchmark(options) {
|
|
|
30557
31225
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30558
31226
|
}
|
|
30559
31227
|
const fixture = emailFixture.generate();
|
|
30560
|
-
const fixtureDir = await mkdtemp9(
|
|
31228
|
+
const fixtureDir = await mkdtemp9(path28.join(tmpdir4(), "bench-email-"));
|
|
30561
31229
|
try {
|
|
30562
31230
|
await options.ingestionAdapter.reset();
|
|
30563
31231
|
for (const file of fixture.files) {
|
|
30564
|
-
const filePath =
|
|
30565
|
-
await
|
|
30566
|
-
await
|
|
31232
|
+
const filePath = path28.join(fixtureDir, file.relativePath);
|
|
31233
|
+
await mkdir13(path28.dirname(filePath), { recursive: true });
|
|
31234
|
+
await writeFile13(filePath, file.content, "utf8");
|
|
30567
31235
|
}
|
|
30568
31236
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30569
31237
|
async () => options.ingestionAdapter.ingest(await realpath7(fixtureDir))
|
|
@@ -30637,9 +31305,9 @@ async function runIngestionBacklinkF1Benchmark(options) {
|
|
|
30637
31305
|
|
|
30638
31306
|
// src/benchmarks/remnic/ingestion-setup-friction/runner.ts
|
|
30639
31307
|
import { randomUUID as randomUUID25 } from "crypto";
|
|
30640
|
-
import { mkdtemp as mkdtemp10, writeFile as
|
|
31308
|
+
import { mkdtemp as mkdtemp10, writeFile as writeFile14, rm as rm11, mkdir as mkdir14, realpath as realpath8 } from "fs/promises";
|
|
30641
31309
|
import { tmpdir as tmpdir5 } from "os";
|
|
30642
|
-
import
|
|
31310
|
+
import path29 from "path";
|
|
30643
31311
|
var INGESTION_SETUP_FRICTION_LOWER_IS_BETTER = /* @__PURE__ */ new Set(["setup_friction", "commands_count", "prompts_count", "errors_count"]);
|
|
30644
31312
|
var ingestionSetupFrictionDefinition = {
|
|
30645
31313
|
id: "ingestion-setup-friction",
|
|
@@ -30659,13 +31327,13 @@ async function runIngestionSetupFrictionBenchmark(options) {
|
|
|
30659
31327
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30660
31328
|
}
|
|
30661
31329
|
const fixture = emailFixture.generate();
|
|
30662
|
-
const fixtureDir = await mkdtemp10(
|
|
31330
|
+
const fixtureDir = await mkdtemp10(path29.join(tmpdir5(), "bench-friction-"));
|
|
30663
31331
|
try {
|
|
30664
31332
|
await options.ingestionAdapter.reset();
|
|
30665
31333
|
for (const file of fixture.files) {
|
|
30666
|
-
const filePath =
|
|
30667
|
-
await
|
|
30668
|
-
await
|
|
31334
|
+
const filePath = path29.join(fixtureDir, file.relativePath);
|
|
31335
|
+
await mkdir14(path29.dirname(filePath), { recursive: true });
|
|
31336
|
+
await writeFile14(filePath, file.content, "utf8");
|
|
30669
31337
|
}
|
|
30670
31338
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30671
31339
|
async () => options.ingestionAdapter.ingest(await realpath8(fixtureDir))
|
|
@@ -30743,9 +31411,9 @@ async function runIngestionSetupFrictionBenchmark(options) {
|
|
|
30743
31411
|
|
|
30744
31412
|
// src/benchmarks/remnic/ingestion-citation-accuracy/runner.ts
|
|
30745
31413
|
import { randomUUID as randomUUID26 } from "crypto";
|
|
30746
|
-
import { mkdtemp as mkdtemp11, writeFile as
|
|
31414
|
+
import { mkdtemp as mkdtemp11, writeFile as writeFile15, rm as rm12, mkdir as mkdir15, realpath as realpath9 } from "fs/promises";
|
|
30747
31415
|
import { tmpdir as tmpdir6 } from "os";
|
|
30748
|
-
import
|
|
31416
|
+
import path30 from "path";
|
|
30749
31417
|
var CITATION_SUPPORT_THRESHOLD = 0.72;
|
|
30750
31418
|
var ingestionCitationAccuracyDefinition = {
|
|
30751
31419
|
id: "ingestion-citation-accuracy",
|
|
@@ -30804,10 +31472,10 @@ function resolveCitedSources(sourceRefs, seeAlso, pageRef, sourceContentMap) {
|
|
|
30804
31472
|
return "";
|
|
30805
31473
|
}
|
|
30806
31474
|
for (const ref of normalizedRefs) {
|
|
30807
|
-
const refBase =
|
|
31475
|
+
const refBase = path30.basename(ref).toLowerCase();
|
|
30808
31476
|
let matched = false;
|
|
30809
31477
|
for (const [relativePath, content] of sourceContentMap) {
|
|
30810
|
-
if (relativePath === ref || relativePath.endsWith(ref) ||
|
|
31478
|
+
if (relativePath === ref || relativePath.endsWith(ref) || path30.basename(relativePath).toLowerCase() === refBase) {
|
|
30811
31479
|
resolved.push(content);
|
|
30812
31480
|
matched = true;
|
|
30813
31481
|
break;
|
|
@@ -30823,9 +31491,9 @@ function resolveCitedSources(sourceRefs, seeAlso, pageRef, sourceContentMap) {
|
|
|
30823
31491
|
if (normalizedRefs.length > 0) {
|
|
30824
31492
|
return "";
|
|
30825
31493
|
}
|
|
30826
|
-
const pageBase =
|
|
31494
|
+
const pageBase = path30.basename(pageRef).toLowerCase();
|
|
30827
31495
|
for (const [relativePath, content] of sourceContentMap) {
|
|
30828
|
-
if (
|
|
31496
|
+
if (path30.basename(relativePath).toLowerCase() === pageBase) {
|
|
30829
31497
|
return content;
|
|
30830
31498
|
}
|
|
30831
31499
|
}
|
|
@@ -30836,13 +31504,13 @@ async function runIngestionCitationAccuracyBenchmark(options) {
|
|
|
30836
31504
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30837
31505
|
}
|
|
30838
31506
|
const fixture = emailFixture.generate();
|
|
30839
|
-
const fixtureDir = await mkdtemp11(
|
|
31507
|
+
const fixtureDir = await mkdtemp11(path30.join(tmpdir6(), "bench-citation-"));
|
|
30840
31508
|
try {
|
|
30841
31509
|
await options.ingestionAdapter.reset();
|
|
30842
31510
|
for (const file of fixture.files) {
|
|
30843
|
-
const filePath =
|
|
30844
|
-
await
|
|
30845
|
-
await
|
|
31511
|
+
const filePath = path30.join(fixtureDir, file.relativePath);
|
|
31512
|
+
await mkdir15(path30.dirname(filePath), { recursive: true });
|
|
31513
|
+
await writeFile15(filePath, file.content, "utf8");
|
|
30846
31514
|
}
|
|
30847
31515
|
const benchmarkStart = performance.now();
|
|
30848
31516
|
const { result: ingestionLog, durationMs: ingestionDurationMs } = await timed(
|
|
@@ -31227,7 +31895,7 @@ var ASSISTANT_MORNING_BRIEF_SMOKE_SCENARIOS = ASSISTANT_MORNING_BRIEF_SCENARIOS.
|
|
|
31227
31895
|
|
|
31228
31896
|
// src/benchmarks/remnic/_assistant-common/runner.ts
|
|
31229
31897
|
import { randomUUID as randomUUID27 } from "crypto";
|
|
31230
|
-
import
|
|
31898
|
+
import path32 from "path";
|
|
31231
31899
|
|
|
31232
31900
|
// src/run-seeds.ts
|
|
31233
31901
|
function buildBenchmarkRunSeeds(runCount, baseSeed) {
|
|
@@ -31317,9 +31985,9 @@ function pairedDeltaConfidenceInterval(candidateValues, baselineValues, options
|
|
|
31317
31985
|
}
|
|
31318
31986
|
|
|
31319
31987
|
// src/judges/sealed-rubric.ts
|
|
31320
|
-
import { createHash as
|
|
31988
|
+
import { createHash as createHash9 } from "crypto";
|
|
31321
31989
|
import { appendFileSync, mkdirSync } from "fs";
|
|
31322
|
-
import
|
|
31990
|
+
import path31 from "path";
|
|
31323
31991
|
|
|
31324
31992
|
// src/judges/sealed-prompts/assistant-rubric-v1.ts
|
|
31325
31993
|
var ASSISTANT_RUBRIC_V1 = `# Assistant rubric v1 (sealed)
|
|
@@ -31426,7 +32094,7 @@ function loadSealedRubric(id = DEFAULT_ASSISTANT_RUBRIC_ID, options = {}) {
|
|
|
31426
32094
|
if (typeof prompt !== "string" || prompt.length === 0) {
|
|
31427
32095
|
throw new Error(`sealed rubric not found in registry: ${id}`);
|
|
31428
32096
|
}
|
|
31429
|
-
const sha256 =
|
|
32097
|
+
const sha256 = createHash9("sha256").update(prompt, "utf8").digest("hex");
|
|
31430
32098
|
const version = parseVersionFromId(id);
|
|
31431
32099
|
return { id, version, prompt, sha256 };
|
|
31432
32100
|
}
|
|
@@ -31599,7 +32267,7 @@ function createSpotCheckFileLogger(options) {
|
|
|
31599
32267
|
return { log() {
|
|
31600
32268
|
} };
|
|
31601
32269
|
}
|
|
31602
|
-
const logPath =
|
|
32270
|
+
const logPath = path31.join(directory, `${runId}.jsonl`);
|
|
31603
32271
|
let written = 0;
|
|
31604
32272
|
let warnedOnWriteFailure = false;
|
|
31605
32273
|
const cap = typeof sampleSize === "number" && sampleSize > 0 ? sampleSize : 5;
|
|
@@ -31688,7 +32356,7 @@ async function runAssistantBenchmark(definition, scenarios, resolved, runnerOpti
|
|
|
31688
32356
|
const runId = buildRunId(definition.id);
|
|
31689
32357
|
const spotCheckLogger = createSpotCheckFileLogger({
|
|
31690
32358
|
runId,
|
|
31691
|
-
directory: runnerOptions.spotCheckDir ??
|
|
32359
|
+
directory: runnerOptions.spotCheckDir ?? path32.join(process.cwd(), "benchmarks", "results", "spot-checks"),
|
|
31692
32360
|
sampleRate: 0.35,
|
|
31693
32361
|
sampleSize: 5
|
|
31694
32362
|
});
|
|
@@ -32337,9 +33005,9 @@ async function runAssistantSynthesisBenchmark(options) {
|
|
|
32337
33005
|
|
|
32338
33006
|
// src/benchmarks/remnic/buffer-surprise-trigger/runner.ts
|
|
32339
33007
|
import { randomUUID as randomUUID28 } from "crypto";
|
|
32340
|
-
import
|
|
32341
|
-
import
|
|
32342
|
-
import { mkdir as
|
|
33008
|
+
import path33 from "path";
|
|
33009
|
+
import os10 from "os";
|
|
33010
|
+
import { mkdir as mkdir16, rm as rm13 } from "fs/promises";
|
|
32343
33011
|
import {
|
|
32344
33012
|
SmartBuffer,
|
|
32345
33013
|
computeSurprise,
|
|
@@ -32568,11 +33236,11 @@ function hasExplicitTopicPivotCue(text) {
|
|
|
32568
33236
|
}
|
|
32569
33237
|
async function runBufferSurpriseTriggerBenchmark(options) {
|
|
32570
33238
|
const cases = loadCases10(options.mode, options.limit);
|
|
32571
|
-
const tmpRoot =
|
|
32572
|
-
|
|
33239
|
+
const tmpRoot = path33.join(
|
|
33240
|
+
os10.tmpdir(),
|
|
32573
33241
|
`remnic-bench-buffer-surprise-${randomUUID28()}`
|
|
32574
33242
|
);
|
|
32575
|
-
await
|
|
33243
|
+
await mkdir16(tmpRoot, { recursive: true });
|
|
32576
33244
|
const tasks = [];
|
|
32577
33245
|
const startedAt = performance.now();
|
|
32578
33246
|
try {
|
|
@@ -32637,12 +33305,12 @@ async function runBufferSurpriseTriggerBenchmark(options) {
|
|
|
32637
33305
|
};
|
|
32638
33306
|
}
|
|
32639
33307
|
async function runSingleCase(caseDef, options) {
|
|
32640
|
-
const memoryDir =
|
|
33308
|
+
const memoryDir = path33.join(
|
|
32641
33309
|
options.tmpRoot,
|
|
32642
33310
|
`${caseDef.id}-${options.label}`
|
|
32643
33311
|
);
|
|
32644
|
-
const workspaceDir =
|
|
32645
|
-
await
|
|
33312
|
+
const workspaceDir = path33.join(memoryDir, "workspace");
|
|
33313
|
+
await mkdir16(workspaceDir, { recursive: true });
|
|
32646
33314
|
const config = parseConfig4({
|
|
32647
33315
|
memoryDir,
|
|
32648
33316
|
workspaceDir,
|
|
@@ -33629,7 +34297,7 @@ async function runRetentionAgedDatasetBenchmark(options) {
|
|
|
33629
34297
|
import { randomUUID as randomUUID31 } from "crypto";
|
|
33630
34298
|
|
|
33631
34299
|
// src/benchmarks/remnic/memcorrect/generator.ts
|
|
33632
|
-
import { createHash as
|
|
34300
|
+
import { createHash as createHash10 } from "crypto";
|
|
33633
34301
|
|
|
33634
34302
|
// src/benchmarks/remnic/memcorrect/token-pools.ts
|
|
33635
34303
|
var PERSONAS = [
|
|
@@ -33953,7 +34621,7 @@ function corpusHash(corpus) {
|
|
|
33953
34621
|
uptakeLatencyCap: corpus.options.uptakeLatencyCap,
|
|
33954
34622
|
scenarios: corpus.scenarios
|
|
33955
34623
|
});
|
|
33956
|
-
return
|
|
34624
|
+
return createHash10("sha256").update(canonical).digest("hex");
|
|
33957
34625
|
}
|
|
33958
34626
|
|
|
33959
34627
|
// src/benchmarks/remnic/memcorrect/schema.ts
|
|
@@ -34904,11 +35572,11 @@ async function runMemCorrectBenchmark(options) {
|
|
|
34904
35572
|
|
|
34905
35573
|
// src/benchmarks/remnic/bounded-memory-contracts/runner.ts
|
|
34906
35574
|
import { randomUUID as randomUUID32 } from "crypto";
|
|
34907
|
-
import { mkdir as
|
|
34908
|
-
import
|
|
35575
|
+
import { mkdir as mkdir17, writeFile as writeFile16 } from "fs/promises";
|
|
35576
|
+
import path34 from "path";
|
|
34909
35577
|
|
|
34910
35578
|
// src/benchmarks/remnic/bounded-memory-contracts/fixture.ts
|
|
34911
|
-
import { createHash as
|
|
35579
|
+
import { createHash as createHash11 } from "crypto";
|
|
34912
35580
|
var SCOPE_ACME = "project:acme";
|
|
34913
35581
|
var SCOPE_BETA = "project:beta";
|
|
34914
35582
|
var SCOPE_ALICE = "user:alice";
|
|
@@ -35391,7 +36059,7 @@ var BOUNDED_MEMORY_SMOKE_FIXTURE = [
|
|
|
35391
36059
|
function fixtureHash(tasks) {
|
|
35392
36060
|
const source = tasks ?? BOUNDED_MEMORY_FIXTURE;
|
|
35393
36061
|
const payload = JSON.stringify(source);
|
|
35394
|
-
return
|
|
36062
|
+
return createHash11("sha256").update(payload, "utf8").digest("hex");
|
|
35395
36063
|
}
|
|
35396
36064
|
|
|
35397
36065
|
// src/benchmarks/remnic/bounded-memory-contracts/agent.ts
|
|
@@ -36137,24 +36805,24 @@ async function runBoundedMemoryContractsBenchmark(options) {
|
|
|
36137
36805
|
};
|
|
36138
36806
|
}
|
|
36139
36807
|
async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks) {
|
|
36140
|
-
const root =
|
|
36141
|
-
await
|
|
36142
|
-
await
|
|
36143
|
-
await
|
|
36144
|
-
await
|
|
36808
|
+
const root = path34.resolve(outputDir);
|
|
36809
|
+
await mkdir17(path34.join(root, "conditions"), { recursive: true });
|
|
36810
|
+
await mkdir17(path34.join(root, "prompts"), { recursive: true });
|
|
36811
|
+
await mkdir17(path34.join(root, "retrieval"), { recursive: true });
|
|
36812
|
+
await mkdir17(path34.join(root, "scores"), { recursive: true });
|
|
36145
36813
|
const csvRows = [
|
|
36146
36814
|
"task_id,condition,family,scope,task_success,should_ask_accuracy,relevant_memory_recall,stale_memory_harm_rate,wrong_scope_retrieval_rate,supersession_respected_rate,citation_coverage,memory_tokens_injected,retrieved_item_count,compression_ratio_vs_raw_transcript"
|
|
36147
36815
|
];
|
|
36148
36816
|
for (const condition of BOUNDED_MEMORY_CONDITIONS) {
|
|
36149
36817
|
const results = byCondition.get(condition);
|
|
36150
|
-
const condDir =
|
|
36151
|
-
await
|
|
36818
|
+
const condDir = path34.join(root, "conditions", condition);
|
|
36819
|
+
await mkdir17(condDir, { recursive: true });
|
|
36152
36820
|
for (const { task, pack, decision } of results) {
|
|
36153
36821
|
const scores = scoreTaskPair(task, pack, decision);
|
|
36154
36822
|
const promptMd = renderPromptPack(task, condition, pack);
|
|
36155
|
-
const promptPath =
|
|
36156
|
-
await
|
|
36157
|
-
await
|
|
36823
|
+
const promptPath = path34.join(root, "prompts", `${task.id}.${condition}.md`);
|
|
36824
|
+
await mkdir17(path34.dirname(promptPath), { recursive: true });
|
|
36825
|
+
await writeFile16(promptPath, promptMd, "utf8");
|
|
36158
36826
|
const retrievalJson = `${JSON.stringify(
|
|
36159
36827
|
{
|
|
36160
36828
|
taskId: task.id,
|
|
@@ -36177,8 +36845,8 @@ async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks
|
|
|
36177
36845
|
2
|
|
36178
36846
|
)}
|
|
36179
36847
|
`;
|
|
36180
|
-
const retrievalPath =
|
|
36181
|
-
await
|
|
36848
|
+
const retrievalPath = path34.join(root, "retrieval", `${task.id}.${condition}.json`);
|
|
36849
|
+
await writeFile16(retrievalPath, retrievalJson, "utf8");
|
|
36182
36850
|
csvRows.push(
|
|
36183
36851
|
[
|
|
36184
36852
|
task.id,
|
|
@@ -36198,24 +36866,24 @@ async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks
|
|
|
36198
36866
|
].join(",")
|
|
36199
36867
|
);
|
|
36200
36868
|
}
|
|
36201
|
-
await
|
|
36202
|
-
|
|
36869
|
+
await writeFile16(
|
|
36870
|
+
path34.join(condDir, "summary.json"),
|
|
36203
36871
|
`${JSON.stringify(conditionAggregates[condition], null, 2)}
|
|
36204
36872
|
`,
|
|
36205
36873
|
"utf8"
|
|
36206
36874
|
);
|
|
36207
36875
|
}
|
|
36208
|
-
await
|
|
36876
|
+
await writeFile16(path34.join(root, "scores", "per-task.csv"), `${csvRows.join("\n")}
|
|
36209
36877
|
`, "utf8");
|
|
36210
|
-
await
|
|
36211
|
-
|
|
36878
|
+
await writeFile16(
|
|
36879
|
+
path34.join(root, "scores", "aggregate.json"),
|
|
36212
36880
|
`${JSON.stringify(conditionAggregates, null, 2)}
|
|
36213
36881
|
`,
|
|
36214
36882
|
"utf8"
|
|
36215
36883
|
);
|
|
36216
36884
|
const report = renderReportMarkdown(tasks, conditionAggregates);
|
|
36217
|
-
await
|
|
36218
|
-
return
|
|
36885
|
+
await writeFile16(path34.join(root, "report.md"), report, "utf8");
|
|
36886
|
+
return path34.join(root, "report.md");
|
|
36219
36887
|
}
|
|
36220
36888
|
function renderPromptPack(task, condition, pack) {
|
|
36221
36889
|
const lines = [];
|
|
@@ -36440,8 +37108,8 @@ function finalizeBenchmarkResultConfig(result, options) {
|
|
|
36440
37108
|
}
|
|
36441
37109
|
|
|
36442
37110
|
// src/benchmark.ts
|
|
36443
|
-
var DEFAULT_BASELINE_PATH =
|
|
36444
|
-
var DEFAULT_REPORT_PATH =
|
|
37111
|
+
var DEFAULT_BASELINE_PATH = path35.join(process.cwd(), "benchmarks", "baseline.json");
|
|
37112
|
+
var DEFAULT_REPORT_PATH = path35.join(process.cwd(), "benchmarks", "report.json");
|
|
36445
37113
|
var BASELINE_VERSION = 1;
|
|
36446
37114
|
var DEFAULT_TOLERANCE = 10;
|
|
36447
37115
|
var DEFAULT_FULL_RUN_COUNT = 5;
|
|
@@ -36519,7 +37187,7 @@ async function runBenchmark(benchmarkId, options) {
|
|
|
36519
37187
|
if (!willWrapPrimary && !willWrapCross) {
|
|
36520
37188
|
return void 0;
|
|
36521
37189
|
}
|
|
36522
|
-
const cacheDir = options.judgeCacheDir ?
|
|
37190
|
+
const cacheDir = options.judgeCacheDir ? path35.resolve(expandTildePath3(options.judgeCacheDir)) : options.outputDir ? path35.join(path35.resolve(expandTildePath3(options.outputDir)), "judge-cache") : void 0;
|
|
36523
37191
|
if (cacheDir === void 0) {
|
|
36524
37192
|
return void 0;
|
|
36525
37193
|
}
|
|
@@ -36651,13 +37319,13 @@ function wrapJudgeWithCache(args) {
|
|
|
36651
37319
|
// differentiator is part of the prompt hash. Bumping
|
|
36652
37320
|
// JUDGE_CACHE_PROTOCOL_VERSION invalidates verdicts when judge
|
|
36653
37321
|
// prompt/parse semantics change (PR #1591, High).
|
|
36654
|
-
judgePromptHash:
|
|
37322
|
+
judgePromptHash: createHash12("sha256").update(JUDGE_CACHE_PROTOCOL_VERSION).update("").update(args.amaBenchJudgeProtocol).update("").update(args.role).digest("hex"),
|
|
36655
37323
|
judgeModelId: args.provider?.model !== void 0 && args.provider.model.length > 0 ? `${args.provider.model}${crossJudgeIdSuffix}` : `unknown-${args.role}-judge`,
|
|
36656
37324
|
// Full judge configuration, deterministically serialized (sorted
|
|
36657
37325
|
// keys) so provider/base-url/retry changes produce fresh cache
|
|
36658
37326
|
// keys. `role` is included so primary and cross judges never
|
|
36659
37327
|
// share a paramsHash.
|
|
36660
|
-
judgeParamsHash:
|
|
37328
|
+
judgeParamsHash: createHash12("sha256").update(
|
|
36661
37329
|
stableStringify2({
|
|
36662
37330
|
role: args.role,
|
|
36663
37331
|
provider: args.provider
|
|
@@ -36718,7 +37386,7 @@ function loadBaseline(baselinePath) {
|
|
|
36718
37386
|
return raw;
|
|
36719
37387
|
}
|
|
36720
37388
|
function saveBaseline(baselinePath, baseline) {
|
|
36721
|
-
fs2.mkdirSync(
|
|
37389
|
+
fs2.mkdirSync(path35.dirname(baselinePath), { recursive: true });
|
|
36722
37390
|
fs2.writeFileSync(baselinePath, `${JSON.stringify(baseline, null, 2)}
|
|
36723
37391
|
`);
|
|
36724
37392
|
}
|
|
@@ -36948,7 +37616,7 @@ function generateReport(results, reportPath) {
|
|
|
36948
37616
|
totalDurationMs: results.reduce((sum, result) => sum + result.totalDurationMs, 0)
|
|
36949
37617
|
};
|
|
36950
37618
|
if (reportPath) {
|
|
36951
|
-
fs2.mkdirSync(
|
|
37619
|
+
fs2.mkdirSync(path35.dirname(reportPath), { recursive: true });
|
|
36952
37620
|
fs2.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}
|
|
36953
37621
|
`);
|
|
36954
37622
|
}
|
|
@@ -37363,7 +38031,7 @@ function formatSignedScore(value) {
|
|
|
37363
38031
|
}
|
|
37364
38032
|
|
|
37365
38033
|
// src/integrity/sealed-qrels.ts
|
|
37366
|
-
import { readFile as
|
|
38034
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
37367
38035
|
function isSealedQrelsArtifact(value) {
|
|
37368
38036
|
if (!value || typeof value !== "object") {
|
|
37369
38037
|
return false;
|
|
@@ -37433,7 +38101,7 @@ function parseSealedQrels(raw, options = {}) {
|
|
|
37433
38101
|
};
|
|
37434
38102
|
}
|
|
37435
38103
|
async function loadSealedQrels(filePath, options = {}) {
|
|
37436
|
-
const raw = await
|
|
38104
|
+
const raw = await readFile20(filePath, "utf8");
|
|
37437
38105
|
return parseSealedQrels(raw, options);
|
|
37438
38106
|
}
|
|
37439
38107
|
function serializeSealedQrels(artifact) {
|
|
@@ -37553,7 +38221,7 @@ function selectFixtureVariant(variants, seed) {
|
|
|
37553
38221
|
}
|
|
37554
38222
|
|
|
37555
38223
|
// src/benchmarks/custom/loader.ts
|
|
37556
|
-
import { readFile as
|
|
38224
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
37557
38225
|
import { parse as parseYaml } from "yaml";
|
|
37558
38226
|
var CUSTOM_SCORING_VALUES = /* @__PURE__ */ new Set([
|
|
37559
38227
|
"exact_match",
|
|
@@ -37573,7 +38241,7 @@ function parseCustomBenchmark(source) {
|
|
|
37573
38241
|
async function loadCustomBenchmarkFile(filePath) {
|
|
37574
38242
|
let source;
|
|
37575
38243
|
try {
|
|
37576
|
-
source = await
|
|
38244
|
+
source = await readFile21(filePath, "utf8");
|
|
37577
38245
|
} catch (error) {
|
|
37578
38246
|
throw new Error(
|
|
37579
38247
|
`Failed to read custom benchmark file ${filePath}: ${formatError(error)}`
|
|
@@ -37681,7 +38349,7 @@ function formatError(error) {
|
|
|
37681
38349
|
|
|
37682
38350
|
// src/benchmarks/custom/runner.ts
|
|
37683
38351
|
import { randomUUID as randomUUID33 } from "crypto";
|
|
37684
|
-
import
|
|
38352
|
+
import path36 from "path";
|
|
37685
38353
|
import { expandTildePath as expandTildePath4 } from "@remnic/core";
|
|
37686
38354
|
async function runCustomBenchmarkFile(filePath, options) {
|
|
37687
38355
|
const spec = await loadCustomBenchmarkFile(filePath);
|
|
@@ -37694,7 +38362,7 @@ async function runCustomBenchmarkFile(filePath, options) {
|
|
|
37694
38362
|
let cacheRestore;
|
|
37695
38363
|
let cacheCounters;
|
|
37696
38364
|
if (spec.scoring === "llm_judge" && runOptions.system.judge !== void 0 && !runOptions.noJudgeCache && (runOptions.judgeProvider ?? null) !== null) {
|
|
37697
|
-
const cacheDir = runOptions.judgeCacheDir ?
|
|
38365
|
+
const cacheDir = runOptions.judgeCacheDir ? path36.resolve(expandTildePath4(runOptions.judgeCacheDir)) : runOptions.outputDir ? path36.join(path36.resolve(expandTildePath4(runOptions.outputDir)), "judge-cache") : void 0;
|
|
37698
38366
|
if (cacheDir !== void 0) {
|
|
37699
38367
|
const originalJudge = runOptions.system.judge;
|
|
37700
38368
|
const wrapped = wrapJudgeWithCache({
|
|
@@ -37895,7 +38563,7 @@ async function scoreTask(scoring, options, question, actual, expected) {
|
|
|
37895
38563
|
}
|
|
37896
38564
|
}
|
|
37897
38565
|
function createCustomBenchmarkDefinition(benchmark, filePath) {
|
|
37898
|
-
const id = `custom:${slugify(
|
|
38566
|
+
const id = `custom:${slugify(path36.basename(filePath, path36.extname(filePath)) || benchmark.name)}`;
|
|
37899
38567
|
return {
|
|
37900
38568
|
id,
|
|
37901
38569
|
title: benchmark.name,
|
|
@@ -38765,9 +39433,9 @@ var chatFixture = {
|
|
|
38765
39433
|
};
|
|
38766
39434
|
|
|
38767
39435
|
// src/judges/calibration-slice.ts
|
|
38768
|
-
import { createHash as
|
|
38769
|
-
import { mkdir as
|
|
38770
|
-
import
|
|
39436
|
+
import { createHash as createHash13, randomBytes as randomBytes3 } from "crypto";
|
|
39437
|
+
import { mkdir as mkdir18, readFile as readFile22, rename as rename4, unlink as unlink4, writeFile as writeFile17 } from "fs/promises";
|
|
39438
|
+
import path37 from "path";
|
|
38771
39439
|
|
|
38772
39440
|
// src/judges/cohen-kappa.ts
|
|
38773
39441
|
var DEFAULT_KAPPA_BOOTSTRAP_SAMPLES = 2e3;
|
|
@@ -38912,7 +39580,7 @@ function selectCalibrationSlice(questionIds, size = CALIBRATION_SLICE_SIZE) {
|
|
|
38912
39580
|
unique.push(id);
|
|
38913
39581
|
}
|
|
38914
39582
|
}
|
|
38915
|
-
return unique.map((id) => ({ id, digest:
|
|
39583
|
+
return unique.map((id) => ({ id, digest: createHash13("sha256").update(id, "utf8").digest("hex") })).sort((a, b) => a.digest < b.digest ? -1 : a.digest > b.digest ? 1 : 0).slice(0, Math.min(size, unique.length)).map((entry) => entry.id);
|
|
38916
39584
|
}
|
|
38917
39585
|
async function runJudgeCalibration(options) {
|
|
38918
39586
|
const binScore = options.binScore ?? ((score) => binarizeJudgeScore(score));
|
|
@@ -38987,7 +39655,7 @@ function validatePinnedQuestionIds(ids, availableIds) {
|
|
|
38987
39655
|
return [...ids];
|
|
38988
39656
|
}
|
|
38989
39657
|
function hashCalibrationAnswerSet(answers) {
|
|
38990
|
-
return
|
|
39658
|
+
return createHash13("sha256").update(JSON.stringify(answers.map((answer) => [
|
|
38991
39659
|
answer.questionId,
|
|
38992
39660
|
answer.question,
|
|
38993
39661
|
answer.predicted,
|
|
@@ -38995,7 +39663,7 @@ function hashCalibrationAnswerSet(answers) {
|
|
|
38995
39663
|
]))).digest("hex");
|
|
38996
39664
|
}
|
|
38997
39665
|
async function writeJudgeCalibrationState(result, calibrationDir, identities, provenance) {
|
|
38998
|
-
await
|
|
39666
|
+
await mkdir18(calibrationDir, { recursive: true });
|
|
38999
39667
|
const state = {
|
|
39000
39668
|
kappa: result.kappa,
|
|
39001
39669
|
sampleSize: result.sampleSize,
|
|
@@ -39008,23 +39676,23 @@ async function writeJudgeCalibrationState(result, calibrationDir, identities, pr
|
|
|
39008
39676
|
...provenance ? provenance : {},
|
|
39009
39677
|
...identities ? identities : {}
|
|
39010
39678
|
};
|
|
39011
|
-
const filePath =
|
|
39679
|
+
const filePath = path37.join(calibrationDir, `${sanitizeCalibrationSegment(result.benchmarkId)}.json`);
|
|
39012
39680
|
const tempPath = `${filePath}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
39013
|
-
await
|
|
39681
|
+
await writeFile17(tempPath, `${JSON.stringify(state, null, 2)}
|
|
39014
39682
|
`, "utf8");
|
|
39015
39683
|
try {
|
|
39016
|
-
await
|
|
39684
|
+
await rename4(tempPath, filePath);
|
|
39017
39685
|
} catch (error) {
|
|
39018
|
-
await
|
|
39686
|
+
await unlink4(tempPath).catch(() => void 0);
|
|
39019
39687
|
throw error;
|
|
39020
39688
|
}
|
|
39021
39689
|
return filePath;
|
|
39022
39690
|
}
|
|
39023
39691
|
async function loadJudgeCalibrationState(benchmarkId, calibrationDir) {
|
|
39024
|
-
const filePath =
|
|
39692
|
+
const filePath = path37.join(calibrationDir, `${sanitizeCalibrationSegment(benchmarkId)}.json`);
|
|
39025
39693
|
let raw;
|
|
39026
39694
|
try {
|
|
39027
|
-
raw = await
|
|
39695
|
+
raw = await readFile22(filePath, "utf8");
|
|
39028
39696
|
} catch {
|
|
39029
39697
|
return void 0;
|
|
39030
39698
|
}
|
|
@@ -39108,9 +39776,9 @@ function sanitizeCalibrationSegment(value) {
|
|
|
39108
39776
|
}
|
|
39109
39777
|
|
|
39110
39778
|
// src/benchmarks/remnic/procedural-recall/ablation.ts
|
|
39111
|
-
import { mkdir as
|
|
39112
|
-
import
|
|
39113
|
-
import
|
|
39779
|
+
import { mkdir as mkdir19, mkdtemp as mkdtemp12, rm as rm14, writeFile as writeFile18, readFile as readFile23 } from "fs/promises";
|
|
39780
|
+
import os11 from "os";
|
|
39781
|
+
import path38 from "path";
|
|
39114
39782
|
import {
|
|
39115
39783
|
StorageManager as StorageManager3,
|
|
39116
39784
|
parseConfig as parseConfig5,
|
|
@@ -39141,7 +39809,7 @@ async function runSide(scenarios, proceduralEnabled) {
|
|
|
39141
39809
|
const observed = [];
|
|
39142
39810
|
for (const scenario of scenarios) {
|
|
39143
39811
|
const dir = await mkdtemp12(
|
|
39144
|
-
|
|
39812
|
+
path38.join(os11.tmpdir(), "remnic-bench-proc-ablation-")
|
|
39145
39813
|
);
|
|
39146
39814
|
try {
|
|
39147
39815
|
const storage = new StorageManager3(dir);
|
|
@@ -39156,7 +39824,7 @@ ${body}`,
|
|
|
39156
39824
|
);
|
|
39157
39825
|
const config = parseConfig5({
|
|
39158
39826
|
memoryDir: dir,
|
|
39159
|
-
workspaceDir:
|
|
39827
|
+
workspaceDir: path38.join(dir, "ws"),
|
|
39160
39828
|
openaiApiKey: "bench-key",
|
|
39161
39829
|
procedural: {
|
|
39162
39830
|
enabled: proceduralEnabled,
|
|
@@ -39231,7 +39899,7 @@ async function runProceduralAblation(options) {
|
|
|
39231
39899
|
};
|
|
39232
39900
|
}
|
|
39233
39901
|
async function loadAblationFixture(fixturePath) {
|
|
39234
|
-
const raw = await
|
|
39902
|
+
const raw = await readFile23(fixturePath, "utf8");
|
|
39235
39903
|
let parsed;
|
|
39236
39904
|
try {
|
|
39237
39905
|
parsed = JSON.parse(raw);
|
|
@@ -39327,9 +39995,9 @@ async function runProceduralAblationCli(args) {
|
|
|
39327
39995
|
random: args.random,
|
|
39328
39996
|
seed: args.seed
|
|
39329
39997
|
});
|
|
39330
|
-
const outDir =
|
|
39331
|
-
await
|
|
39332
|
-
await
|
|
39998
|
+
const outDir = path38.dirname(path38.resolve(args.outPath));
|
|
39999
|
+
await mkdir19(outDir, { recursive: true });
|
|
40000
|
+
await writeFile18(args.outPath, JSON.stringify(artifact, null, 2) + "\n", "utf8");
|
|
39333
40001
|
return artifact;
|
|
39334
40002
|
}
|
|
39335
40003
|
|
|
@@ -40443,7 +41111,7 @@ function createMitigatedTarget(config) {
|
|
|
40443
41111
|
}
|
|
40444
41112
|
|
|
40445
41113
|
// src/coding-graph/generator.ts
|
|
40446
|
-
import { createHash as
|
|
41114
|
+
import { createHash as createHash14 } from "crypto";
|
|
40447
41115
|
function createSeededRng3(seed) {
|
|
40448
41116
|
let state = seed >>> 0;
|
|
40449
41117
|
return function rng() {
|
|
@@ -40472,7 +41140,7 @@ var EDGE_TYPE_WEIGHTS = [
|
|
|
40472
41140
|
var PROVENANCE_VALUES = ["heuristic", "heuristic", "heuristic", "trace"];
|
|
40473
41141
|
var AVG_BYTES_PER_LINE = 40;
|
|
40474
41142
|
function hashContent(input) {
|
|
40475
|
-
return
|
|
41143
|
+
return createHash14("sha256").update(input).digest("hex").slice(0, 16);
|
|
40476
41144
|
}
|
|
40477
41145
|
function generateSyntheticRepo(config) {
|
|
40478
41146
|
const rng = createSeededRng3(config.seed);
|
|
@@ -40570,8 +41238,8 @@ import { performance as performance2 } from "perf_hooks";
|
|
|
40570
41238
|
import { mkdtemp as mkdtemp13, rm as rm15 } from "fs/promises";
|
|
40571
41239
|
import { statSync } from "fs";
|
|
40572
41240
|
import { tmpdir as tmpdir7 } from "os";
|
|
40573
|
-
import
|
|
40574
|
-
import
|
|
41241
|
+
import path39 from "path";
|
|
41242
|
+
import os12 from "os";
|
|
40575
41243
|
import {
|
|
40576
41244
|
GraphStore
|
|
40577
41245
|
} from "@remnic/coding-graph";
|
|
@@ -40597,14 +41265,14 @@ var CODING_GRAPH_BENCH_SCHEMA_VERSION = 2;
|
|
|
40597
41265
|
|
|
40598
41266
|
// src/coding-graph/harness.ts
|
|
40599
41267
|
function captureMachineFingerprint() {
|
|
40600
|
-
const cpus =
|
|
41268
|
+
const cpus = os12.cpus();
|
|
40601
41269
|
return {
|
|
40602
41270
|
arch: process.arch,
|
|
40603
41271
|
platform: process.platform,
|
|
40604
41272
|
nodeVersion: process.version,
|
|
40605
41273
|
cpuModel: cpus.length > 0 ? cpus[0].model : null,
|
|
40606
41274
|
cpuCores: cpus.length,
|
|
40607
|
-
totalMemoryMb: Math.round(
|
|
41275
|
+
totalMemoryMb: Math.round(os12.totalmem() / (1024 * 1024))
|
|
40608
41276
|
};
|
|
40609
41277
|
}
|
|
40610
41278
|
function percentile3(sorted, p) {
|
|
@@ -40667,15 +41335,15 @@ async function runCodingGraphBenchmark(config = {}) {
|
|
|
40667
41335
|
const sampleRss = () => {
|
|
40668
41336
|
peakRss = Math.max(peakRss, process.memoryUsage().rss);
|
|
40669
41337
|
};
|
|
40670
|
-
const dir = await mkdtemp13(
|
|
40671
|
-
const dbPath =
|
|
41338
|
+
const dir = await mkdtemp13(path39.join(tmpdir7(), "coding-graph-bench-"));
|
|
41339
|
+
const dbPath = path39.join(dir, "bench.sqlite");
|
|
40672
41340
|
try {
|
|
40673
41341
|
const store = await GraphStore.open({ dbPath });
|
|
40674
41342
|
try {
|
|
40675
41343
|
const FULL_INDEX_SAMPLES = 3;
|
|
40676
41344
|
const fullIndexSamples = [];
|
|
40677
41345
|
for (let s = 0; s < FULL_INDEX_SAMPLES; s++) {
|
|
40678
|
-
const sampleStore = s === 0 ? store : await GraphStore.open({ dbPath:
|
|
41346
|
+
const sampleStore = s === 0 ? store : await GraphStore.open({ dbPath: path39.join(dir, `bench-warm-${s}.sqlite`) });
|
|
40679
41347
|
const fi = await timeAsync(() => sampleStore.upsertFileBatch(storeFiles));
|
|
40680
41348
|
if (!fi.result.ok) {
|
|
40681
41349
|
if (sampleStore !== store) await sampleStore.close();
|
|
@@ -41067,6 +41735,7 @@ export {
|
|
|
41067
41735
|
SEALED_PROMPT_REGISTRY,
|
|
41068
41736
|
SINGLE_FLAG_ABLATION_MATRIX,
|
|
41069
41737
|
SYNTHETIC_MEMORIES,
|
|
41738
|
+
StructuredJudgeError,
|
|
41070
41739
|
ZepMemCorrectAdapter,
|
|
41071
41740
|
addContaminationEntry,
|
|
41072
41741
|
aggregateTaskScores,
|
|
@@ -41140,6 +41809,7 @@ export {
|
|
|
41140
41809
|
createResponderFromProvider,
|
|
41141
41810
|
createSeededRng,
|
|
41142
41811
|
createSpotCheckFileLogger,
|
|
41812
|
+
createStructuredBenchJudge,
|
|
41143
41813
|
createStructuredJudgeFromProvider,
|
|
41144
41814
|
createSyntheticEmailIngestionAdapter,
|
|
41145
41815
|
createSyntheticTarget,
|
|
@@ -41177,6 +41847,7 @@ export {
|
|
|
41177
41847
|
isContaminationManifest,
|
|
41178
41848
|
isSealedQrelsArtifact,
|
|
41179
41849
|
isSha256Hex,
|
|
41850
|
+
isStructuredJudgeProvider,
|
|
41180
41851
|
judgeMemCorrectCorrectionAcceptance,
|
|
41181
41852
|
judgeMemCorrectStaleMemoryHarm,
|
|
41182
41853
|
linkMatches,
|