@remnic/bench 9.6.19 → 9.6.20
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 +76 -40
- package/dist/index.js +1165 -620
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -8972,11 +8972,560 @@ function createClaudeCliProvider(config, deps) {
|
|
|
8972
8972
|
// src/providers/codex-cli.ts
|
|
8973
8973
|
import { spawn as spawn2 } from "child_process";
|
|
8974
8974
|
import { createHash as createHash5, randomUUID } from "crypto";
|
|
8975
|
-
import { mkdir as
|
|
8975
|
+
import { mkdir as mkdir6, mkdtemp as mkdtemp3, readFile as readFile7, rm as rm3, writeFile as writeFile6 } from "fs/promises";
|
|
8976
|
+
import os5 from "os";
|
|
8977
|
+
import path8 from "path";
|
|
8978
|
+
|
|
8979
|
+
// src/judges/memcorrect-rubrics.ts
|
|
8980
|
+
var OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION = "openai-responses-bench-v1";
|
|
8981
|
+
var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION = "memcorrect-correction-acceptance-v1";
|
|
8982
|
+
var MEMCORRECT_STALE_HARM_RUBRIC_VERSION = "memcorrect-stale-memory-harm-v1";
|
|
8983
|
+
var GENERAL_ANSWER_JUDGE_RUBRIC = [
|
|
8984
|
+
"Grade the predicted benchmark answer against the reference answer.",
|
|
8985
|
+
"A score of 1 means fully correct, 0 means fully incorrect, and values between 0 and 1 mean partially correct.",
|
|
8986
|
+
"Do not reward unsupported claims. Ignore harmless wording and formatting differences."
|
|
8987
|
+
].join(" ");
|
|
8988
|
+
var MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC = [
|
|
8989
|
+
"Decide whether the memory system accepted the user's correction.",
|
|
8990
|
+
"Pass only when the corrected fact is reflected and the retired fact is not asserted as current.",
|
|
8991
|
+
"A quotation or correction-history record that clearly marks the retired fact as obsolete is not stale recall.",
|
|
8992
|
+
"Use a score of 1 for accepted, 0 for not accepted, and a fractional score only when the evidence is genuinely ambiguous."
|
|
8993
|
+
].join(" ");
|
|
8994
|
+
var MEMCORRECT_STALE_HARM_RUBRIC = [
|
|
8995
|
+
"Decide whether the memory system avoided stale-memory harm after a correction.",
|
|
8996
|
+
"Pass only when the answer does not present the retired fact as current and does not act on it.",
|
|
8997
|
+
"Correction provenance may mention the retired fact only when it is explicitly identified as obsolete.",
|
|
8998
|
+
"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."
|
|
8999
|
+
].join(" ");
|
|
9000
|
+
|
|
9001
|
+
// src/providers/structured-judge.ts
|
|
9002
|
+
var VERDICT_JSON_SCHEMA = {
|
|
9003
|
+
type: "object",
|
|
9004
|
+
additionalProperties: false,
|
|
9005
|
+
required: ["score", "decision", "reason"],
|
|
9006
|
+
properties: {
|
|
9007
|
+
score: { type: "number", minimum: 0, maximum: 1 },
|
|
9008
|
+
decision: { type: "string", enum: ["pass", "partial", "fail"] },
|
|
9009
|
+
reason: { type: "string" }
|
|
9010
|
+
}
|
|
9011
|
+
};
|
|
9012
|
+
var ASSISTANT_RUBRIC_JSON_SCHEMA = {
|
|
9013
|
+
type: "object",
|
|
9014
|
+
additionalProperties: false,
|
|
9015
|
+
required: ["identity_accuracy", "stance_coherence", "novelty", "calibration", "notes"],
|
|
9016
|
+
properties: {
|
|
9017
|
+
identity_accuracy: { type: "number", minimum: 0, maximum: 5 },
|
|
9018
|
+
stance_coherence: { type: "number", minimum: 0, maximum: 5 },
|
|
9019
|
+
novelty: { type: "number", minimum: 0, maximum: 5 },
|
|
9020
|
+
calibration: { type: "number", minimum: 0, maximum: 5 },
|
|
9021
|
+
notes: { type: "string" }
|
|
9022
|
+
}
|
|
9023
|
+
};
|
|
9024
|
+
var StructuredJudgeError = class extends Error {
|
|
9025
|
+
code;
|
|
9026
|
+
retryable;
|
|
9027
|
+
httpStatus;
|
|
9028
|
+
telemetry;
|
|
9029
|
+
constructor(failure) {
|
|
9030
|
+
super(failure.error.message);
|
|
9031
|
+
this.name = "StructuredJudgeError";
|
|
9032
|
+
this.code = failure.error.code;
|
|
9033
|
+
this.retryable = failure.error.retryable;
|
|
9034
|
+
this.httpStatus = failure.error.httpStatus;
|
|
9035
|
+
this.telemetry = failure.telemetry;
|
|
9036
|
+
}
|
|
9037
|
+
};
|
|
9038
|
+
function isStructuredJudgeProvider(provider) {
|
|
9039
|
+
const candidate = provider;
|
|
9040
|
+
return typeof candidate.judge === "function" && typeof candidate.evaluateAssistantRubric === "function";
|
|
9041
|
+
}
|
|
9042
|
+
function createStructuredBenchJudge(provider, rubricVersion = OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION) {
|
|
9043
|
+
const scoreWithMetrics = async (question, predicted, expected, control) => unwrapJudgeResult(
|
|
9044
|
+
provider,
|
|
9045
|
+
await provider.judge({
|
|
9046
|
+
rubric: GENERAL_ANSWER_JUDGE_RUBRIC,
|
|
9047
|
+
rubricVersion,
|
|
9048
|
+
input: [`QUESTION: ${question}`, `REFERENCE_ANSWER: ${expected}`, `PREDICTED_ANSWER: ${predicted}`].join(
|
|
9049
|
+
"\n\n"
|
|
9050
|
+
),
|
|
9051
|
+
signal: control?.signal
|
|
9052
|
+
})
|
|
9053
|
+
);
|
|
9054
|
+
const scoreBinaryPrompt = async (prompt, control) => {
|
|
9055
|
+
const result = await provider.judge({
|
|
9056
|
+
rubric: `${GENERAL_ANSWER_JUDGE_RUBRIC} This evaluator is binary: score must be exactly 0 or 1.`,
|
|
9057
|
+
rubricVersion,
|
|
9058
|
+
input: prompt,
|
|
9059
|
+
signal: control?.signal
|
|
9060
|
+
});
|
|
9061
|
+
if (result.ok && result.verdict.score !== 0 && result.verdict.score !== 1) {
|
|
9062
|
+
throwJudgeFailure(provider, {
|
|
9063
|
+
ok: false,
|
|
9064
|
+
error: {
|
|
9065
|
+
code: "malformed_verdict",
|
|
9066
|
+
message: "Structured judge returned a non-binary verdict for a binary rubric.",
|
|
9067
|
+
retryable: false
|
|
9068
|
+
},
|
|
9069
|
+
telemetry: { ...result.telemetry, errorCode: "malformed_verdict" }
|
|
9070
|
+
});
|
|
9071
|
+
}
|
|
9072
|
+
return unwrapJudgeResult(provider, result);
|
|
9073
|
+
};
|
|
9074
|
+
const judgeSpecialized = async (request, rubric, control) => {
|
|
9075
|
+
const result = await provider.judge({
|
|
9076
|
+
rubric: rubric === "correction" ? MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC : MEMCORRECT_STALE_HARM_RUBRIC,
|
|
9077
|
+
rubricVersion: rubric === "correction" ? MEMCORRECT_CORRECTION_ACCEPTANCE_RUBRIC_VERSION : MEMCORRECT_STALE_HARM_RUBRIC_VERSION,
|
|
9078
|
+
input: serializeMemCorrectJudgeRequest(request),
|
|
9079
|
+
signal: control?.signal
|
|
9080
|
+
});
|
|
9081
|
+
if (!result.ok) {
|
|
9082
|
+
throwJudgeFailure(provider, result);
|
|
9083
|
+
}
|
|
9084
|
+
const base = unwrapJudgeResult(provider, result);
|
|
9085
|
+
return {
|
|
9086
|
+
...base,
|
|
9087
|
+
decision: result.verdict.decision,
|
|
9088
|
+
reason: result.verdict.reason,
|
|
9089
|
+
rubricVersion: result.telemetry.rubricVersion
|
|
9090
|
+
};
|
|
9091
|
+
};
|
|
9092
|
+
return {
|
|
9093
|
+
async score(question, predicted, expected, control) {
|
|
9094
|
+
return (await scoreWithMetrics(question, predicted, expected, control)).score;
|
|
9095
|
+
},
|
|
9096
|
+
scoreWithMetrics,
|
|
9097
|
+
scoreBinaryPrompt,
|
|
9098
|
+
judgeMemCorrectCorrectionAcceptance: (request, control) => judgeSpecialized(request, "correction", control),
|
|
9099
|
+
judgeMemCorrectStaleMemoryHarm: (request, control) => judgeSpecialized(request, "stale_harm", control)
|
|
9100
|
+
};
|
|
9101
|
+
}
|
|
9102
|
+
function parseStructuredJudgeVerdict(text) {
|
|
9103
|
+
let parsed;
|
|
9104
|
+
try {
|
|
9105
|
+
parsed = JSON.parse(text);
|
|
9106
|
+
} catch {
|
|
9107
|
+
return null;
|
|
9108
|
+
}
|
|
9109
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
9110
|
+
const candidate = parsed;
|
|
9111
|
+
if (Object.keys(candidate).sort().join(",") !== "decision,reason,score") return null;
|
|
9112
|
+
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) {
|
|
9113
|
+
return null;
|
|
9114
|
+
}
|
|
9115
|
+
return {
|
|
9116
|
+
score: candidate.score,
|
|
9117
|
+
decision: candidate.decision,
|
|
9118
|
+
reason: candidate.reason.trim()
|
|
9119
|
+
};
|
|
9120
|
+
}
|
|
9121
|
+
function isValidAssistantRubric(text) {
|
|
9122
|
+
let parsed;
|
|
9123
|
+
try {
|
|
9124
|
+
parsed = JSON.parse(text);
|
|
9125
|
+
} catch {
|
|
9126
|
+
return false;
|
|
9127
|
+
}
|
|
9128
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false;
|
|
9129
|
+
const candidate = parsed;
|
|
9130
|
+
if (Object.keys(candidate).sort().join(",") !== "calibration,identity_accuracy,notes,novelty,stance_coherence") {
|
|
9131
|
+
return false;
|
|
9132
|
+
}
|
|
9133
|
+
return ["identity_accuracy", "stance_coherence", "novelty", "calibration"].every(
|
|
9134
|
+
(key) => typeof candidate[key] === "number" && Number.isFinite(candidate[key]) && candidate[key] >= 0 && candidate[key] <= 5
|
|
9135
|
+
) && typeof candidate.notes === "string";
|
|
9136
|
+
}
|
|
9137
|
+
function serializeMemCorrectJudgeRequest(request) {
|
|
9138
|
+
return JSON.stringify({
|
|
9139
|
+
taskId: request.taskId,
|
|
9140
|
+
query: request.query,
|
|
9141
|
+
retiredContent: request.retiredContent,
|
|
9142
|
+
correctedContent: request.correctedContent,
|
|
9143
|
+
evidence: {
|
|
9144
|
+
postCorrectionRecall: request.postCorrectionRecall,
|
|
9145
|
+
postMaintenanceRecall: request.postMaintenanceRecall,
|
|
9146
|
+
postReingestRecall: request.postReingestRecall
|
|
9147
|
+
}
|
|
9148
|
+
});
|
|
9149
|
+
}
|
|
9150
|
+
function unwrapJudgeResult(provider, result) {
|
|
9151
|
+
if (!result.ok) {
|
|
9152
|
+
throwJudgeFailure(provider, result);
|
|
9153
|
+
}
|
|
9154
|
+
return {
|
|
9155
|
+
score: result.verdict.score,
|
|
9156
|
+
tokens: {
|
|
9157
|
+
input: result.telemetry.inputTokens,
|
|
9158
|
+
output: result.telemetry.outputTokens
|
|
9159
|
+
},
|
|
9160
|
+
latencyMs: result.telemetry.latencyMs,
|
|
9161
|
+
model: result.telemetry.model
|
|
9162
|
+
};
|
|
9163
|
+
}
|
|
9164
|
+
function throwJudgeFailure(provider, failure) {
|
|
9165
|
+
throw provider.createJudgeError?.(failure) ?? new StructuredJudgeError(failure);
|
|
9166
|
+
}
|
|
9167
|
+
|
|
9168
|
+
// src/providers/codex-credit-budget.ts
|
|
9169
|
+
import { mkdir as mkdir5, open, readFile as readFile6, rename as rename2, rmdir, unlink as unlink3, writeFile as writeFile5 } from "fs/promises";
|
|
8976
9170
|
import os4 from "os";
|
|
8977
9171
|
import path7 from "path";
|
|
9172
|
+
var ONE_MILLION = 1e6;
|
|
9173
|
+
var MAX_BOUNDED_CALL_CREDITS = 300;
|
|
9174
|
+
var SOL_MODEL = /^gpt-5\.6-sol$/i;
|
|
9175
|
+
var CREDIT_RATES = [
|
|
9176
|
+
[/^gpt-5\.6-sol$/i, { input: 125, cachedInput: 12.5, output: 750 }],
|
|
9177
|
+
[/^gpt-5\.6-terra$/i, { input: 62.5, cachedInput: 6.25, output: 375 }],
|
|
9178
|
+
[/^gpt-5\.6-luna$/i, { input: 25, cachedInput: 2.5, output: 150 }],
|
|
9179
|
+
[/^gpt-5\.5$/i, { input: 125, cachedInput: 12.5, output: 750 }],
|
|
9180
|
+
[/^gpt-5\.4-mini$/i, { input: 18.75, cachedInput: 1.875, output: 113 }],
|
|
9181
|
+
[/^gpt-5\.4$/i, { input: 62.5, cachedInput: 6.25, output: 375 }],
|
|
9182
|
+
[/^gpt-5\.3-codex$/i, { input: 43.75, cachedInput: 4.375, output: 350 }],
|
|
9183
|
+
[/^gpt-5\.2$/i, { input: 43.75, cachedInput: 4.375, output: 350 }]
|
|
9184
|
+
];
|
|
9185
|
+
var completionQueue = Promise.resolve();
|
|
9186
|
+
var CodexCreditAccountingError = class extends Error {
|
|
9187
|
+
constructor(message) {
|
|
9188
|
+
super(message);
|
|
9189
|
+
this.name = "CodexCreditAccountingError";
|
|
9190
|
+
}
|
|
9191
|
+
};
|
|
9192
|
+
var CodexCreditDispatchError = class extends Error {
|
|
9193
|
+
constructor(message, options) {
|
|
9194
|
+
super(message, options);
|
|
9195
|
+
this.name = "CodexCreditDispatchError";
|
|
9196
|
+
}
|
|
9197
|
+
};
|
|
9198
|
+
function resolveCodexCreditBudgetConfig(env = process.env) {
|
|
9199
|
+
const rawBudget = env.REMNIC_BENCH_CODEX_CREDIT_BUDGET?.trim();
|
|
9200
|
+
if (!rawBudget) return void 0;
|
|
9201
|
+
const budgetCredits = parsePositiveNumber(
|
|
9202
|
+
rawBudget,
|
|
9203
|
+
"REMNIC_BENCH_CODEX_CREDIT_BUDGET"
|
|
9204
|
+
);
|
|
9205
|
+
const reserveCredits = parseNonNegativeNumber(
|
|
9206
|
+
env.REMNIC_BENCH_CODEX_CREDIT_RESERVE?.trim() ?? "473",
|
|
9207
|
+
"REMNIC_BENCH_CODEX_CREDIT_RESERVE"
|
|
9208
|
+
);
|
|
9209
|
+
if (reserveCredits >= budgetCredits) {
|
|
9210
|
+
throw new Error(
|
|
9211
|
+
"REMNIC_BENCH_CODEX_CREDIT_RESERVE must be smaller than REMNIC_BENCH_CODEX_CREDIT_BUDGET"
|
|
9212
|
+
);
|
|
9213
|
+
}
|
|
9214
|
+
if (reserveCredits < MAX_BOUNDED_CALL_CREDITS) {
|
|
9215
|
+
throw new Error(
|
|
9216
|
+
`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`
|
|
9217
|
+
);
|
|
9218
|
+
}
|
|
9219
|
+
const ledgerPath = path7.resolve(
|
|
9220
|
+
expandHomeRelativePath2(
|
|
9221
|
+
env.REMNIC_BENCH_CODEX_CREDIT_LEDGER?.trim() || ".remnic/bench/codex-credit-ledger.json"
|
|
9222
|
+
)
|
|
9223
|
+
);
|
|
9224
|
+
return {
|
|
9225
|
+
budgetCredits,
|
|
9226
|
+
reserveCredits,
|
|
9227
|
+
ledgerPath,
|
|
9228
|
+
allowSol: /^(?:1|true|yes|on)$/i.test(
|
|
9229
|
+
env.REMNIC_BENCH_CODEX_ALLOW_SOL?.trim() ?? ""
|
|
9230
|
+
)
|
|
9231
|
+
};
|
|
9232
|
+
}
|
|
9233
|
+
async function runWithinCodexCreditBudget(args) {
|
|
9234
|
+
if (!args.config) {
|
|
9235
|
+
return (await args.run()).value;
|
|
9236
|
+
}
|
|
9237
|
+
const previous = completionQueue;
|
|
9238
|
+
let release;
|
|
9239
|
+
completionQueue = new Promise((resolve) => {
|
|
9240
|
+
release = resolve;
|
|
9241
|
+
});
|
|
9242
|
+
await previous;
|
|
9243
|
+
const lockPath = `${args.config.ledgerPath}.lock`;
|
|
9244
|
+
let lock;
|
|
9245
|
+
let dispatchStarted = false;
|
|
9246
|
+
let accountingSettled = false;
|
|
9247
|
+
try {
|
|
9248
|
+
await mkdir5(path7.dirname(lockPath), { recursive: true, mode: 448 });
|
|
9249
|
+
lock = await acquireLedgerLock(lockPath);
|
|
9250
|
+
assertModelAllowed(args.model, args.config);
|
|
9251
|
+
const ledger = await readLedger(args.config);
|
|
9252
|
+
if (ledger.blockedReason) {
|
|
9253
|
+
throw new Error(
|
|
9254
|
+
`Codex credit ledger is blocked pending manual reconciliation: ${ledger.blockedReason}`
|
|
9255
|
+
);
|
|
9256
|
+
}
|
|
9257
|
+
const usableCredits = args.config.budgetCredits - args.config.reserveCredits;
|
|
9258
|
+
if (ledger.spentCredits >= usableCredits) {
|
|
9259
|
+
throw new Error(
|
|
9260
|
+
`Codex credit budget exhausted: ${ledger.spentCredits.toFixed(3)} spent; ${usableCredits.toFixed(3)} usable after the ${args.config.reserveCredits.toFixed(3)} safety reserve.`
|
|
9261
|
+
);
|
|
9262
|
+
}
|
|
9263
|
+
await writeLockState(lock, "in-flight");
|
|
9264
|
+
dispatchStarted = true;
|
|
9265
|
+
let result;
|
|
9266
|
+
try {
|
|
9267
|
+
result = await args.run();
|
|
9268
|
+
} catch (error) {
|
|
9269
|
+
if (error instanceof CodexCreditDispatchError) {
|
|
9270
|
+
await writeLockState(lock, "settled");
|
|
9271
|
+
accountingSettled = true;
|
|
9272
|
+
} else {
|
|
9273
|
+
const blockedLedger = {
|
|
9274
|
+
...ledger,
|
|
9275
|
+
blockedReason: error instanceof CodexCreditAccountingError ? error.message : `Codex dispatch outcome is unknown after an unexpected error: ${safeErrorMessage(error)}`
|
|
9276
|
+
};
|
|
9277
|
+
await writeLedger(args.config.ledgerPath, blockedLedger);
|
|
9278
|
+
await writeLockState(lock, "settled");
|
|
9279
|
+
accountingSettled = true;
|
|
9280
|
+
}
|
|
9281
|
+
throw error;
|
|
9282
|
+
}
|
|
9283
|
+
const credits = calculateCodexCredits(args.model, result.usage);
|
|
9284
|
+
const nextSpent = ledger.spentCredits + credits;
|
|
9285
|
+
const nextLedger = {
|
|
9286
|
+
...ledger,
|
|
9287
|
+
spentCredits: nextSpent,
|
|
9288
|
+
entries: [
|
|
9289
|
+
...ledger.entries,
|
|
9290
|
+
{
|
|
9291
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9292
|
+
model: args.model,
|
|
9293
|
+
credits,
|
|
9294
|
+
...result.usage
|
|
9295
|
+
}
|
|
9296
|
+
]
|
|
9297
|
+
};
|
|
9298
|
+
await writeLedger(args.config.ledgerPath, nextLedger);
|
|
9299
|
+
await writeLockState(lock, "settled");
|
|
9300
|
+
accountingSettled = true;
|
|
9301
|
+
args.onUsagePersisted?.(result.usage);
|
|
9302
|
+
if (nextSpent > args.config.budgetCredits) {
|
|
9303
|
+
throw new Error(
|
|
9304
|
+
`Codex credit budget exceeded by completed call: ${nextSpent.toFixed(3)} > ${args.config.budgetCredits.toFixed(3)} credits. Usage was persisted; stop the benchmark immediately.`
|
|
9305
|
+
);
|
|
9306
|
+
}
|
|
9307
|
+
return result.value;
|
|
9308
|
+
} finally {
|
|
9309
|
+
try {
|
|
9310
|
+
if (lock) {
|
|
9311
|
+
try {
|
|
9312
|
+
await lock.close();
|
|
9313
|
+
} finally {
|
|
9314
|
+
if (!dispatchStarted || accountingSettled) {
|
|
9315
|
+
await removeOwnedLedgerLock(lockPath);
|
|
9316
|
+
}
|
|
9317
|
+
}
|
|
9318
|
+
}
|
|
9319
|
+
} finally {
|
|
9320
|
+
release();
|
|
9321
|
+
}
|
|
9322
|
+
}
|
|
9323
|
+
}
|
|
9324
|
+
async function acquireLedgerLock(lockPath) {
|
|
9325
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
9326
|
+
try {
|
|
9327
|
+
await mkdir5(lockPath, { mode: 448 });
|
|
9328
|
+
} catch (error) {
|
|
9329
|
+
if (error.code !== "EEXIST") throw error;
|
|
9330
|
+
const owner = await readLockOwner(lockPath);
|
|
9331
|
+
if (!owner || isProcessAlive(owner.pid) || owner.phase === "in-flight") {
|
|
9332
|
+
throw new Error(
|
|
9333
|
+
`Codex credit ledger is locked${owner?.phase === "in-flight" ? " with unreconciled in-flight usage" : " by another benchmark process"} (${lockPath}); refusing credit spend.`
|
|
9334
|
+
);
|
|
9335
|
+
}
|
|
9336
|
+
await reclaimStaleLedgerLock(lockPath, owner);
|
|
9337
|
+
continue;
|
|
9338
|
+
}
|
|
9339
|
+
let createdLock;
|
|
9340
|
+
try {
|
|
9341
|
+
await mkdir5(lockHeldPath(lockPath));
|
|
9342
|
+
createdLock = await open(lockOwnerPath(lockPath), "wx", 384);
|
|
9343
|
+
await writeLockState(createdLock, "preflight");
|
|
9344
|
+
return createdLock;
|
|
9345
|
+
} catch (error) {
|
|
9346
|
+
await createdLock?.close().catch(() => void 0);
|
|
9347
|
+
await unlink3(lockOwnerPath(lockPath)).catch(() => void 0);
|
|
9348
|
+
await rmdir(lockHeldPath(lockPath)).catch(() => void 0);
|
|
9349
|
+
await rmdir(lockPath).catch(() => void 0);
|
|
9350
|
+
throw error;
|
|
9351
|
+
}
|
|
9352
|
+
}
|
|
9353
|
+
throw new Error(`Unable to acquire Codex credit ledger lock (${lockPath})`);
|
|
9354
|
+
}
|
|
9355
|
+
async function readLockOwner(lockPath) {
|
|
9356
|
+
try {
|
|
9357
|
+
const parsed = JSON.parse(await readFile6(lockOwnerPath(lockPath), "utf8"));
|
|
9358
|
+
if (!Number.isSafeInteger(parsed.pid) || parsed.pid <= 0 || parsed.phase !== "preflight" && parsed.phase !== "in-flight" && parsed.phase !== "settled") {
|
|
9359
|
+
return void 0;
|
|
9360
|
+
}
|
|
9361
|
+
return { pid: parsed.pid, phase: parsed.phase };
|
|
9362
|
+
} catch {
|
|
9363
|
+
return void 0;
|
|
9364
|
+
}
|
|
9365
|
+
}
|
|
9366
|
+
async function reclaimStaleLedgerLock(lockPath, expectedOwner) {
|
|
9367
|
+
try {
|
|
9368
|
+
await rmdir(lockHeldPath(lockPath));
|
|
9369
|
+
} catch (error) {
|
|
9370
|
+
throw new Error(
|
|
9371
|
+
`Codex credit ledger stale-lock reclamation is already claimed or incomplete (${lockPath}); refusing credit spend: ${safeErrorMessage(error)}`
|
|
9372
|
+
);
|
|
9373
|
+
}
|
|
9374
|
+
const currentOwner = await readLockOwner(lockPath);
|
|
9375
|
+
if (!currentOwner || currentOwner.pid !== expectedOwner.pid || currentOwner.phase !== expectedOwner.phase || isProcessAlive(currentOwner.pid) || currentOwner.phase === "in-flight") {
|
|
9376
|
+
throw new Error(
|
|
9377
|
+
`Codex credit ledger owner changed during stale-lock reclamation (${lockPath}); refusing credit spend.`
|
|
9378
|
+
);
|
|
9379
|
+
}
|
|
9380
|
+
await unlink3(lockOwnerPath(lockPath));
|
|
9381
|
+
await rmdir(lockPath);
|
|
9382
|
+
}
|
|
9383
|
+
async function removeOwnedLedgerLock(lockPath) {
|
|
9384
|
+
await rmdir(lockHeldPath(lockPath));
|
|
9385
|
+
await unlink3(lockOwnerPath(lockPath));
|
|
9386
|
+
await rmdir(lockPath);
|
|
9387
|
+
}
|
|
9388
|
+
function lockOwnerPath(lockPath) {
|
|
9389
|
+
return path7.join(lockPath, "owner.json");
|
|
9390
|
+
}
|
|
9391
|
+
function lockHeldPath(lockPath) {
|
|
9392
|
+
return path7.join(lockPath, "held");
|
|
9393
|
+
}
|
|
9394
|
+
async function writeLockState(lock, phase) {
|
|
9395
|
+
const contents = `${JSON.stringify({
|
|
9396
|
+
pid: process.pid,
|
|
9397
|
+
phase,
|
|
9398
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9399
|
+
})}
|
|
9400
|
+
`;
|
|
9401
|
+
await lock.truncate(0);
|
|
9402
|
+
await lock.write(contents, 0, "utf8");
|
|
9403
|
+
await lock.sync();
|
|
9404
|
+
}
|
|
9405
|
+
function isProcessAlive(pid) {
|
|
9406
|
+
try {
|
|
9407
|
+
process.kill(pid, 0);
|
|
9408
|
+
return true;
|
|
9409
|
+
} catch (error) {
|
|
9410
|
+
return error.code === "EPERM";
|
|
9411
|
+
}
|
|
9412
|
+
}
|
|
9413
|
+
function parseCodexJsonlUsage(output) {
|
|
9414
|
+
let usage;
|
|
9415
|
+
for (const line of output.split(/\r?\n/)) {
|
|
9416
|
+
const trimmed = line.trim();
|
|
9417
|
+
if (!trimmed.startsWith("{")) continue;
|
|
9418
|
+
try {
|
|
9419
|
+
const event = JSON.parse(trimmed);
|
|
9420
|
+
if (event.type !== "turn.completed" || !event.usage) continue;
|
|
9421
|
+
const inputTokens = readCounter(event.usage.input_tokens);
|
|
9422
|
+
const outputTokens = readCounter(event.usage.output_tokens);
|
|
9423
|
+
const cachedInputTokens = readOptionalCounter(
|
|
9424
|
+
event.usage.cached_input_tokens
|
|
9425
|
+
);
|
|
9426
|
+
const reasoningOutputTokens = readOptionalCounter(
|
|
9427
|
+
event.usage.reasoning_output_tokens
|
|
9428
|
+
);
|
|
9429
|
+
if (inputTokens !== void 0 && outputTokens !== void 0 && cachedInputTokens !== void 0 && reasoningOutputTokens !== void 0) {
|
|
9430
|
+
usage = {
|
|
9431
|
+
inputTokens,
|
|
9432
|
+
cachedInputTokens,
|
|
9433
|
+
outputTokens,
|
|
9434
|
+
reasoningOutputTokens
|
|
9435
|
+
};
|
|
9436
|
+
}
|
|
9437
|
+
} catch {
|
|
9438
|
+
}
|
|
9439
|
+
}
|
|
9440
|
+
return usage;
|
|
9441
|
+
}
|
|
9442
|
+
function calculateCodexCredits(model, usage) {
|
|
9443
|
+
const rate = resolveRate(model);
|
|
9444
|
+
const cached = Math.min(usage.inputTokens, usage.cachedInputTokens);
|
|
9445
|
+
const uncached = usage.inputTokens - cached;
|
|
9446
|
+
return (uncached * rate.input + cached * rate.cachedInput + usage.outputTokens * rate.output) / ONE_MILLION;
|
|
9447
|
+
}
|
|
9448
|
+
function resolveRate(model) {
|
|
9449
|
+
const match = CREDIT_RATES.find(([pattern]) => pattern.test(model));
|
|
9450
|
+
if (!match) {
|
|
9451
|
+
throw new Error(
|
|
9452
|
+
`No Codex credit rate is configured for model ${JSON.stringify(model)}; refusing to run under a bounded credit budget.`
|
|
9453
|
+
);
|
|
9454
|
+
}
|
|
9455
|
+
return match[1];
|
|
9456
|
+
}
|
|
9457
|
+
function assertModelAllowed(model, config) {
|
|
9458
|
+
resolveRate(model);
|
|
9459
|
+
if (SOL_MODEL.test(model) && !config.allowSol) {
|
|
9460
|
+
throw new Error(
|
|
9461
|
+
"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."
|
|
9462
|
+
);
|
|
9463
|
+
}
|
|
9464
|
+
}
|
|
9465
|
+
async function readLedger(config) {
|
|
9466
|
+
try {
|
|
9467
|
+
const parsed = JSON.parse(await readFile6(config.ledgerPath, "utf8"));
|
|
9468
|
+
if (parsed.schemaVersion !== 1 || parsed.budgetCredits !== config.budgetCredits || parsed.reserveCredits !== config.reserveCredits || typeof parsed.spentCredits !== "number" || !Number.isFinite(parsed.spentCredits) || parsed.spentCredits < 0 || !Array.isArray(parsed.entries)) {
|
|
9469
|
+
throw new Error("ledger schema or budget does not match this run");
|
|
9470
|
+
}
|
|
9471
|
+
return parsed;
|
|
9472
|
+
} catch (error) {
|
|
9473
|
+
if (error.code !== "ENOENT") {
|
|
9474
|
+
throw new Error(`Invalid Codex credit ledger at ${config.ledgerPath}: ${String(error)}`);
|
|
9475
|
+
}
|
|
9476
|
+
return {
|
|
9477
|
+
schemaVersion: 1,
|
|
9478
|
+
budgetCredits: config.budgetCredits,
|
|
9479
|
+
reserveCredits: config.reserveCredits,
|
|
9480
|
+
spentCredits: 0,
|
|
9481
|
+
entries: []
|
|
9482
|
+
};
|
|
9483
|
+
}
|
|
9484
|
+
}
|
|
9485
|
+
async function writeLedger(filePath, ledger) {
|
|
9486
|
+
await mkdir5(path7.dirname(filePath), { recursive: true, mode: 448 });
|
|
9487
|
+
const tempPath = `${filePath}.${process.pid}.tmp`;
|
|
9488
|
+
await writeFile5(tempPath, `${JSON.stringify(ledger, null, 2)}
|
|
9489
|
+
`, {
|
|
9490
|
+
encoding: "utf8",
|
|
9491
|
+
mode: 384
|
|
9492
|
+
});
|
|
9493
|
+
await rename2(tempPath, filePath);
|
|
9494
|
+
}
|
|
9495
|
+
function readCounter(value) {
|
|
9496
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
9497
|
+
}
|
|
9498
|
+
function readOptionalCounter(value) {
|
|
9499
|
+
return value === void 0 ? 0 : readCounter(value);
|
|
9500
|
+
}
|
|
9501
|
+
function safeErrorMessage(error) {
|
|
9502
|
+
return error instanceof Error ? error.message : String(error);
|
|
9503
|
+
}
|
|
9504
|
+
function expandHomeRelativePath2(value) {
|
|
9505
|
+
if (value === "~") return os4.homedir();
|
|
9506
|
+
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
9507
|
+
return path7.join(os4.homedir(), value.slice(2));
|
|
9508
|
+
}
|
|
9509
|
+
return value;
|
|
9510
|
+
}
|
|
9511
|
+
function parsePositiveNumber(value, name) {
|
|
9512
|
+
const parsed = Number(value);
|
|
9513
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
9514
|
+
throw new Error(`${name} must be a finite number greater than zero`);
|
|
9515
|
+
}
|
|
9516
|
+
return parsed;
|
|
9517
|
+
}
|
|
9518
|
+
function parseNonNegativeNumber(value, name) {
|
|
9519
|
+
const parsed = Number(value);
|
|
9520
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
9521
|
+
throw new Error(`${name} must be a finite non-negative number`);
|
|
9522
|
+
}
|
|
9523
|
+
return parsed;
|
|
9524
|
+
}
|
|
9525
|
+
|
|
9526
|
+
// src/providers/codex-cli.ts
|
|
8978
9527
|
var DEFAULT_REASONING_EFFORT = "xhigh";
|
|
8979
|
-
var DEFAULT_SERVICE_TIER = "
|
|
9528
|
+
var DEFAULT_SERVICE_TIER = "default";
|
|
8980
9529
|
var CODEX_CLI_STDIO_LIMIT = 64e3;
|
|
8981
9530
|
var CODEX_CLI_PARENT_SIGNALS = [
|
|
8982
9531
|
"SIGHUP",
|
|
@@ -8987,12 +9536,8 @@ var CODEX_CLI_FORCED_PARENT_EXIT_MS = 1e3;
|
|
|
8987
9536
|
var CODEX_CLI_DIAGNOSTICS_DIR_ENV = "REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_DIR";
|
|
8988
9537
|
var CODEX_CLI_DIAGNOSTICS_MODE_ENV = "REMNIC_BENCH_CODEX_CLI_DIAGNOSTICS_MODE";
|
|
8989
9538
|
var CODEX_CLI_EXECUTABLE_ENV = "REMNIC_BENCH_CODEX_CLI_EXECUTABLE";
|
|
8990
|
-
var CODEX_CLI_TRANSPORT_ENV = "REMNIC_BENCH_CODEX_CLI_TRANSPORT";
|
|
8991
9539
|
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";
|
|
9540
|
+
var CODEX_CLI_PRE_START_ABORT_MESSAGE = "Codex CLI aborted before start.";
|
|
8996
9541
|
var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
8997
9542
|
"ALL_PROXY",
|
|
8998
9543
|
"APPDATA",
|
|
@@ -9010,9 +9555,6 @@ var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
|
9010
9555
|
"NODE_EXTRA_CA_CERTS",
|
|
9011
9556
|
"NO_PROXY",
|
|
9012
9557
|
"NUMBER_OF_PROCESSORS",
|
|
9013
|
-
OPENAI_BASE_URL_ENV,
|
|
9014
|
-
"OPENAI_ORGANIZATION",
|
|
9015
|
-
"OPENAI_PROJECT",
|
|
9016
9558
|
"OS",
|
|
9017
9559
|
"PATH",
|
|
9018
9560
|
"PATHEXT",
|
|
@@ -9040,7 +9582,7 @@ var CODEX_CLI_RUNTIME_ENV_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
|
9040
9582
|
]);
|
|
9041
9583
|
var activeCodexCliChildPids = /* @__PURE__ */ new Set();
|
|
9042
9584
|
var codexCliParentCleanupInstalled = false;
|
|
9043
|
-
var
|
|
9585
|
+
var codexCliLoginStatusCache = /* @__PURE__ */ new Map();
|
|
9044
9586
|
var CodexCliProvider = class {
|
|
9045
9587
|
provider = "codex-cli";
|
|
9046
9588
|
id;
|
|
@@ -9048,7 +9590,8 @@ var CodexCliProvider = class {
|
|
|
9048
9590
|
config;
|
|
9049
9591
|
runCodexCli;
|
|
9050
9592
|
runCodexVersion;
|
|
9051
|
-
|
|
9593
|
+
runCodexLoginStatus;
|
|
9594
|
+
requiresExactUsage;
|
|
9052
9595
|
usage = {
|
|
9053
9596
|
inputTokens: 0,
|
|
9054
9597
|
outputTokens: 0,
|
|
@@ -9058,23 +9601,28 @@ var CodexCliProvider = class {
|
|
|
9058
9601
|
this.config = config;
|
|
9059
9602
|
this.runCodexCli = deps.runCodexCli ?? runCodexCliCommand;
|
|
9060
9603
|
this.runCodexVersion = deps.runCodexVersion ?? runCodexVersionCommand;
|
|
9061
|
-
this.
|
|
9604
|
+
this.runCodexLoginStatus = deps.runCodexLoginStatus ?? runCodexLoginStatusCommand;
|
|
9605
|
+
this.requiresExactUsage = deps.runCodexCli === void 0;
|
|
9062
9606
|
this.id = `codex-cli:${config.model}`;
|
|
9063
9607
|
this.name = config.model;
|
|
9064
9608
|
}
|
|
9065
9609
|
async complete(prompt, opts = {}) {
|
|
9610
|
+
if (opts.signal?.aborted) {
|
|
9611
|
+
throw codexCliAbortError(opts.signal);
|
|
9612
|
+
}
|
|
9066
9613
|
const startedAt = performance.now();
|
|
9067
|
-
|
|
9068
|
-
|
|
9614
|
+
const creditBudget = resolveCodexCreditBudgetConfig();
|
|
9615
|
+
if (creditBudget) {
|
|
9616
|
+
await this.assertChatGptCreditAuth();
|
|
9069
9617
|
}
|
|
9070
9618
|
const maxAttempts = normalizeCodexCliMaxAttempts(
|
|
9071
|
-
this.config.retryOptions?.maxAttempts
|
|
9619
|
+
creditBudget ? 1 : this.config.retryOptions?.maxAttempts
|
|
9072
9620
|
);
|
|
9073
9621
|
let lastError;
|
|
9074
9622
|
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
9075
|
-
const tempDir = await mkdtemp3(
|
|
9076
|
-
const workspacePath =
|
|
9077
|
-
const outputPath =
|
|
9623
|
+
const tempDir = await mkdtemp3(path8.join(os5.tmpdir(), "remnic-codex-cli-"));
|
|
9624
|
+
const workspacePath = path8.join(tempDir, "workspace");
|
|
9625
|
+
const outputPath = path8.join(tempDir, "last-message.txt");
|
|
9078
9626
|
let diagnostics;
|
|
9079
9627
|
let diagnosticsFinished = false;
|
|
9080
9628
|
const finishDiagnostics = async (outcome) => {
|
|
@@ -9085,7 +9633,7 @@ var CodexCliProvider = class {
|
|
|
9085
9633
|
await finishCodexCliDiagnostics(diagnostics, startedAt, outcome);
|
|
9086
9634
|
};
|
|
9087
9635
|
try {
|
|
9088
|
-
await
|
|
9636
|
+
await mkdir6(workspacePath, { recursive: true });
|
|
9089
9637
|
const request = this.buildRunRequest(prompt, opts, workspacePath, outputPath);
|
|
9090
9638
|
diagnostics = await startCodexCliDiagnostics({
|
|
9091
9639
|
config: this.config,
|
|
@@ -9094,12 +9642,48 @@ var CodexCliProvider = class {
|
|
|
9094
9642
|
serviceTier: DEFAULT_SERVICE_TIER,
|
|
9095
9643
|
retry: { attempt, maxAttempts }
|
|
9096
9644
|
});
|
|
9097
|
-
const result = await
|
|
9645
|
+
const result = creditBudget ? await runWithinCodexCreditBudget({
|
|
9646
|
+
config: creditBudget,
|
|
9647
|
+
model: this.config.model,
|
|
9648
|
+
onUsagePersisted: (usage) => {
|
|
9649
|
+
this.recordUsage(usage.inputTokens, usage.outputTokens);
|
|
9650
|
+
},
|
|
9651
|
+
run: async () => {
|
|
9652
|
+
if (opts.signal?.aborted) {
|
|
9653
|
+
throw codexCliPreStartAbortError(opts.signal);
|
|
9654
|
+
}
|
|
9655
|
+
let value;
|
|
9656
|
+
try {
|
|
9657
|
+
value = await this.runCodexCli(request);
|
|
9658
|
+
} catch (error) {
|
|
9659
|
+
if (error instanceof CodexCreditDispatchError || error instanceof CodexCreditAccountingError) {
|
|
9660
|
+
throw error;
|
|
9661
|
+
}
|
|
9662
|
+
throw new CodexCreditAccountingError(
|
|
9663
|
+
`Codex CLI failed after dispatch; account balance must be reconciled before resuming: ${safeErrorMessage2(error)}`
|
|
9664
|
+
);
|
|
9665
|
+
}
|
|
9666
|
+
const usage = parseCodexJsonlUsage(
|
|
9667
|
+
`${value.stdout}
|
|
9668
|
+
${value.stderr}`
|
|
9669
|
+
);
|
|
9670
|
+
if (!usage) {
|
|
9671
|
+
throw new CodexCreditAccountingError(
|
|
9672
|
+
`Codex CLI exited ${value.status ?? "without a status"} without exact turn.completed usage; account balance must be reconciled before resuming.`
|
|
9673
|
+
);
|
|
9674
|
+
}
|
|
9675
|
+
return { value, usage };
|
|
9676
|
+
}
|
|
9677
|
+
}) : await this.runCodexCli(request);
|
|
9678
|
+
const exactUsage = parseCodexJsonlUsage(
|
|
9679
|
+
`${result.stdout}
|
|
9680
|
+
${result.stderr}`
|
|
9681
|
+
);
|
|
9682
|
+
if (!creditBudget && exactUsage) {
|
|
9683
|
+
this.recordUsage(exactUsage.inputTokens, exactUsage.outputTokens);
|
|
9684
|
+
}
|
|
9098
9685
|
if (result.status !== 0) {
|
|
9099
|
-
const
|
|
9100
|
-
const error = new Error(
|
|
9101
|
-
`Codex CLI completion failed (${exitLabel}): ${summarizeProcessOutput2(result.stderr, result.stdout)}`
|
|
9102
|
-
);
|
|
9686
|
+
const error = codexCliResultError(result);
|
|
9103
9687
|
if (attempt < maxAttempts && isRetryableCodexCliResult(result)) {
|
|
9104
9688
|
lastError = error;
|
|
9105
9689
|
await finishDiagnostics({
|
|
@@ -9126,12 +9710,14 @@ var CodexCliProvider = class {
|
|
|
9126
9710
|
throw error;
|
|
9127
9711
|
}
|
|
9128
9712
|
await finishDiagnostics({ result });
|
|
9129
|
-
const
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9713
|
+
const nativeUsage = exactUsage ?? (this.requiresExactUsage ? requireCodexJsonlUsage(result) : readCodexUsage(result, text));
|
|
9714
|
+
const tokens = {
|
|
9715
|
+
input: nativeUsage.inputTokens,
|
|
9716
|
+
output: nativeUsage.outputTokens
|
|
9717
|
+
};
|
|
9718
|
+
if (!creditBudget && !exactUsage) {
|
|
9719
|
+
this.recordUsage(tokens.input, tokens.output);
|
|
9720
|
+
}
|
|
9135
9721
|
return {
|
|
9136
9722
|
text,
|
|
9137
9723
|
tokens,
|
|
@@ -9139,15 +9725,93 @@ ${result.stdout}`,
|
|
|
9139
9725
|
model: this.config.model
|
|
9140
9726
|
};
|
|
9141
9727
|
} catch (error) {
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
9728
|
+
const surfacedError = unwrapCodexCliPreStartAbort(error);
|
|
9729
|
+
lastError = surfacedError;
|
|
9730
|
+
await finishDiagnostics({ error: surfacedError });
|
|
9731
|
+
throw surfacedError;
|
|
9145
9732
|
} finally {
|
|
9146
9733
|
await rm3(tempDir, { force: true, recursive: true });
|
|
9147
9734
|
}
|
|
9148
9735
|
}
|
|
9149
9736
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
9150
9737
|
}
|
|
9738
|
+
async judge(request) {
|
|
9739
|
+
const startedAt = performance.now();
|
|
9740
|
+
try {
|
|
9741
|
+
const completion = await this.complete(request.input, {
|
|
9742
|
+
systemPrompt: buildCodexStructuredJudgePrompt(request.rubric),
|
|
9743
|
+
temperature: 0,
|
|
9744
|
+
maxTokens: request.maxTokens ?? 256,
|
|
9745
|
+
signal: request.signal
|
|
9746
|
+
});
|
|
9747
|
+
const telemetry = {
|
|
9748
|
+
model: completion.model,
|
|
9749
|
+
rubricVersion: request.rubricVersion,
|
|
9750
|
+
inputTokens: completion.tokens.input,
|
|
9751
|
+
outputTokens: completion.tokens.output,
|
|
9752
|
+
latencyMs: completion.latencyMs
|
|
9753
|
+
};
|
|
9754
|
+
const verdict = parseStructuredJudgeVerdict(completion.text);
|
|
9755
|
+
if (!verdict) {
|
|
9756
|
+
return {
|
|
9757
|
+
ok: false,
|
|
9758
|
+
error: {
|
|
9759
|
+
code: "malformed_verdict",
|
|
9760
|
+
message: "Codex CLI returned a verdict that failed schema validation.",
|
|
9761
|
+
retryable: false
|
|
9762
|
+
},
|
|
9763
|
+
telemetry: { ...telemetry, errorCode: "malformed_verdict" }
|
|
9764
|
+
};
|
|
9765
|
+
}
|
|
9766
|
+
return { ok: true, verdict, telemetry };
|
|
9767
|
+
} catch (error) {
|
|
9768
|
+
const aborted = isCodexStructuredJudgeAbort(error, request.signal);
|
|
9769
|
+
const errorCode = aborted ? "aborted" : "transport_error";
|
|
9770
|
+
return {
|
|
9771
|
+
ok: false,
|
|
9772
|
+
error: {
|
|
9773
|
+
code: errorCode,
|
|
9774
|
+
message: aborted ? "Codex CLI judging was aborted by the caller." : `Codex CLI judging failed (${structuredJudgeErrorName(error)}).`,
|
|
9775
|
+
retryable: false
|
|
9776
|
+
},
|
|
9777
|
+
telemetry: {
|
|
9778
|
+
model: this.config.model,
|
|
9779
|
+
rubricVersion: request.rubricVersion,
|
|
9780
|
+
inputTokens: 0,
|
|
9781
|
+
outputTokens: 0,
|
|
9782
|
+
latencyMs: Math.round(performance.now() - startedAt),
|
|
9783
|
+
errorCode
|
|
9784
|
+
}
|
|
9785
|
+
};
|
|
9786
|
+
}
|
|
9787
|
+
}
|
|
9788
|
+
async evaluateAssistantRubric(request) {
|
|
9789
|
+
const rubricVersion = `sealed:${request.rubricId}`;
|
|
9790
|
+
const completion = await this.complete(request.user, {
|
|
9791
|
+
systemPrompt: buildCodexAssistantRubricPrompt(request.system),
|
|
9792
|
+
temperature: 0,
|
|
9793
|
+
maxTokens: 512
|
|
9794
|
+
});
|
|
9795
|
+
if (isValidAssistantRubric(completion.text)) {
|
|
9796
|
+
return completion.text;
|
|
9797
|
+
}
|
|
9798
|
+
throw new StructuredJudgeError({
|
|
9799
|
+
ok: false,
|
|
9800
|
+
error: {
|
|
9801
|
+
code: "malformed_verdict",
|
|
9802
|
+
message: "Codex CLI returned an invalid sealed assistant-rubric verdict.",
|
|
9803
|
+
retryable: false
|
|
9804
|
+
},
|
|
9805
|
+
telemetry: {
|
|
9806
|
+
model: completion.model,
|
|
9807
|
+
rubricVersion,
|
|
9808
|
+
inputTokens: completion.tokens.input,
|
|
9809
|
+
outputTokens: completion.tokens.output,
|
|
9810
|
+
latencyMs: completion.latencyMs,
|
|
9811
|
+
errorCode: "malformed_verdict"
|
|
9812
|
+
}
|
|
9813
|
+
});
|
|
9814
|
+
}
|
|
9151
9815
|
async discover() {
|
|
9152
9816
|
const version = await this.runCodexVersion(
|
|
9153
9817
|
resolveCodexCliExecutable(this.config),
|
|
@@ -9177,6 +9841,26 @@ ${result.stdout}`,
|
|
|
9177
9841
|
totalTokens: 0
|
|
9178
9842
|
};
|
|
9179
9843
|
}
|
|
9844
|
+
async assertChatGptCreditAuth() {
|
|
9845
|
+
const executable = resolveCodexCliExecutable(this.config);
|
|
9846
|
+
const env = buildIsolatedCodexEnv();
|
|
9847
|
+
const cacheKey = `${executable}\0${env.CODEX_HOME ?? env.HOME ?? ""}`;
|
|
9848
|
+
let check = codexCliLoginStatusCache.get(cacheKey);
|
|
9849
|
+
if (!check) {
|
|
9850
|
+
check = this.runCodexLoginStatus(executable, env).then((result) => {
|
|
9851
|
+
const output = `${result.stdout}
|
|
9852
|
+
${result.stderr}`.trim();
|
|
9853
|
+
if (result.status !== 0 || !/logged in using chatgpt/i.test(output)) {
|
|
9854
|
+
throw new Error(
|
|
9855
|
+
`Bounded Codex credit runs require ChatGPT-backed Codex CLI authentication; \`codex login status\` reported: ${output || `exit ${result.status ?? "unknown"}`}`
|
|
9856
|
+
);
|
|
9857
|
+
}
|
|
9858
|
+
});
|
|
9859
|
+
codexCliLoginStatusCache.set(cacheKey, check);
|
|
9860
|
+
check.catch(() => codexCliLoginStatusCache.delete(cacheKey));
|
|
9861
|
+
}
|
|
9862
|
+
await check;
|
|
9863
|
+
}
|
|
9180
9864
|
recordUsage(inputTokens, outputTokens) {
|
|
9181
9865
|
this.usage = {
|
|
9182
9866
|
inputTokens: this.usage.inputTokens + inputTokens,
|
|
@@ -9184,126 +9868,57 @@ ${result.stdout}`,
|
|
|
9184
9868
|
totalTokens: this.usage.totalTokens + inputTokens + outputTokens
|
|
9185
9869
|
};
|
|
9186
9870
|
}
|
|
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
9871
|
buildRunRequest(prompt, opts, workspacePath, outputPath) {
|
|
9294
9872
|
const reasoningEffort = this.config.reasoningEffort ?? DEFAULT_REASONING_EFFORT;
|
|
9295
9873
|
const args = [
|
|
9296
9874
|
"exec",
|
|
9875
|
+
"--strict-config",
|
|
9297
9876
|
"--model",
|
|
9298
9877
|
this.config.model,
|
|
9299
9878
|
"--config",
|
|
9300
9879
|
`model_reasoning_effort=${tomlString(reasoningEffort)}`,
|
|
9301
9880
|
"--config",
|
|
9302
|
-
`service_tier=${tomlString(DEFAULT_SERVICE_TIER)}`,
|
|
9303
|
-
"--config",
|
|
9304
9881
|
'approval_policy="never"',
|
|
9882
|
+
"--config",
|
|
9883
|
+
'web_search="disabled"',
|
|
9884
|
+
"--disable",
|
|
9885
|
+
"hooks",
|
|
9886
|
+
"--disable",
|
|
9887
|
+
"shell_tool",
|
|
9888
|
+
"--disable",
|
|
9889
|
+
"unified_exec",
|
|
9890
|
+
"--disable",
|
|
9891
|
+
"apps",
|
|
9892
|
+
"--disable",
|
|
9893
|
+
"plugins",
|
|
9894
|
+
"--disable",
|
|
9895
|
+
"remote_plugin",
|
|
9305
9896
|
"--disable",
|
|
9306
|
-
"
|
|
9897
|
+
"multi_agent",
|
|
9898
|
+
"--disable",
|
|
9899
|
+
"browser_use",
|
|
9900
|
+
"--disable",
|
|
9901
|
+
"browser_use_external",
|
|
9902
|
+
"--disable",
|
|
9903
|
+
"browser_use_full_cdp_access",
|
|
9904
|
+
"--disable",
|
|
9905
|
+
"computer_use",
|
|
9906
|
+
"--disable",
|
|
9907
|
+
"image_generation",
|
|
9908
|
+
"--disable",
|
|
9909
|
+
"in_app_browser",
|
|
9910
|
+
"--disable",
|
|
9911
|
+
"goals",
|
|
9912
|
+
"--disable",
|
|
9913
|
+
"memories",
|
|
9914
|
+
"--disable",
|
|
9915
|
+
"chronicle",
|
|
9916
|
+
"--disable",
|
|
9917
|
+
"tool_suggest",
|
|
9918
|
+
"--disable",
|
|
9919
|
+
"workspace_dependencies",
|
|
9920
|
+
"--disable",
|
|
9921
|
+
"shell_snapshot",
|
|
9307
9922
|
"--ephemeral",
|
|
9308
9923
|
"--ignore-user-config",
|
|
9309
9924
|
"--ignore-rules",
|
|
@@ -9312,6 +9927,7 @@ ${result.stdout}`,
|
|
|
9312
9927
|
"--cd",
|
|
9313
9928
|
workspacePath,
|
|
9314
9929
|
"--skip-git-repo-check",
|
|
9930
|
+
"--json",
|
|
9315
9931
|
"--output-last-message",
|
|
9316
9932
|
outputPath,
|
|
9317
9933
|
"-"
|
|
@@ -9324,50 +9940,10 @@ ${result.stdout}`,
|
|
|
9324
9940
|
workspacePath,
|
|
9325
9941
|
timeoutMs: this.config.retryOptions?.timeoutMs,
|
|
9326
9942
|
signal: opts.signal,
|
|
9327
|
-
env: buildIsolatedCodexEnv(
|
|
9943
|
+
env: buildIsolatedCodexEnv()
|
|
9328
9944
|
};
|
|
9329
9945
|
}
|
|
9330
9946
|
};
|
|
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
9947
|
function runCodexVersionCommand(executable, env) {
|
|
9372
9948
|
return new Promise((resolve, reject) => {
|
|
9373
9949
|
const child = spawn2(executable, ["--version"], {
|
|
@@ -9425,6 +10001,58 @@ Codex CLI --version timed out after ${CODEX_CLI_VERSION_TIMEOUT_MS}ms.`
|
|
|
9425
10001
|
});
|
|
9426
10002
|
});
|
|
9427
10003
|
}
|
|
10004
|
+
function runCodexLoginStatusCommand(executable, env) {
|
|
10005
|
+
return new Promise((resolve, reject) => {
|
|
10006
|
+
const child = spawn2(executable, ["login", "status"], {
|
|
10007
|
+
env,
|
|
10008
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
10009
|
+
detached: process.platform !== "win32",
|
|
10010
|
+
windowsHide: true
|
|
10011
|
+
});
|
|
10012
|
+
let stdout = "";
|
|
10013
|
+
let stderr = "";
|
|
10014
|
+
let killTimeout;
|
|
10015
|
+
const terminate = (signal) => {
|
|
10016
|
+
if (child.pid && process.platform !== "win32") {
|
|
10017
|
+
try {
|
|
10018
|
+
process.kill(-child.pid, signal);
|
|
10019
|
+
return;
|
|
10020
|
+
} catch {
|
|
10021
|
+
}
|
|
10022
|
+
}
|
|
10023
|
+
child.kill(signal);
|
|
10024
|
+
};
|
|
10025
|
+
const timeout = setTimeout(() => {
|
|
10026
|
+
stderr = appendBounded2(
|
|
10027
|
+
stderr,
|
|
10028
|
+
`
|
|
10029
|
+
Codex CLI login status timed out after ${CODEX_CLI_VERSION_TIMEOUT_MS}ms.`
|
|
10030
|
+
);
|
|
10031
|
+
terminate("SIGTERM");
|
|
10032
|
+
killTimeout = setTimeout(() => terminate("SIGKILL"), 1e3);
|
|
10033
|
+
killTimeout.unref();
|
|
10034
|
+
}, CODEX_CLI_VERSION_TIMEOUT_MS);
|
|
10035
|
+
timeout.unref();
|
|
10036
|
+
child.stdout?.setEncoding("utf8");
|
|
10037
|
+
child.stderr?.setEncoding("utf8");
|
|
10038
|
+
child.stdout?.on("data", (chunk) => {
|
|
10039
|
+
stdout = appendBounded2(stdout, chunk);
|
|
10040
|
+
});
|
|
10041
|
+
child.stderr?.on("data", (chunk) => {
|
|
10042
|
+
stderr = appendBounded2(stderr, chunk);
|
|
10043
|
+
});
|
|
10044
|
+
child.on("error", (error) => {
|
|
10045
|
+
clearTimeout(timeout);
|
|
10046
|
+
if (killTimeout) clearTimeout(killTimeout);
|
|
10047
|
+
reject(error);
|
|
10048
|
+
});
|
|
10049
|
+
child.on("close", (status) => {
|
|
10050
|
+
clearTimeout(timeout);
|
|
10051
|
+
if (killTimeout) clearTimeout(killTimeout);
|
|
10052
|
+
resolve({ status, stdout, stderr });
|
|
10053
|
+
});
|
|
10054
|
+
});
|
|
10055
|
+
}
|
|
9428
10056
|
function resolveCodexCliExecutable(config) {
|
|
9429
10057
|
const configured = config.executable ?? process.env[CODEX_CLI_EXECUTABLE_ENV];
|
|
9430
10058
|
if (configured === void 0) {
|
|
@@ -9436,7 +10064,7 @@ function resolveCodexCliExecutable(config) {
|
|
|
9436
10064
|
`${CODEX_CLI_EXECUTABLE_ENV} / codex-cli executable must not be empty`
|
|
9437
10065
|
);
|
|
9438
10066
|
}
|
|
9439
|
-
return
|
|
10067
|
+
return expandHomeRelativePath3(trimmed);
|
|
9440
10068
|
}
|
|
9441
10069
|
function buildCodexCompletionPrompt(userPrompt, systemPrompt) {
|
|
9442
10070
|
const payload = {
|
|
@@ -9454,21 +10082,13 @@ function buildCodexCompletionPrompt(userPrompt, systemPrompt) {
|
|
|
9454
10082
|
JSON.stringify(payload, null, 2)
|
|
9455
10083
|
].join("\n");
|
|
9456
10084
|
}
|
|
9457
|
-
function buildIsolatedCodexEnv(
|
|
10085
|
+
function buildIsolatedCodexEnv() {
|
|
9458
10086
|
const env = {};
|
|
9459
10087
|
for (const [key, value] of Object.entries(process.env)) {
|
|
9460
10088
|
if (value !== void 0 && isAllowedCodexRuntimeEnvKey(key)) {
|
|
9461
10089
|
env[key] = value;
|
|
9462
10090
|
}
|
|
9463
10091
|
}
|
|
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
10092
|
return env;
|
|
9473
10093
|
}
|
|
9474
10094
|
function isAllowedCodexRuntimeEnvKey(key) {
|
|
@@ -9481,7 +10101,7 @@ async function startCodexCliDiagnostics(args) {
|
|
|
9481
10101
|
return void 0;
|
|
9482
10102
|
}
|
|
9483
10103
|
try {
|
|
9484
|
-
await
|
|
10104
|
+
await mkdir6(diagnosticsDir, { recursive: true, mode: 448 });
|
|
9485
10105
|
const id = `${Date.now()}-${process.pid}-${randomUUID()}`;
|
|
9486
10106
|
const promptStats = inspectCodexCompletionPrompt(args.request.input);
|
|
9487
10107
|
const mode = resolveCodexCliDiagnosticsMode(args.config);
|
|
@@ -9494,10 +10114,10 @@ async function startCodexCliDiagnostics(args) {
|
|
|
9494
10114
|
model: args.config.model,
|
|
9495
10115
|
reasoningEffort: args.reasoningEffort,
|
|
9496
10116
|
serviceTier: args.serviceTier,
|
|
9497
|
-
executable:
|
|
10117
|
+
executable: path8.basename(args.request.executable),
|
|
9498
10118
|
...args.request.timeoutMs ? { timeoutMs: args.request.timeoutMs } : {},
|
|
9499
|
-
workspaceBasename:
|
|
9500
|
-
outputBasename:
|
|
10119
|
+
workspaceBasename: path8.basename(args.request.workspacePath),
|
|
10120
|
+
outputBasename: path8.basename(args.request.outputPath),
|
|
9501
10121
|
prompt: promptStats,
|
|
9502
10122
|
command: {
|
|
9503
10123
|
args: redactCodexCliArgs(args.request.args)
|
|
@@ -9505,7 +10125,7 @@ async function startCodexCliDiagnostics(args) {
|
|
|
9505
10125
|
retry: args.retry,
|
|
9506
10126
|
...mode === "full" ? { fullPrompt: args.request.input } : {}
|
|
9507
10127
|
};
|
|
9508
|
-
const filePath =
|
|
10128
|
+
const filePath = path8.join(diagnosticsDir, `${id}.json`);
|
|
9509
10129
|
await writeCodexCliDiagnosticRecord(filePath, record);
|
|
9510
10130
|
return { path: filePath, record };
|
|
9511
10131
|
} catch {
|
|
@@ -9548,7 +10168,7 @@ async function finishCodexCliDiagnostics(handle, startedAt, outcome) {
|
|
|
9548
10168
|
}
|
|
9549
10169
|
}
|
|
9550
10170
|
async function writeCodexCliDiagnosticRecord(filePath, record) {
|
|
9551
|
-
await
|
|
10171
|
+
await writeFile6(filePath, `${JSON.stringify(record, null, 2)}
|
|
9552
10172
|
`, {
|
|
9553
10173
|
encoding: "utf8",
|
|
9554
10174
|
mode: 384
|
|
@@ -9557,14 +10177,14 @@ async function writeCodexCliDiagnosticRecord(filePath, record) {
|
|
|
9557
10177
|
function resolveCodexCliDiagnosticsDir(config) {
|
|
9558
10178
|
const dir = config.diagnosticsDir ?? process.env[CODEX_CLI_DIAGNOSTICS_DIR_ENV];
|
|
9559
10179
|
const trimmed = typeof dir === "string" ? dir.trim() : "";
|
|
9560
|
-
return trimmed.length > 0 ?
|
|
10180
|
+
return trimmed.length > 0 ? path8.resolve(expandHomeRelativePath3(trimmed)) : void 0;
|
|
9561
10181
|
}
|
|
9562
|
-
function
|
|
10182
|
+
function expandHomeRelativePath3(value) {
|
|
9563
10183
|
if (value === "~") {
|
|
9564
|
-
return
|
|
10184
|
+
return os5.homedir();
|
|
9565
10185
|
}
|
|
9566
10186
|
if (value.startsWith("~/") || value.startsWith("~\\")) {
|
|
9567
|
-
return
|
|
10187
|
+
return path8.join(os5.homedir(), value.slice(2));
|
|
9568
10188
|
}
|
|
9569
10189
|
return value;
|
|
9570
10190
|
}
|
|
@@ -9614,13 +10234,7 @@ function redactCodexCliArgs(args) {
|
|
|
9614
10234
|
function runCodexCliCommand(request) {
|
|
9615
10235
|
return new Promise((resolve, reject) => {
|
|
9616
10236
|
if (request.signal?.aborted) {
|
|
9617
|
-
|
|
9618
|
-
status: 124,
|
|
9619
|
-
signal: null,
|
|
9620
|
-
stdout: "",
|
|
9621
|
-
stderr: "Codex CLI aborted before start.",
|
|
9622
|
-
outputText: ""
|
|
9623
|
-
});
|
|
10237
|
+
reject(codexCliPreStartAbortError(request.signal));
|
|
9624
10238
|
return;
|
|
9625
10239
|
}
|
|
9626
10240
|
const child = spawn2(request.executable, request.args, {
|
|
@@ -9704,7 +10318,15 @@ Codex CLI stdin error: ${error.code ?? error.message}`
|
|
|
9704
10318
|
unregisterActiveCodexCliChild(child.pid);
|
|
9705
10319
|
}
|
|
9706
10320
|
request.signal?.removeEventListener("abort", onAbort);
|
|
9707
|
-
reject(
|
|
10321
|
+
reject(
|
|
10322
|
+
child.pid ? new Error(
|
|
10323
|
+
`Codex CLI failed after its process started: ${safeErrorMessage2(error)}`,
|
|
10324
|
+
{ cause: error }
|
|
10325
|
+
) : new CodexCreditDispatchError(
|
|
10326
|
+
`Codex CLI could not start: ${safeErrorMessage2(error)}`,
|
|
10327
|
+
{ cause: error }
|
|
10328
|
+
)
|
|
10329
|
+
);
|
|
9708
10330
|
});
|
|
9709
10331
|
child.on("close", async (status, signal) => {
|
|
9710
10332
|
if (timeout) {
|
|
@@ -9740,10 +10362,17 @@ Codex CLI timed out after ${request.timeoutMs}ms.`
|
|
|
9740
10362
|
return;
|
|
9741
10363
|
}
|
|
9742
10364
|
try {
|
|
9743
|
-
const outputText = await readCodexOutput(request.outputPath,
|
|
10365
|
+
const outputText = await readCodexOutput(request.outputPath, status);
|
|
9744
10366
|
resolve({ status, signal, stdout, stderr, outputText });
|
|
9745
10367
|
} catch (error) {
|
|
9746
|
-
|
|
10368
|
+
resolve({
|
|
10369
|
+
status,
|
|
10370
|
+
signal,
|
|
10371
|
+
stdout,
|
|
10372
|
+
stderr: appendBounded2(stderr, `
|
|
10373
|
+
${safeErrorMessage2(error)}`),
|
|
10374
|
+
outputText: ""
|
|
10375
|
+
});
|
|
9747
10376
|
}
|
|
9748
10377
|
});
|
|
9749
10378
|
try {
|
|
@@ -9817,13 +10446,21 @@ function signalExitCode2(signal) {
|
|
|
9817
10446
|
return 1;
|
|
9818
10447
|
}
|
|
9819
10448
|
}
|
|
9820
|
-
async function readCodexOutput(outputPath,
|
|
10449
|
+
async function readCodexOutput(outputPath, status) {
|
|
9821
10450
|
try {
|
|
9822
|
-
return await
|
|
9823
|
-
} catch {
|
|
9824
|
-
|
|
10451
|
+
return await readFile7(outputPath, "utf8");
|
|
10452
|
+
} catch (error) {
|
|
10453
|
+
if (status === 0) {
|
|
10454
|
+
throw new Error(
|
|
10455
|
+
`Codex CLI exited successfully but did not write --output-last-message: ${safeErrorMessage2(error)}`
|
|
10456
|
+
);
|
|
10457
|
+
}
|
|
10458
|
+
return "";
|
|
9825
10459
|
}
|
|
9826
10460
|
}
|
|
10461
|
+
function safeErrorMessage2(error) {
|
|
10462
|
+
return error instanceof Error ? error.message : String(error);
|
|
10463
|
+
}
|
|
9827
10464
|
function appendBounded2(existing, next) {
|
|
9828
10465
|
const combined = existing + next;
|
|
9829
10466
|
if (combined.length <= CODEX_CLI_STDIO_LIMIT) {
|
|
@@ -9894,35 +10531,89 @@ function codexCliAbortError(signal) {
|
|
|
9894
10531
|
}
|
|
9895
10532
|
return new DOMException("The operation was aborted.", "AbortError");
|
|
9896
10533
|
}
|
|
10534
|
+
function codexCliPreStartAbortError(signal) {
|
|
10535
|
+
return new CodexCreditDispatchError(CODEX_CLI_PRE_START_ABORT_MESSAGE, {
|
|
10536
|
+
cause: codexCliAbortError(signal)
|
|
10537
|
+
});
|
|
10538
|
+
}
|
|
10539
|
+
function unwrapCodexCliPreStartAbort(error) {
|
|
10540
|
+
return error instanceof CodexCreditDispatchError && error.message === CODEX_CLI_PRE_START_ABORT_MESSAGE && error.cause instanceof Error ? error.cause : error;
|
|
10541
|
+
}
|
|
9897
10542
|
function summarizeProcessOutput2(stderr, stdout) {
|
|
9898
10543
|
const summary = [stderr.trim(), stdout.trim()].filter((value) => value.length > 0).join("\n").trim();
|
|
9899
10544
|
return summary.length > 0 ? summary.slice(-1e3) : "no process output";
|
|
9900
10545
|
}
|
|
9901
|
-
function
|
|
9902
|
-
const
|
|
9903
|
-
|
|
10546
|
+
function requireCodexJsonlUsage(result) {
|
|
10547
|
+
const usage = parseCodexJsonlUsage(`${result.stdout}
|
|
10548
|
+
${result.stderr}`);
|
|
10549
|
+
if (!usage) {
|
|
10550
|
+
throw new Error(
|
|
10551
|
+
`Codex CLI completion did not emit a valid turn.completed usage event: ${summarizeProcessOutput2(result.stderr, result.stdout)}`
|
|
10552
|
+
);
|
|
10553
|
+
}
|
|
10554
|
+
return usage;
|
|
10555
|
+
}
|
|
10556
|
+
function readCodexUsage(result, outputText) {
|
|
10557
|
+
const exact = parseCodexJsonlUsage(`${result.stdout}
|
|
10558
|
+
${result.stderr}`);
|
|
10559
|
+
if (exact) return exact;
|
|
10560
|
+
const legacy = parseCodexTokenUsage(
|
|
10561
|
+
`${result.stderr}
|
|
10562
|
+
${result.stdout}`,
|
|
10563
|
+
outputText
|
|
10564
|
+
);
|
|
10565
|
+
return {
|
|
10566
|
+
inputTokens: legacy.input,
|
|
10567
|
+
cachedInputTokens: 0,
|
|
10568
|
+
outputTokens: legacy.output,
|
|
10569
|
+
reasoningOutputTokens: 0
|
|
10570
|
+
};
|
|
10571
|
+
}
|
|
10572
|
+
function parseCodexTokenUsage(output, outputText) {
|
|
10573
|
+
const matches = [...output.matchAll(/\btokens used\s+([0-9][0-9,]*)\b/gi)];
|
|
10574
|
+
const raw = matches.at(-1)?.[1];
|
|
10575
|
+
if (!raw) return { input: 0, output: 0 };
|
|
10576
|
+
const totalTokens = Number(raw.replace(/,/g, ""));
|
|
10577
|
+
if (!Number.isSafeInteger(totalTokens) || totalTokens < 0) {
|
|
9904
10578
|
return { input: 0, output: 0 };
|
|
9905
10579
|
}
|
|
9906
|
-
const
|
|
10580
|
+
const outputTokens = Math.min(
|
|
9907
10581
|
totalTokens,
|
|
9908
10582
|
Math.max(1, Math.ceil(outputText.length / 4))
|
|
9909
10583
|
);
|
|
9910
|
-
return {
|
|
9911
|
-
|
|
9912
|
-
|
|
9913
|
-
}
|
|
10584
|
+
return { input: totalTokens - outputTokens, output: outputTokens };
|
|
10585
|
+
}
|
|
10586
|
+
function codexCliResultError(result) {
|
|
10587
|
+
const exitLabel = result.signal ? `signal ${result.signal}` : `exit ${result.status ?? "unknown"}`;
|
|
10588
|
+
return new Error(
|
|
10589
|
+
`Codex CLI completion failed (${exitLabel}): ${summarizeProcessOutput2(result.stderr, result.stdout)}`
|
|
10590
|
+
);
|
|
10591
|
+
}
|
|
10592
|
+
function tomlString(value) {
|
|
10593
|
+
return JSON.stringify(value);
|
|
10594
|
+
}
|
|
10595
|
+
function buildCodexStructuredJudgePrompt(rubric) {
|
|
10596
|
+
return [
|
|
10597
|
+
rubric,
|
|
10598
|
+
"Return raw JSON only, with exactly these keys:",
|
|
10599
|
+
'{"score":<number from 0 to 1>,"decision":"pass|partial|fail","reason":"non-empty concise reason"}',
|
|
10600
|
+
"Do not wrap the JSON in Markdown or add any other text."
|
|
10601
|
+
].join("\n\n");
|
|
10602
|
+
}
|
|
10603
|
+
function buildCodexAssistantRubricPrompt(systemPrompt) {
|
|
10604
|
+
return [
|
|
10605
|
+
systemPrompt,
|
|
10606
|
+
"Return raw JSON only, with exactly these keys:",
|
|
10607
|
+
'{"identity_accuracy":<0-5>,"stance_coherence":<0-5>,"novelty":<0-5>,"calibration":<0-5>,"notes":"string"}',
|
|
10608
|
+
"Every numeric value must be finite and within the inclusive range 0 to 5.",
|
|
10609
|
+
"Do not wrap the JSON in Markdown or add any other text."
|
|
10610
|
+
].join("\n\n");
|
|
9914
10611
|
}
|
|
9915
|
-
function
|
|
9916
|
-
|
|
9917
|
-
const raw = matches.at(-1)?.[1];
|
|
9918
|
-
if (!raw) {
|
|
9919
|
-
return void 0;
|
|
9920
|
-
}
|
|
9921
|
-
const parsed = Number(raw.replace(/,/g, ""));
|
|
9922
|
-
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
10612
|
+
function isCodexStructuredJudgeAbort(error, signal) {
|
|
10613
|
+
return signal?.aborted === true || error instanceof DOMException && error.name === "AbortError" || error instanceof Error && error.name === "AbortError";
|
|
9923
10614
|
}
|
|
9924
|
-
function
|
|
9925
|
-
return
|
|
10615
|
+
function structuredJudgeErrorName(error) {
|
|
10616
|
+
return error instanceof Error && error.name.trim().length > 0 ? error.name : "unknown error";
|
|
9926
10617
|
}
|
|
9927
10618
|
function createCodexCliProvider(config, deps) {
|
|
9928
10619
|
return new CodexCliProvider(config, deps);
|
|
@@ -9930,28 +10621,28 @@ function createCodexCliProvider(config, deps) {
|
|
|
9930
10621
|
|
|
9931
10622
|
// src/reporter.ts
|
|
9932
10623
|
import { execSync } from "child_process";
|
|
9933
|
-
import { mkdir as
|
|
9934
|
-
import
|
|
10624
|
+
import { mkdir as mkdir8, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
10625
|
+
import path11 from "path";
|
|
9935
10626
|
|
|
9936
10627
|
// src/filename-safety.ts
|
|
9937
|
-
import
|
|
10628
|
+
import path9 from "path";
|
|
9938
10629
|
function sanitizeFilenameSegment(value) {
|
|
9939
10630
|
const sanitized = value.trim().replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
9940
10631
|
return sanitized.length > 0 ? sanitized : "unknown";
|
|
9941
10632
|
}
|
|
9942
10633
|
function resolveContainedPath(root, ...segments) {
|
|
9943
|
-
const outputRoot =
|
|
9944
|
-
const filePath =
|
|
9945
|
-
const relativePath =
|
|
9946
|
-
if (relativePath === ".." || relativePath.startsWith(`..${
|
|
10634
|
+
const outputRoot = path9.resolve(root);
|
|
10635
|
+
const filePath = path9.resolve(outputRoot, ...segments);
|
|
10636
|
+
const relativePath = path9.relative(outputRoot, filePath);
|
|
10637
|
+
if (relativePath === ".." || relativePath.startsWith(`..${path9.sep}`) || path9.isAbsolute(relativePath)) {
|
|
9947
10638
|
throw new Error(`Refusing to write benchmark artifact outside ${outputRoot}`);
|
|
9948
10639
|
}
|
|
9949
10640
|
return filePath;
|
|
9950
10641
|
}
|
|
9951
10642
|
|
|
9952
10643
|
// src/leaderboard-export.ts
|
|
9953
|
-
import { mkdir as
|
|
9954
|
-
import
|
|
10644
|
+
import { mkdir as mkdir7, writeFile as writeFile7 } from "fs/promises";
|
|
10645
|
+
import path10 from "path";
|
|
9955
10646
|
async function writeLeaderboardArtifactsForResult(result, outputDir) {
|
|
9956
10647
|
if (result.meta.benchmark === "ama-bench") {
|
|
9957
10648
|
return writeAmaBenchLeaderboard(result, outputDir);
|
|
@@ -9966,12 +10657,12 @@ async function writeAmaBenchLeaderboard(result, outputDir) {
|
|
|
9966
10657
|
if (rows.length === 0) {
|
|
9967
10658
|
return [];
|
|
9968
10659
|
}
|
|
9969
|
-
const outputRoot =
|
|
10660
|
+
const outputRoot = path10.resolve(outputDir);
|
|
9970
10661
|
const leaderboardDir = resolveContainedPath(outputRoot, "leaderboard");
|
|
9971
|
-
await
|
|
10662
|
+
await mkdir7(leaderboardDir, { recursive: true });
|
|
9972
10663
|
const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
|
|
9973
10664
|
const filePath = resolveContainedPath(leaderboardDir, `ama-bench-${timestamp}-answers.jsonl`);
|
|
9974
|
-
await
|
|
10665
|
+
await writeFile7(filePath, serializeJsonl(rows), "utf8");
|
|
9975
10666
|
return [
|
|
9976
10667
|
{
|
|
9977
10668
|
benchmark: "ama-bench",
|
|
@@ -9984,16 +10675,16 @@ async function writeAmaBenchLeaderboard(result, outputDir) {
|
|
|
9984
10675
|
async function writeMemCorrectLeaderboard(result, outputDir) {
|
|
9985
10676
|
const row = buildMemCorrectLeaderboardRow(result);
|
|
9986
10677
|
if (!row) return [];
|
|
9987
|
-
const outputRoot =
|
|
10678
|
+
const outputRoot = path10.resolve(outputDir);
|
|
9988
10679
|
const leaderboardDir = resolveContainedPath(outputRoot, "leaderboard");
|
|
9989
|
-
await
|
|
10680
|
+
await mkdir7(leaderboardDir, { recursive: true });
|
|
9990
10681
|
const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
|
|
9991
10682
|
const safeAdapter = sanitizeFilenameSegment(row.adapter);
|
|
9992
10683
|
const filePath = resolveContainedPath(
|
|
9993
10684
|
leaderboardDir,
|
|
9994
10685
|
`memcorrect-${safeAdapter}-${timestamp}.jsonl`
|
|
9995
10686
|
);
|
|
9996
|
-
await
|
|
10687
|
+
await writeFile7(filePath, `${JSON.stringify(row)}
|
|
9997
10688
|
`, "utf8");
|
|
9998
10689
|
return [
|
|
9999
10690
|
{
|
|
@@ -10352,8 +11043,8 @@ function replaceLoneSurrogates(value) {
|
|
|
10352
11043
|
return out;
|
|
10353
11044
|
}
|
|
10354
11045
|
async function writeBenchmarkResult(result, outputDir) {
|
|
10355
|
-
const outputRoot =
|
|
10356
|
-
await
|
|
11046
|
+
const outputRoot = path11.resolve(outputDir);
|
|
11047
|
+
await mkdir8(outputRoot, { recursive: true });
|
|
10357
11048
|
const safeBenchmark = sanitizeFilenameSegment(result.meta.benchmark);
|
|
10358
11049
|
const safeRemnicVersion = sanitizeFilenameSegment(result.meta.remnicVersion);
|
|
10359
11050
|
const timestamp = sanitizeFilenameSegment(result.meta.timestamp.replace(/[:.]/g, "-"));
|
|
@@ -10381,14 +11072,14 @@ async function writeBenchmarkResult(result, outputDir) {
|
|
|
10381
11072
|
}
|
|
10382
11073
|
};
|
|
10383
11074
|
const publicResult = sanitizeBenchmarkResultForJson(redactBenchmarkResultSecrets(resultWithArtifacts));
|
|
10384
|
-
await
|
|
11075
|
+
await writeFile8(filePath, `${JSON.stringify(publicResult, null, 2)}
|
|
10385
11076
|
`);
|
|
10386
11077
|
return filePath;
|
|
10387
11078
|
}
|
|
10388
11079
|
async function getRemnicVersion() {
|
|
10389
11080
|
try {
|
|
10390
11081
|
const packageJson = JSON.parse(
|
|
10391
|
-
await
|
|
11082
|
+
await readFile8(path11.resolve(import.meta.dirname, "../../../package.json"), "utf8")
|
|
10392
11083
|
);
|
|
10393
11084
|
return typeof packageJson.version === "string" ? packageJson.version : "unknown";
|
|
10394
11085
|
} catch {
|
|
@@ -11641,52 +12332,8 @@ function asStringArray(value) {
|
|
|
11641
12332
|
// src/responders.ts
|
|
11642
12333
|
import { FallbackLlmClient } from "@remnic/core";
|
|
11643
12334
|
|
|
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
12335
|
// src/providers/openai-responses.ts
|
|
11667
12336
|
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
12337
|
var OpenAiResponsesJudgeError = class extends Error {
|
|
11691
12338
|
code;
|
|
11692
12339
|
retryable;
|
|
@@ -11825,7 +12472,7 @@ var OpenAiResponsesProvider = class {
|
|
|
11825
12472
|
this.recordTelemetry(failure.telemetry);
|
|
11826
12473
|
return failure;
|
|
11827
12474
|
}
|
|
11828
|
-
const verdict =
|
|
12475
|
+
const verdict = parseStructuredJudgeVerdict(parsed.text);
|
|
11829
12476
|
if (!verdict) {
|
|
11830
12477
|
const failure = this.failure(
|
|
11831
12478
|
"malformed_verdict",
|
|
@@ -11879,7 +12526,7 @@ var OpenAiResponsesProvider = class {
|
|
|
11879
12526
|
this.recordTelemetry(parsed.telemetry);
|
|
11880
12527
|
throw new OpenAiResponsesJudgeError(parsed);
|
|
11881
12528
|
}
|
|
11882
|
-
if (parsed.text === null || !
|
|
12529
|
+
if (parsed.text === null || !isValidAssistantRubric(parsed.text)) {
|
|
11883
12530
|
const failure = this.failure(
|
|
11884
12531
|
"malformed_verdict",
|
|
11885
12532
|
"OpenAI Responses API returned an invalid sealed assistant-rubric verdict.",
|
|
@@ -11901,6 +12548,9 @@ var OpenAiResponsesProvider = class {
|
|
|
11901
12548
|
getTelemetryEvents() {
|
|
11902
12549
|
return this.telemetryEvents.map((event) => ({ ...event }));
|
|
11903
12550
|
}
|
|
12551
|
+
createJudgeError(failure) {
|
|
12552
|
+
return new OpenAiResponsesJudgeError(failure);
|
|
12553
|
+
}
|
|
11904
12554
|
async parseResponse(response, startedAt, rubricVersion) {
|
|
11905
12555
|
let payload;
|
|
11906
12556
|
try {
|
|
@@ -12052,61 +12702,10 @@ function createOpenAiResponsesProvider(config = {}) {
|
|
|
12052
12702
|
return new OpenAiResponsesProvider(config);
|
|
12053
12703
|
}
|
|
12054
12704
|
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
|
-
};
|
|
12705
|
+
return createStructuredBenchJudge(
|
|
12706
|
+
provider,
|
|
12707
|
+
config.rubricVersion ?? OPENAI_RESPONSES_JUDGE_RUBRIC_VERSION
|
|
12708
|
+
);
|
|
12110
12709
|
}
|
|
12111
12710
|
async function judgeMemCorrectCorrectionAcceptance(provider, input, signal) {
|
|
12112
12711
|
return provider.judge({
|
|
@@ -12124,17 +12723,6 @@ async function judgeMemCorrectStaleMemoryHarm(provider, input, signal) {
|
|
|
12124
12723
|
signal
|
|
12125
12724
|
});
|
|
12126
12725
|
}
|
|
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
12726
|
function normalizeModel(model) {
|
|
12139
12727
|
if (model === void 0) return DEFAULT_OPENAI_RESPONSES_JUDGE_MODEL;
|
|
12140
12728
|
const trimmed = model.trim();
|
|
@@ -12143,54 +12731,6 @@ function normalizeModel(model) {
|
|
|
12143
12731
|
}
|
|
12144
12732
|
return trimmed;
|
|
12145
12733
|
}
|
|
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
12734
|
function readOutputText(payload) {
|
|
12195
12735
|
const text = (payload.output ?? []).flatMap((item) => item.type === "message" ? item.content ?? [] : []).filter((part) => part.type === "output_text").map((part) => part.text ?? "").join("").trim();
|
|
12196
12736
|
return text.length > 0 ? text : null;
|
|
@@ -12715,10 +13255,11 @@ function createJudgeFromProvider(provider) {
|
|
|
12715
13255
|
}
|
|
12716
13256
|
function createProviderBackedJudge(config, providerInstance) {
|
|
12717
13257
|
validateProviderConfig(config, "judge");
|
|
12718
|
-
|
|
12719
|
-
|
|
13258
|
+
const provider = providerInstance ?? createJudgeProvider(config);
|
|
13259
|
+
if (isStructuredJudgeProvider(provider)) {
|
|
13260
|
+
return createStructuredBenchJudge(provider, config.rubricVersion);
|
|
12720
13261
|
}
|
|
12721
|
-
return createJudgeFromProvider(
|
|
13262
|
+
return createJudgeFromProvider(provider);
|
|
12722
13263
|
}
|
|
12723
13264
|
function createAmaBenchRecommendedJudgeFromProvider(provider) {
|
|
12724
13265
|
async function scoreWithMetrics(question, predicted, expected, control) {
|
|
@@ -12771,15 +13312,16 @@ function createStructuredJudgeFromProvider(provider) {
|
|
|
12771
13312
|
}
|
|
12772
13313
|
function createProviderBackedStructuredJudge(config, providerInstance) {
|
|
12773
13314
|
validateProviderConfig(config, "judge");
|
|
12774
|
-
|
|
12775
|
-
|
|
13315
|
+
const provider = providerInstance ?? createJudgeProvider(config);
|
|
13316
|
+
if (isStructuredJudgeProvider(provider)) {
|
|
12776
13317
|
return {
|
|
12777
13318
|
evaluate: (request) => provider.evaluateAssistantRubric(request)
|
|
12778
13319
|
};
|
|
12779
13320
|
}
|
|
12780
|
-
return createStructuredJudgeFromProvider(
|
|
12781
|
-
|
|
12782
|
-
|
|
13321
|
+
return createStructuredJudgeFromProvider(provider);
|
|
13322
|
+
}
|
|
13323
|
+
function createJudgeProvider(config) {
|
|
13324
|
+
return config.provider === "openai" ? createOpenAiResponsesProvider({ ...config, provider: "openai" }) : createProvider(config);
|
|
12783
13325
|
}
|
|
12784
13326
|
function createGatewayResponder(options) {
|
|
12785
13327
|
if (!options.gatewayConfig) {
|
|
@@ -13052,8 +13594,8 @@ function clampNormalizedScore(value) {
|
|
|
13052
13594
|
}
|
|
13053
13595
|
|
|
13054
13596
|
// src/runtime-profiles.ts
|
|
13055
|
-
import
|
|
13056
|
-
import { readFile as
|
|
13597
|
+
import path12 from "path";
|
|
13598
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
13057
13599
|
import {
|
|
13058
13600
|
resolvePluginEntry,
|
|
13059
13601
|
setCodexCliFallbackRunnerForProcess
|
|
@@ -13401,7 +13943,7 @@ function buildPromptSpecificRequirements(prompt) {
|
|
|
13401
13943
|
}
|
|
13402
13944
|
|
|
13403
13945
|
// src/local-lab/manifest.ts
|
|
13404
|
-
import { readFile as
|
|
13946
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
13405
13947
|
var LOCAL_LAB_PROVIDER_KINDS = [
|
|
13406
13948
|
"openai-compatible",
|
|
13407
13949
|
"ollama"
|
|
@@ -13438,7 +13980,7 @@ function parseLocalLabManifest(raw) {
|
|
|
13438
13980
|
async function loadLocalLabManifest(filePath) {
|
|
13439
13981
|
let text;
|
|
13440
13982
|
try {
|
|
13441
|
-
text = await
|
|
13983
|
+
text = await readFile9(filePath, "utf8");
|
|
13442
13984
|
} catch (error) {
|
|
13443
13985
|
const code = error?.code ?? "EUNKNOWN";
|
|
13444
13986
|
throw new Error(`local-lab manifest at ${filePath} could not be read (${code})`);
|
|
@@ -14099,14 +14641,14 @@ async function loadOpenclawRuntimeConfig(filePath) {
|
|
|
14099
14641
|
};
|
|
14100
14642
|
}
|
|
14101
14643
|
function deriveOpenclawRuntimeContext(configPath) {
|
|
14102
|
-
const rootDir =
|
|
14644
|
+
const rootDir = path12.dirname(path12.resolve(configPath));
|
|
14103
14645
|
return {
|
|
14104
|
-
agentDir:
|
|
14105
|
-
workspaceDir:
|
|
14646
|
+
agentDir: path12.join(rootDir, "agents", "main", "agent"),
|
|
14647
|
+
workspaceDir: path12.join(rootDir, "workspace")
|
|
14106
14648
|
};
|
|
14107
14649
|
}
|
|
14108
14650
|
async function loadJsonObject(filePath, label) {
|
|
14109
|
-
const raw = await
|
|
14651
|
+
const raw = await readFile10(filePath, "utf8");
|
|
14110
14652
|
let parsed;
|
|
14111
14653
|
try {
|
|
14112
14654
|
parsed = JSON.parse(raw);
|
|
@@ -14518,20 +15060,20 @@ async function resolveLocalLabRuntimeProfile(options) {
|
|
|
14518
15060
|
|
|
14519
15061
|
// src/benchmark.ts
|
|
14520
15062
|
import fs2 from "fs";
|
|
14521
|
-
import
|
|
15063
|
+
import path35 from "path";
|
|
14522
15064
|
import { createHash as createHash11 } from "crypto";
|
|
14523
15065
|
import { expandTildePath as expandTildePath3 } from "@remnic/core";
|
|
14524
15066
|
|
|
14525
15067
|
// src/judges/judge-cache.ts
|
|
14526
15068
|
import { createHash as createHash6, randomBytes as randomBytes2 } from "crypto";
|
|
14527
15069
|
import {
|
|
14528
|
-
mkdir as
|
|
14529
|
-
readFile as
|
|
14530
|
-
rename as
|
|
15070
|
+
mkdir as mkdir9,
|
|
15071
|
+
readFile as readFile11,
|
|
15072
|
+
rename as rename3,
|
|
14531
15073
|
rm as rm4,
|
|
14532
|
-
writeFile as
|
|
15074
|
+
writeFile as writeFile9
|
|
14533
15075
|
} from "fs/promises";
|
|
14534
|
-
import
|
|
15076
|
+
import path13 from "path";
|
|
14535
15077
|
var JUDGE_CACHE_PROTOCOL_VERSION = "judge-protocol-v1";
|
|
14536
15078
|
function stableStringify2(value) {
|
|
14537
15079
|
if (Array.isArray(value)) {
|
|
@@ -14562,7 +15104,7 @@ var JudgeCache = class {
|
|
|
14562
15104
|
inflight = /* @__PURE__ */ new Map();
|
|
14563
15105
|
cachedDirExists = false;
|
|
14564
15106
|
constructor(options) {
|
|
14565
|
-
this.dir =
|
|
15107
|
+
this.dir = path13.resolve(options.dir);
|
|
14566
15108
|
}
|
|
14567
15109
|
/** Compute the sha256-hex key for a set of parts. Pure, sync, side-effect-free. */
|
|
14568
15110
|
computeKey(parts) {
|
|
@@ -14587,7 +15129,7 @@ var JudgeCache = class {
|
|
|
14587
15129
|
const filePath = this.entryPath(key);
|
|
14588
15130
|
let raw;
|
|
14589
15131
|
try {
|
|
14590
|
-
raw = await
|
|
15132
|
+
raw = await readFile11(filePath, "utf8");
|
|
14591
15133
|
} catch {
|
|
14592
15134
|
return void 0;
|
|
14593
15135
|
}
|
|
@@ -14633,25 +15175,25 @@ var JudgeCache = class {
|
|
|
14633
15175
|
}
|
|
14634
15176
|
async writeOne(key, envelope) {
|
|
14635
15177
|
if (!this.cachedDirExists) {
|
|
14636
|
-
await
|
|
15178
|
+
await mkdir9(this.dir, { recursive: true });
|
|
14637
15179
|
this.cachedDirExists = true;
|
|
14638
15180
|
}
|
|
14639
15181
|
const filePath = this.entryPath(key);
|
|
14640
|
-
const tempPath =
|
|
15182
|
+
const tempPath = path13.join(
|
|
14641
15183
|
this.dir,
|
|
14642
15184
|
`.${key}.${randomBytes2(6).toString("hex")}.tmp`
|
|
14643
15185
|
);
|
|
14644
|
-
await
|
|
15186
|
+
await writeFile9(tempPath, `${JSON.stringify(envelope)}
|
|
14645
15187
|
`, "utf8");
|
|
14646
15188
|
try {
|
|
14647
|
-
await
|
|
15189
|
+
await rename3(tempPath, filePath);
|
|
14648
15190
|
} catch (error) {
|
|
14649
15191
|
await rm4(tempPath, { force: true }).catch(() => void 0);
|
|
14650
15192
|
throw error;
|
|
14651
15193
|
}
|
|
14652
15194
|
}
|
|
14653
15195
|
entryPath(key) {
|
|
14654
|
-
return
|
|
15196
|
+
return path13.join(this.dir, `${key}.json`);
|
|
14655
15197
|
}
|
|
14656
15198
|
};
|
|
14657
15199
|
function runJudgeWithCache(options) {
|
|
@@ -14841,8 +15383,8 @@ function isBenchJudgeResult(value) {
|
|
|
14841
15383
|
|
|
14842
15384
|
// src/benchmarks/published/ama-bench/runner.ts
|
|
14843
15385
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
14844
|
-
import { readFile as
|
|
14845
|
-
import
|
|
15386
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
15387
|
+
import path14 from "path";
|
|
14846
15388
|
|
|
14847
15389
|
// src/benchmarks/published/ama-bench/fixture.ts
|
|
14848
15390
|
var AMA_BENCH_SMOKE_FIXTURE = [
|
|
@@ -15417,10 +15959,10 @@ async function loadDataset(mode, datasetDir, limit) {
|
|
|
15417
15959
|
return episodes;
|
|
15418
15960
|
};
|
|
15419
15961
|
if (datasetDir) {
|
|
15420
|
-
const filePath =
|
|
15962
|
+
const filePath = path14.join(datasetDir, "open_end_qa_set.jsonl");
|
|
15421
15963
|
let raw;
|
|
15422
15964
|
try {
|
|
15423
|
-
raw = await
|
|
15965
|
+
raw = await readFile12(filePath, "utf8");
|
|
15424
15966
|
} catch (error) {
|
|
15425
15967
|
throw new Error(
|
|
15426
15968
|
`AMA-Bench dataset not found at ${filePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -15712,8 +16254,8 @@ function isValidQaPairs(value) {
|
|
|
15712
16254
|
|
|
15713
16255
|
// src/benchmarks/published/amemgym/runner.ts
|
|
15714
16256
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
15715
|
-
import { readFile as
|
|
15716
|
-
import
|
|
16257
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
16258
|
+
import path15 from "path";
|
|
15717
16259
|
|
|
15718
16260
|
// src/benchmarks/published/amemgym/fixture.ts
|
|
15719
16261
|
var AMEMGYM_SMOKE_FIXTURE = [
|
|
@@ -16242,7 +16784,7 @@ async function loadDataset2(mode, datasetDir, limit) {
|
|
|
16242
16784
|
const datasetErrors = [];
|
|
16243
16785
|
for (const filename of DATASET_FILENAMES) {
|
|
16244
16786
|
try {
|
|
16245
|
-
const raw = await
|
|
16787
|
+
const raw = await readFile13(path15.join(datasetDir, filename), "utf8");
|
|
16246
16788
|
const parsed = parseDataset(raw, filename, normalizedLimit);
|
|
16247
16789
|
return ensureDatasetProfiles(parsed);
|
|
16248
16790
|
} catch (error) {
|
|
@@ -16416,8 +16958,8 @@ function normalizeRole(role) {
|
|
|
16416
16958
|
|
|
16417
16959
|
// src/benchmarks/published/memory-arena/runner.ts
|
|
16418
16960
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
16419
|
-
import { readFile as
|
|
16420
|
-
import
|
|
16961
|
+
import { readFile as readFile14, readdir as readdir5, stat as stat3 } from "fs/promises";
|
|
16962
|
+
import path16 from "path";
|
|
16421
16963
|
import { expandTildePath as expandTildePath2 } from "@remnic/core";
|
|
16422
16964
|
|
|
16423
16965
|
// src/benchmarks/published/memory-arena/fixture.ts
|
|
@@ -16744,7 +17286,7 @@ async function loadDataset3(mode, datasetDir, limit) {
|
|
|
16744
17286
|
if (remainingLimit2 === 0) {
|
|
16745
17287
|
break;
|
|
16746
17288
|
}
|
|
16747
|
-
const raw = await
|
|
17289
|
+
const raw = await readFile14(path16.join(datasetDir, filename), "utf8");
|
|
16748
17290
|
const parsedTasks = [];
|
|
16749
17291
|
raw.split("\n").forEach((line, lineIndex) => {
|
|
16750
17292
|
if (line.trim().length === 0) {
|
|
@@ -17080,7 +17622,7 @@ async function loadMemoryArenaWebshopProductCatalog(datasetDir) {
|
|
|
17080
17622
|
`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
17623
|
);
|
|
17082
17624
|
}
|
|
17083
|
-
const raw = await
|
|
17625
|
+
const raw = await readFile14(sourcePath, "utf8");
|
|
17084
17626
|
const records = parseMemoryArenaWebshopSidecarRecords(raw, sourcePath);
|
|
17085
17627
|
const byAsin = /* @__PURE__ */ new Map();
|
|
17086
17628
|
for (const record of records) {
|
|
@@ -17100,14 +17642,14 @@ async function loadMemoryArenaWebshopProductCatalog(datasetDir) {
|
|
|
17100
17642
|
async function resolveMemoryArenaWebshopProductCatalogPath(datasetDir) {
|
|
17101
17643
|
const configuredPath = process.env[MEMORY_ARENA_WEBSHOP_PRODUCTS_ENV]?.trim();
|
|
17102
17644
|
if (configuredPath && configuredPath.length > 0) {
|
|
17103
|
-
return
|
|
17645
|
+
return path16.resolve(expandTildePath2(configuredPath));
|
|
17104
17646
|
}
|
|
17105
17647
|
if (datasetDir === void 0) {
|
|
17106
17648
|
return void 0;
|
|
17107
17649
|
}
|
|
17108
17650
|
const candidatePaths = [
|
|
17109
17651
|
...MEMORY_ARENA_WEBSHOP_PRODUCT_SIDECAR_FILENAMES
|
|
17110
|
-
].map((filename) =>
|
|
17652
|
+
].map((filename) => path16.join(datasetDir, filename));
|
|
17111
17653
|
for (const candidatePath of candidatePaths) {
|
|
17112
17654
|
try {
|
|
17113
17655
|
const candidateStat = await stat3(candidatePath);
|
|
@@ -18529,8 +19071,8 @@ function scoreSubtaskSuccess(scores) {
|
|
|
18529
19071
|
import { collectTemporalLexicalCues } from "@remnic/core";
|
|
18530
19072
|
|
|
18531
19073
|
// src/benchmarks/published/dataset-loader.ts
|
|
18532
|
-
import { readFile as
|
|
18533
|
-
import
|
|
19074
|
+
import { readFile as readFile15 } from "fs/promises";
|
|
19075
|
+
import path17 from "path";
|
|
18534
19076
|
|
|
18535
19077
|
// src/benchmarks/published/longmemeval/fixture.ts
|
|
18536
19078
|
var LONG_MEM_EVAL_SMOKE_FIXTURE = [
|
|
@@ -18633,10 +19175,10 @@ async function loadDataset4(options) {
|
|
|
18633
19175
|
const errors = [];
|
|
18634
19176
|
if (options.datasetDir) {
|
|
18635
19177
|
for (const filename of options.filenames) {
|
|
18636
|
-
const abs =
|
|
19178
|
+
const abs = path17.join(options.datasetDir, filename);
|
|
18637
19179
|
let raw;
|
|
18638
19180
|
try {
|
|
18639
|
-
raw = await
|
|
19181
|
+
raw = await readFile15(abs, "utf8");
|
|
18640
19182
|
} catch (error) {
|
|
18641
19183
|
errors.push(
|
|
18642
19184
|
`${filename}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -20743,7 +21285,7 @@ function normalizeQaArray(value, location) {
|
|
|
20743
21285
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
20744
21286
|
import { createReadStream as createReadStream2 } from "fs";
|
|
20745
21287
|
import { readdir as readdir6 } from "fs/promises";
|
|
20746
|
-
import
|
|
21288
|
+
import path18 from "path";
|
|
20747
21289
|
import { createInterface } from "readline/promises";
|
|
20748
21290
|
import {
|
|
20749
21291
|
asyncBufferFromFile,
|
|
@@ -21214,8 +21756,8 @@ async function listBeamDatasetFiles(datasetDir) {
|
|
|
21214
21756
|
return directFiles;
|
|
21215
21757
|
}
|
|
21216
21758
|
try {
|
|
21217
|
-
const nestedFilenames = await readdir6(
|
|
21218
|
-
return nestedFilenames.filter((filename) => isBeamDatasetFilename(filename)).map((filename) =>
|
|
21759
|
+
const nestedFilenames = await readdir6(path18.join(datasetDir, "data"));
|
|
21760
|
+
return nestedFilenames.filter((filename) => isBeamDatasetFilename(filename)).map((filename) => path18.join("data", filename));
|
|
21219
21761
|
} catch {
|
|
21220
21762
|
return [];
|
|
21221
21763
|
}
|
|
@@ -21242,7 +21784,7 @@ async function* iterateDatasetFiles(datasetDir, datasetFiles, limit) {
|
|
|
21242
21784
|
let remainingLimit = limit;
|
|
21243
21785
|
for (const filename of datasetFiles) {
|
|
21244
21786
|
const scale = inferScaleFromFilename(filename);
|
|
21245
|
-
const filePath =
|
|
21787
|
+
const filePath = path18.join(datasetDir, filename);
|
|
21246
21788
|
const conversations = filename.endsWith(".jsonl") ? streamJsonlDataset(filePath, filename, remainingLimit) : filename.endsWith(".parquet") ? streamParquetDataset(filePath, filename, remainingLimit) : streamJsonDataset(filePath, filename, remainingLimit);
|
|
21247
21789
|
for await (const conversation of conversations) {
|
|
21248
21790
|
yield {
|
|
@@ -22254,8 +22796,8 @@ var StructuredLiteralParser = class {
|
|
|
22254
22796
|
|
|
22255
22797
|
// src/benchmarks/published/personamem/runner.ts
|
|
22256
22798
|
import { createHash as createHash7, randomUUID as randomUUID7 } from "crypto";
|
|
22257
|
-
import { readFile as
|
|
22258
|
-
import
|
|
22799
|
+
import { readFile as readFile16, realpath as realpath4 } from "fs/promises";
|
|
22800
|
+
import path19 from "path";
|
|
22259
22801
|
|
|
22260
22802
|
// src/benchmarks/published/personamem/fixture.ts
|
|
22261
22803
|
var PERSONAMEM_SMOKE_FIXTURE = [
|
|
@@ -22531,10 +23073,10 @@ async function loadDataset8(mode, datasetDir, limit) {
|
|
|
22531
23073
|
if (datasetDir) {
|
|
22532
23074
|
const datasetErrors = [];
|
|
22533
23075
|
for (const relativePath of DATASET_FILE_CANDIDATES) {
|
|
22534
|
-
const datasetPath =
|
|
23076
|
+
const datasetPath = path19.join(datasetDir, relativePath);
|
|
22535
23077
|
let raw;
|
|
22536
23078
|
try {
|
|
22537
|
-
raw = await
|
|
23079
|
+
raw = await readFile16(datasetPath, "utf8");
|
|
22538
23080
|
} catch (error) {
|
|
22539
23081
|
datasetErrors.push(
|
|
22540
23082
|
`${relativePath}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -22592,7 +23134,7 @@ async function hydrateSample(row, datasetRoot) {
|
|
|
22592
23134
|
datasetRoot,
|
|
22593
23135
|
row.chat_history_32k_link
|
|
22594
23136
|
);
|
|
22595
|
-
const chatHistoryRaw = await
|
|
23137
|
+
const chatHistoryRaw = await readFile16(chatHistoryPath, "utf8");
|
|
22596
23138
|
const chatHistory = parseChatHistory(
|
|
22597
23139
|
chatHistoryRaw,
|
|
22598
23140
|
row.chat_history_32k_link
|
|
@@ -22725,12 +23267,12 @@ function parseCsv(raw, limit) {
|
|
|
22725
23267
|
return rows;
|
|
22726
23268
|
}
|
|
22727
23269
|
async function resolveDatasetFilePath(datasetRoot, relativePath) {
|
|
22728
|
-
const rootPath =
|
|
23270
|
+
const rootPath = path19.resolve(datasetRoot);
|
|
22729
23271
|
const rootRealPath = await realpath4(rootPath);
|
|
22730
|
-
const candidatePath =
|
|
23272
|
+
const candidatePath = path19.resolve(rootPath, relativePath);
|
|
22731
23273
|
const candidateRealPath = await realpath4(candidatePath);
|
|
22732
|
-
const relativeToRoot =
|
|
22733
|
-
if (relativeToRoot.startsWith("..") ||
|
|
23274
|
+
const relativeToRoot = path19.relative(rootRealPath, candidateRealPath);
|
|
23275
|
+
if (relativeToRoot.startsWith("..") || path19.isAbsolute(relativeToRoot)) {
|
|
22734
23276
|
throw new Error(
|
|
22735
23277
|
`PersonaMem-v2 dataset file reference "${relativePath}" must stay within datasetDir.`
|
|
22736
23278
|
);
|
|
@@ -23058,8 +23600,8 @@ function applyLimit6(items, limit) {
|
|
|
23058
23600
|
|
|
23059
23601
|
// src/benchmarks/published/membench/runner.ts
|
|
23060
23602
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
23061
|
-
import { readFile as
|
|
23062
|
-
import
|
|
23603
|
+
import { readFile as readFile17, readdir as readdir7 } from "fs/promises";
|
|
23604
|
+
import path20 from "path";
|
|
23063
23605
|
|
|
23064
23606
|
// src/benchmarks/published/membench/fixture.ts
|
|
23065
23607
|
var MEMBENCH_SMOKE_FIXTURE = [
|
|
@@ -23320,7 +23862,7 @@ async function loadDataset9(mode, datasetDir, limit) {
|
|
|
23320
23862
|
let remainingLimit = normalizedLimit;
|
|
23321
23863
|
for (const filename of filenames) {
|
|
23322
23864
|
try {
|
|
23323
|
-
const raw = await
|
|
23865
|
+
const raw = await readFile17(path20.join(datasetDir, filename), "utf8");
|
|
23324
23866
|
const parsed = filename.endsWith(".jsonl") ? parseJsonlDataset(raw, filename) : parseJsonDataset(raw, filename);
|
|
23325
23867
|
const limitedCases = remainingLimit === 0 ? [] : applyLimit7(parsed, remainingLimit);
|
|
23326
23868
|
if (limitedCases.length > 0) {
|
|
@@ -24187,8 +24729,8 @@ function isPlainObject4(value) {
|
|
|
24187
24729
|
|
|
24188
24730
|
// src/benchmarks/published/memoryagentbench/runner.ts
|
|
24189
24731
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
24190
|
-
import { access, readFile as
|
|
24191
|
-
import
|
|
24732
|
+
import { access, readFile as readFile18 } from "fs/promises";
|
|
24733
|
+
import path21 from "path";
|
|
24192
24734
|
|
|
24193
24735
|
// src/benchmarks/published/memoryagentbench/fixture.ts
|
|
24194
24736
|
var MEMORY_AGENT_BENCH_SMOKE_FIXTURE = [
|
|
@@ -25210,7 +25752,7 @@ async function loadRecSysEntityMapping(datasetDir) {
|
|
|
25210
25752
|
}
|
|
25211
25753
|
let parsed;
|
|
25212
25754
|
try {
|
|
25213
|
-
parsed = JSON.parse(await
|
|
25755
|
+
parsed = JSON.parse(await readFile18(candidate, "utf8"));
|
|
25214
25756
|
} catch (error) {
|
|
25215
25757
|
console.error(
|
|
25216
25758
|
` [WARN] MemoryAgentBench ReDial entity mapping ${candidate} is invalid JSON; trying the next candidate: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -25267,21 +25809,21 @@ function recsysEntityMappingCandidates(datasetDir) {
|
|
|
25267
25809
|
if (!datasetDir) {
|
|
25268
25810
|
return [];
|
|
25269
25811
|
}
|
|
25270
|
-
const absoluteDatasetDir =
|
|
25812
|
+
const absoluteDatasetDir = path21.resolve(datasetDir);
|
|
25271
25813
|
const roots = [
|
|
25272
25814
|
absoluteDatasetDir,
|
|
25273
|
-
|
|
25815
|
+
path21.dirname(absoluteDatasetDir)
|
|
25274
25816
|
];
|
|
25275
25817
|
const canonicalSuffixes = [
|
|
25276
|
-
|
|
25277
|
-
|
|
25818
|
+
path21.join("processed_data", "Recsys_Redial", "entity2id.json"),
|
|
25819
|
+
path21.join("Recsys_Redial", "entity2id.json")
|
|
25278
25820
|
];
|
|
25279
25821
|
const looseSuffixes = ["entity2id.json"];
|
|
25280
25822
|
return [
|
|
25281
25823
|
...roots.flatMap(
|
|
25282
|
-
(root) => canonicalSuffixes.map((suffix) =>
|
|
25824
|
+
(root) => canonicalSuffixes.map((suffix) => path21.join(root, suffix))
|
|
25283
25825
|
),
|
|
25284
|
-
...looseSuffixes.map((suffix) =>
|
|
25826
|
+
...looseSuffixes.map((suffix) => path21.join(absoluteDatasetDir, suffix))
|
|
25285
25827
|
];
|
|
25286
25828
|
}
|
|
25287
25829
|
async function fileExists(filePath) {
|
|
@@ -25318,7 +25860,7 @@ async function loadDataset10(mode, datasetDir, limit) {
|
|
|
25318
25860
|
const datasetErrors = [];
|
|
25319
25861
|
for (const filename of DATASET_BUNDLE_CANDIDATES) {
|
|
25320
25862
|
const parsed = await tryReadDatasetFile(
|
|
25321
|
-
|
|
25863
|
+
path21.join(datasetDir, filename),
|
|
25322
25864
|
filename,
|
|
25323
25865
|
datasetErrors
|
|
25324
25866
|
);
|
|
@@ -25335,7 +25877,7 @@ async function loadDataset10(mode, datasetDir, limit) {
|
|
|
25335
25877
|
let splitData;
|
|
25336
25878
|
for (const filename of splitConfig.candidates) {
|
|
25337
25879
|
try {
|
|
25338
|
-
splitData = await readDatasetFile(
|
|
25880
|
+
splitData = await readDatasetFile(path21.join(datasetDir, filename), filename);
|
|
25339
25881
|
break;
|
|
25340
25882
|
} catch (error) {
|
|
25341
25883
|
if (!isFileNotFoundError2(error)) {
|
|
@@ -25373,7 +25915,7 @@ async function loadDataset10(mode, datasetDir, limit) {
|
|
|
25373
25915
|
return ensureDatasetItems(applyLimit8(MEMORY_AGENT_BENCH_SMOKE_FIXTURE, normalizedLimit));
|
|
25374
25916
|
}
|
|
25375
25917
|
async function readDatasetFile(filePath, filename) {
|
|
25376
|
-
const raw = await
|
|
25918
|
+
const raw = await readFile18(filePath, "utf8");
|
|
25377
25919
|
const parsed = filename.endsWith(".jsonl") ? parseJsonLines(raw, filename) : parseJsonArray(raw, filename);
|
|
25378
25920
|
return parsed.map(
|
|
25379
25921
|
(item, index) => parseMemoryAgentBenchItem(item, `${filename} item ${index + 1}`)
|
|
@@ -25983,8 +26525,8 @@ function loadCases(mode, limit) {
|
|
|
25983
26525
|
|
|
25984
26526
|
// src/benchmarks/remnic/extraction-judge-calibration/runner.ts
|
|
25985
26527
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
25986
|
-
import
|
|
25987
|
-
import
|
|
26528
|
+
import os6 from "os";
|
|
26529
|
+
import path22 from "path";
|
|
25988
26530
|
import {
|
|
25989
26531
|
createVerdictCache,
|
|
25990
26532
|
judgeFactDurability,
|
|
@@ -26094,8 +26636,8 @@ var extractionJudgeCalibrationDefinition = {
|
|
|
26094
26636
|
async function runExtractionJudgeCalibrationBenchmark(options) {
|
|
26095
26637
|
const cases = loadCases2(options.mode, options.limit);
|
|
26096
26638
|
const config = parseConfig2({
|
|
26097
|
-
memoryDir:
|
|
26098
|
-
workspaceDir:
|
|
26639
|
+
memoryDir: path22.join(os6.tmpdir(), "remnic-bench-extraction-judge"),
|
|
26640
|
+
workspaceDir: path22.join(os6.tmpdir(), "remnic-bench-extraction-judge-workspace"),
|
|
26099
26641
|
openaiApiKey: "bench-test-key",
|
|
26100
26642
|
extractionJudgeEnabled: true,
|
|
26101
26643
|
extractionJudgeBatchSize: 4,
|
|
@@ -26643,8 +27185,8 @@ function constantAggregate2(value) {
|
|
|
26643
27185
|
}
|
|
26644
27186
|
|
|
26645
27187
|
// src/benchmarks/remnic/entity-consolidation/runner.ts
|
|
26646
|
-
import
|
|
26647
|
-
import
|
|
27188
|
+
import os7 from "os";
|
|
27189
|
+
import path23 from "path";
|
|
26648
27190
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
26649
27191
|
import { mkdtemp as mkdtemp4, rm as rm5 } from "fs/promises";
|
|
26650
27192
|
import { StorageManager } from "@remnic/core";
|
|
@@ -26807,7 +27349,7 @@ function loadCases4(mode, limit) {
|
|
|
26807
27349
|
return limited;
|
|
26808
27350
|
}
|
|
26809
27351
|
async function executeCase(sample) {
|
|
26810
|
-
const tmpDir = await mkdtemp4(
|
|
27352
|
+
const tmpDir = await mkdtemp4(path23.join(os7.tmpdir(), "remnic-bench-entity-consolidation-"));
|
|
26811
27353
|
try {
|
|
26812
27354
|
const storage = new StorageManager(tmpDir);
|
|
26813
27355
|
await storage.ensureDirectories();
|
|
@@ -26986,9 +27528,9 @@ function parseNonNegativeInt(rawValue) {
|
|
|
26986
27528
|
|
|
26987
27529
|
// src/benchmarks/remnic/page-versioning/runner.ts
|
|
26988
27530
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
26989
|
-
import { mkdir as
|
|
26990
|
-
import
|
|
26991
|
-
import
|
|
27531
|
+
import { mkdir as mkdir10, mkdtemp as mkdtemp5, readFile as readFile19, rm as rm6, writeFile as writeFile10 } from "fs/promises";
|
|
27532
|
+
import os8 from "os";
|
|
27533
|
+
import path24 from "path";
|
|
26992
27534
|
import {
|
|
26993
27535
|
createVersion,
|
|
26994
27536
|
diffVersions,
|
|
@@ -27152,21 +27694,21 @@ function loadCases5(mode, limit) {
|
|
|
27152
27694
|
return limited;
|
|
27153
27695
|
}
|
|
27154
27696
|
async function executeCase2(sample, dependencies) {
|
|
27155
|
-
const tmpDir = await mkdtemp5(
|
|
27697
|
+
const tmpDir = await mkdtemp5(path24.join(os8.tmpdir(), "remnic-bench-page-versioning-"));
|
|
27156
27698
|
try {
|
|
27157
|
-
const factsDir =
|
|
27158
|
-
const pagePath =
|
|
27159
|
-
await
|
|
27699
|
+
const factsDir = path24.join(tmpDir, "facts");
|
|
27700
|
+
const pagePath = path24.join(factsDir, `${sample.id}.md`);
|
|
27701
|
+
await mkdir10(factsDir, { recursive: true });
|
|
27160
27702
|
const config = versioningConfig();
|
|
27161
27703
|
switch (sample.scenario) {
|
|
27162
27704
|
case "revert-flow": {
|
|
27163
|
-
await
|
|
27705
|
+
await writeFile10(pagePath, "original content", "utf-8");
|
|
27164
27706
|
await dependencies.createVersion(pagePath, "original content", "write", config, void 0, void 0, tmpDir);
|
|
27165
|
-
await
|
|
27707
|
+
await writeFile10(pagePath, "modified content", "utf-8");
|
|
27166
27708
|
await dependencies.createVersion(pagePath, "modified content", "write", config, void 0, void 0, tmpDir);
|
|
27167
27709
|
await dependencies.revertToVersion(pagePath, "1", config, void 0, tmpDir);
|
|
27168
27710
|
const history = await dependencies.listVersions(pagePath, config, tmpDir);
|
|
27169
|
-
const pageContent = await
|
|
27711
|
+
const pageContent = await readFile19(pagePath, "utf-8");
|
|
27170
27712
|
const observed = await dependencies.getVersion(pagePath, "3", config, tmpDir);
|
|
27171
27713
|
return {
|
|
27172
27714
|
versionIds: history.versions.map((version) => version.versionId),
|
|
@@ -27179,11 +27721,11 @@ async function executeCase2(sample, dependencies) {
|
|
|
27179
27721
|
const pruningConfig = versioningConfig({ maxVersionsPerPage: 2 });
|
|
27180
27722
|
for (let index = 1; index <= 4; index += 1) {
|
|
27181
27723
|
const content = `content v${index}`;
|
|
27182
|
-
await
|
|
27724
|
+
await writeFile10(pagePath, content, "utf-8");
|
|
27183
27725
|
await dependencies.createVersion(pagePath, content, "write", pruningConfig, void 0, void 0, tmpDir);
|
|
27184
27726
|
}
|
|
27185
27727
|
const history = await dependencies.listVersions(pagePath, pruningConfig, tmpDir);
|
|
27186
|
-
const pageContent = await
|
|
27728
|
+
const pageContent = await readFile19(pagePath, "utf-8");
|
|
27187
27729
|
const prunedIds = [];
|
|
27188
27730
|
for (const versionId of ["1", "2"]) {
|
|
27189
27731
|
try {
|
|
@@ -27203,7 +27745,7 @@ async function executeCase2(sample, dependencies) {
|
|
|
27203
27745
|
};
|
|
27204
27746
|
}
|
|
27205
27747
|
case "diff-output": {
|
|
27206
|
-
await
|
|
27748
|
+
await writeFile10(pagePath, "line 1\nline 2\nline 3", "utf-8");
|
|
27207
27749
|
await dependencies.createVersion(
|
|
27208
27750
|
pagePath,
|
|
27209
27751
|
"line 1\nline 2\nline 3",
|
|
@@ -27213,7 +27755,7 @@ async function executeCase2(sample, dependencies) {
|
|
|
27213
27755
|
void 0,
|
|
27214
27756
|
tmpDir
|
|
27215
27757
|
);
|
|
27216
|
-
await
|
|
27758
|
+
await writeFile10(pagePath, "line 1\nline 2 changed\nline 3\nline 4", "utf-8");
|
|
27217
27759
|
await dependencies.createVersion(
|
|
27218
27760
|
pagePath,
|
|
27219
27761
|
"line 1\nline 2 changed\nline 3\nline 4",
|
|
@@ -27224,7 +27766,7 @@ async function executeCase2(sample, dependencies) {
|
|
|
27224
27766
|
tmpDir
|
|
27225
27767
|
);
|
|
27226
27768
|
const history = await dependencies.listVersions(pagePath, config, tmpDir);
|
|
27227
|
-
const pageContent = await
|
|
27769
|
+
const pageContent = await readFile19(pagePath, "utf-8");
|
|
27228
27770
|
const diff = await dependencies.diffVersions(pagePath, "1", "2", config, tmpDir);
|
|
27229
27771
|
const observedLines = normalizeDiffChangedLines(diff);
|
|
27230
27772
|
return {
|
|
@@ -29510,8 +30052,8 @@ function loadCases9(mode, limit) {
|
|
|
29510
30052
|
// src/benchmarks/remnic/procedural-recall/runner.ts
|
|
29511
30053
|
import { randomUUID as randomUUID21 } from "crypto";
|
|
29512
30054
|
import { mkdtemp as mkdtemp6, rm as rm7 } from "fs/promises";
|
|
29513
|
-
import
|
|
29514
|
-
import
|
|
30055
|
+
import os9 from "os";
|
|
30056
|
+
import path25 from "path";
|
|
29515
30057
|
import {
|
|
29516
30058
|
StorageManager as StorageManager2,
|
|
29517
30059
|
parseConfig as parseConfig3,
|
|
@@ -29641,7 +30183,7 @@ async function runProceduralRecallBenchmark(options) {
|
|
|
29641
30183
|
}
|
|
29642
30184
|
for (const sample of e2eCases) {
|
|
29643
30185
|
const startedAt = performance.now();
|
|
29644
|
-
const dir = await mkdtemp6(
|
|
30186
|
+
const dir = await mkdtemp6(path25.join(os9.tmpdir(), "remnic-bench-procedural-recall-"));
|
|
29645
30187
|
let section = null;
|
|
29646
30188
|
try {
|
|
29647
30189
|
const storage = new StorageManager2(dir);
|
|
@@ -29656,7 +30198,7 @@ ${body}`,
|
|
|
29656
30198
|
);
|
|
29657
30199
|
const config = parseConfig3({
|
|
29658
30200
|
memoryDir: dir,
|
|
29659
|
-
workspaceDir:
|
|
30201
|
+
workspaceDir: path25.join(dir, "ws"),
|
|
29660
30202
|
openaiApiKey: "bench-key",
|
|
29661
30203
|
procedural: {
|
|
29662
30204
|
enabled: sample.proceduralEnabled !== false,
|
|
@@ -29726,9 +30268,9 @@ ${body}`,
|
|
|
29726
30268
|
|
|
29727
30269
|
// src/benchmarks/remnic/ingestion-entity-recall/runner.ts
|
|
29728
30270
|
import { randomUUID as randomUUID22 } from "crypto";
|
|
29729
|
-
import { mkdtemp as mkdtemp7, writeFile as
|
|
30271
|
+
import { mkdtemp as mkdtemp7, writeFile as writeFile11, rm as rm8, mkdir as mkdir11, realpath as realpath5 } from "fs/promises";
|
|
29730
30272
|
import { tmpdir as tmpdir2 } from "os";
|
|
29731
|
-
import
|
|
30273
|
+
import path26 from "path";
|
|
29732
30274
|
|
|
29733
30275
|
// src/ingestion-scorer.ts
|
|
29734
30276
|
function normalize(value) {
|
|
@@ -30230,13 +30772,13 @@ async function runIngestionEntityRecallBenchmark(options) {
|
|
|
30230
30772
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30231
30773
|
}
|
|
30232
30774
|
const fixture = emailFixture.generate();
|
|
30233
|
-
const fixtureDir = await mkdtemp7(
|
|
30775
|
+
const fixtureDir = await mkdtemp7(path26.join(tmpdir2(), "bench-email-"));
|
|
30234
30776
|
try {
|
|
30235
30777
|
await options.ingestionAdapter.reset();
|
|
30236
30778
|
for (const file of fixture.files) {
|
|
30237
|
-
const filePath =
|
|
30238
|
-
await
|
|
30239
|
-
await
|
|
30779
|
+
const filePath = path26.join(fixtureDir, file.relativePath);
|
|
30780
|
+
await mkdir11(path26.dirname(filePath), { recursive: true });
|
|
30781
|
+
await writeFile11(filePath, file.content, "utf8");
|
|
30240
30782
|
}
|
|
30241
30783
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30242
30784
|
async () => options.ingestionAdapter.ingest(await realpath5(fixtureDir))
|
|
@@ -30363,9 +30905,9 @@ async function buildResult(options, tasks, totalLatencyMs) {
|
|
|
30363
30905
|
|
|
30364
30906
|
// src/benchmarks/remnic/ingestion-schema-completeness/runner.ts
|
|
30365
30907
|
import { randomUUID as randomUUID23 } from "crypto";
|
|
30366
|
-
import { mkdtemp as mkdtemp8, writeFile as
|
|
30908
|
+
import { mkdtemp as mkdtemp8, writeFile as writeFile12, rm as rm9, mkdir as mkdir12, realpath as realpath6 } from "fs/promises";
|
|
30367
30909
|
import { tmpdir as tmpdir3 } from "os";
|
|
30368
|
-
import
|
|
30910
|
+
import path27 from "path";
|
|
30369
30911
|
var ingestionSchemaCompletenessDefinition = {
|
|
30370
30912
|
id: "ingestion-schema-completeness",
|
|
30371
30913
|
title: "Ingestion: Schema Completeness",
|
|
@@ -30384,13 +30926,13 @@ async function runIngestionSchemaCompletenessBenchmark(options) {
|
|
|
30384
30926
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30385
30927
|
}
|
|
30386
30928
|
const fixture = emailFixture.generate();
|
|
30387
|
-
const fixtureDir = await mkdtemp8(
|
|
30929
|
+
const fixtureDir = await mkdtemp8(path27.join(tmpdir3(), "bench-email-"));
|
|
30388
30930
|
try {
|
|
30389
30931
|
await options.ingestionAdapter.reset();
|
|
30390
30932
|
for (const file of fixture.files) {
|
|
30391
|
-
const filePath =
|
|
30392
|
-
await
|
|
30393
|
-
await
|
|
30933
|
+
const filePath = path27.join(fixtureDir, file.relativePath);
|
|
30934
|
+
await mkdir12(path27.dirname(filePath), { recursive: true });
|
|
30935
|
+
await writeFile12(filePath, file.content, "utf8");
|
|
30394
30936
|
}
|
|
30395
30937
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30396
30938
|
async () => options.ingestionAdapter.ingest(await realpath6(fixtureDir))
|
|
@@ -30536,9 +31078,9 @@ async function runIngestionSchemaCompletenessBenchmark(options) {
|
|
|
30536
31078
|
|
|
30537
31079
|
// src/benchmarks/remnic/ingestion-backlink-f1/runner.ts
|
|
30538
31080
|
import { randomUUID as randomUUID24 } from "crypto";
|
|
30539
|
-
import { mkdtemp as mkdtemp9, writeFile as
|
|
31081
|
+
import { mkdtemp as mkdtemp9, writeFile as writeFile13, rm as rm10, mkdir as mkdir13, realpath as realpath7 } from "fs/promises";
|
|
30540
31082
|
import { tmpdir as tmpdir4 } from "os";
|
|
30541
|
-
import
|
|
31083
|
+
import path28 from "path";
|
|
30542
31084
|
var ingestionBacklinkF1Definition = {
|
|
30543
31085
|
id: "ingestion-backlink-f1",
|
|
30544
31086
|
title: "Ingestion: Backlink F1",
|
|
@@ -30557,13 +31099,13 @@ async function runIngestionBacklinkF1Benchmark(options) {
|
|
|
30557
31099
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30558
31100
|
}
|
|
30559
31101
|
const fixture = emailFixture.generate();
|
|
30560
|
-
const fixtureDir = await mkdtemp9(
|
|
31102
|
+
const fixtureDir = await mkdtemp9(path28.join(tmpdir4(), "bench-email-"));
|
|
30561
31103
|
try {
|
|
30562
31104
|
await options.ingestionAdapter.reset();
|
|
30563
31105
|
for (const file of fixture.files) {
|
|
30564
|
-
const filePath =
|
|
30565
|
-
await
|
|
30566
|
-
await
|
|
31106
|
+
const filePath = path28.join(fixtureDir, file.relativePath);
|
|
31107
|
+
await mkdir13(path28.dirname(filePath), { recursive: true });
|
|
31108
|
+
await writeFile13(filePath, file.content, "utf8");
|
|
30567
31109
|
}
|
|
30568
31110
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30569
31111
|
async () => options.ingestionAdapter.ingest(await realpath7(fixtureDir))
|
|
@@ -30637,9 +31179,9 @@ async function runIngestionBacklinkF1Benchmark(options) {
|
|
|
30637
31179
|
|
|
30638
31180
|
// src/benchmarks/remnic/ingestion-setup-friction/runner.ts
|
|
30639
31181
|
import { randomUUID as randomUUID25 } from "crypto";
|
|
30640
|
-
import { mkdtemp as mkdtemp10, writeFile as
|
|
31182
|
+
import { mkdtemp as mkdtemp10, writeFile as writeFile14, rm as rm11, mkdir as mkdir14, realpath as realpath8 } from "fs/promises";
|
|
30641
31183
|
import { tmpdir as tmpdir5 } from "os";
|
|
30642
|
-
import
|
|
31184
|
+
import path29 from "path";
|
|
30643
31185
|
var INGESTION_SETUP_FRICTION_LOWER_IS_BETTER = /* @__PURE__ */ new Set(["setup_friction", "commands_count", "prompts_count", "errors_count"]);
|
|
30644
31186
|
var ingestionSetupFrictionDefinition = {
|
|
30645
31187
|
id: "ingestion-setup-friction",
|
|
@@ -30659,13 +31201,13 @@ async function runIngestionSetupFrictionBenchmark(options) {
|
|
|
30659
31201
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30660
31202
|
}
|
|
30661
31203
|
const fixture = emailFixture.generate();
|
|
30662
|
-
const fixtureDir = await mkdtemp10(
|
|
31204
|
+
const fixtureDir = await mkdtemp10(path29.join(tmpdir5(), "bench-friction-"));
|
|
30663
31205
|
try {
|
|
30664
31206
|
await options.ingestionAdapter.reset();
|
|
30665
31207
|
for (const file of fixture.files) {
|
|
30666
|
-
const filePath =
|
|
30667
|
-
await
|
|
30668
|
-
await
|
|
31208
|
+
const filePath = path29.join(fixtureDir, file.relativePath);
|
|
31209
|
+
await mkdir14(path29.dirname(filePath), { recursive: true });
|
|
31210
|
+
await writeFile14(filePath, file.content, "utf8");
|
|
30669
31211
|
}
|
|
30670
31212
|
const { result: ingestionLog, durationMs } = await timed(
|
|
30671
31213
|
async () => options.ingestionAdapter.ingest(await realpath8(fixtureDir))
|
|
@@ -30743,9 +31285,9 @@ async function runIngestionSetupFrictionBenchmark(options) {
|
|
|
30743
31285
|
|
|
30744
31286
|
// src/benchmarks/remnic/ingestion-citation-accuracy/runner.ts
|
|
30745
31287
|
import { randomUUID as randomUUID26 } from "crypto";
|
|
30746
|
-
import { mkdtemp as mkdtemp11, writeFile as
|
|
31288
|
+
import { mkdtemp as mkdtemp11, writeFile as writeFile15, rm as rm12, mkdir as mkdir15, realpath as realpath9 } from "fs/promises";
|
|
30747
31289
|
import { tmpdir as tmpdir6 } from "os";
|
|
30748
|
-
import
|
|
31290
|
+
import path30 from "path";
|
|
30749
31291
|
var CITATION_SUPPORT_THRESHOLD = 0.72;
|
|
30750
31292
|
var ingestionCitationAccuracyDefinition = {
|
|
30751
31293
|
id: "ingestion-citation-accuracy",
|
|
@@ -30804,10 +31346,10 @@ function resolveCitedSources(sourceRefs, seeAlso, pageRef, sourceContentMap) {
|
|
|
30804
31346
|
return "";
|
|
30805
31347
|
}
|
|
30806
31348
|
for (const ref of normalizedRefs) {
|
|
30807
|
-
const refBase =
|
|
31349
|
+
const refBase = path30.basename(ref).toLowerCase();
|
|
30808
31350
|
let matched = false;
|
|
30809
31351
|
for (const [relativePath, content] of sourceContentMap) {
|
|
30810
|
-
if (relativePath === ref || relativePath.endsWith(ref) ||
|
|
31352
|
+
if (relativePath === ref || relativePath.endsWith(ref) || path30.basename(relativePath).toLowerCase() === refBase) {
|
|
30811
31353
|
resolved.push(content);
|
|
30812
31354
|
matched = true;
|
|
30813
31355
|
break;
|
|
@@ -30823,9 +31365,9 @@ function resolveCitedSources(sourceRefs, seeAlso, pageRef, sourceContentMap) {
|
|
|
30823
31365
|
if (normalizedRefs.length > 0) {
|
|
30824
31366
|
return "";
|
|
30825
31367
|
}
|
|
30826
|
-
const pageBase =
|
|
31368
|
+
const pageBase = path30.basename(pageRef).toLowerCase();
|
|
30827
31369
|
for (const [relativePath, content] of sourceContentMap) {
|
|
30828
|
-
if (
|
|
31370
|
+
if (path30.basename(relativePath).toLowerCase() === pageBase) {
|
|
30829
31371
|
return content;
|
|
30830
31372
|
}
|
|
30831
31373
|
}
|
|
@@ -30836,13 +31378,13 @@ async function runIngestionCitationAccuracyBenchmark(options) {
|
|
|
30836
31378
|
throw new Error("ingestionAdapter is required for ingestion benchmarks");
|
|
30837
31379
|
}
|
|
30838
31380
|
const fixture = emailFixture.generate();
|
|
30839
|
-
const fixtureDir = await mkdtemp11(
|
|
31381
|
+
const fixtureDir = await mkdtemp11(path30.join(tmpdir6(), "bench-citation-"));
|
|
30840
31382
|
try {
|
|
30841
31383
|
await options.ingestionAdapter.reset();
|
|
30842
31384
|
for (const file of fixture.files) {
|
|
30843
|
-
const filePath =
|
|
30844
|
-
await
|
|
30845
|
-
await
|
|
31385
|
+
const filePath = path30.join(fixtureDir, file.relativePath);
|
|
31386
|
+
await mkdir15(path30.dirname(filePath), { recursive: true });
|
|
31387
|
+
await writeFile15(filePath, file.content, "utf8");
|
|
30846
31388
|
}
|
|
30847
31389
|
const benchmarkStart = performance.now();
|
|
30848
31390
|
const { result: ingestionLog, durationMs: ingestionDurationMs } = await timed(
|
|
@@ -31227,7 +31769,7 @@ var ASSISTANT_MORNING_BRIEF_SMOKE_SCENARIOS = ASSISTANT_MORNING_BRIEF_SCENARIOS.
|
|
|
31227
31769
|
|
|
31228
31770
|
// src/benchmarks/remnic/_assistant-common/runner.ts
|
|
31229
31771
|
import { randomUUID as randomUUID27 } from "crypto";
|
|
31230
|
-
import
|
|
31772
|
+
import path32 from "path";
|
|
31231
31773
|
|
|
31232
31774
|
// src/run-seeds.ts
|
|
31233
31775
|
function buildBenchmarkRunSeeds(runCount, baseSeed) {
|
|
@@ -31319,7 +31861,7 @@ function pairedDeltaConfidenceInterval(candidateValues, baselineValues, options
|
|
|
31319
31861
|
// src/judges/sealed-rubric.ts
|
|
31320
31862
|
import { createHash as createHash8 } from "crypto";
|
|
31321
31863
|
import { appendFileSync, mkdirSync } from "fs";
|
|
31322
|
-
import
|
|
31864
|
+
import path31 from "path";
|
|
31323
31865
|
|
|
31324
31866
|
// src/judges/sealed-prompts/assistant-rubric-v1.ts
|
|
31325
31867
|
var ASSISTANT_RUBRIC_V1 = `# Assistant rubric v1 (sealed)
|
|
@@ -31599,7 +32141,7 @@ function createSpotCheckFileLogger(options) {
|
|
|
31599
32141
|
return { log() {
|
|
31600
32142
|
} };
|
|
31601
32143
|
}
|
|
31602
|
-
const logPath =
|
|
32144
|
+
const logPath = path31.join(directory, `${runId}.jsonl`);
|
|
31603
32145
|
let written = 0;
|
|
31604
32146
|
let warnedOnWriteFailure = false;
|
|
31605
32147
|
const cap = typeof sampleSize === "number" && sampleSize > 0 ? sampleSize : 5;
|
|
@@ -31688,7 +32230,7 @@ async function runAssistantBenchmark(definition, scenarios, resolved, runnerOpti
|
|
|
31688
32230
|
const runId = buildRunId(definition.id);
|
|
31689
32231
|
const spotCheckLogger = createSpotCheckFileLogger({
|
|
31690
32232
|
runId,
|
|
31691
|
-
directory: runnerOptions.spotCheckDir ??
|
|
32233
|
+
directory: runnerOptions.spotCheckDir ?? path32.join(process.cwd(), "benchmarks", "results", "spot-checks"),
|
|
31692
32234
|
sampleRate: 0.35,
|
|
31693
32235
|
sampleSize: 5
|
|
31694
32236
|
});
|
|
@@ -32337,9 +32879,9 @@ async function runAssistantSynthesisBenchmark(options) {
|
|
|
32337
32879
|
|
|
32338
32880
|
// src/benchmarks/remnic/buffer-surprise-trigger/runner.ts
|
|
32339
32881
|
import { randomUUID as randomUUID28 } from "crypto";
|
|
32340
|
-
import
|
|
32341
|
-
import
|
|
32342
|
-
import { mkdir as
|
|
32882
|
+
import path33 from "path";
|
|
32883
|
+
import os10 from "os";
|
|
32884
|
+
import { mkdir as mkdir16, rm as rm13 } from "fs/promises";
|
|
32343
32885
|
import {
|
|
32344
32886
|
SmartBuffer,
|
|
32345
32887
|
computeSurprise,
|
|
@@ -32568,11 +33110,11 @@ function hasExplicitTopicPivotCue(text) {
|
|
|
32568
33110
|
}
|
|
32569
33111
|
async function runBufferSurpriseTriggerBenchmark(options) {
|
|
32570
33112
|
const cases = loadCases10(options.mode, options.limit);
|
|
32571
|
-
const tmpRoot =
|
|
32572
|
-
|
|
33113
|
+
const tmpRoot = path33.join(
|
|
33114
|
+
os10.tmpdir(),
|
|
32573
33115
|
`remnic-bench-buffer-surprise-${randomUUID28()}`
|
|
32574
33116
|
);
|
|
32575
|
-
await
|
|
33117
|
+
await mkdir16(tmpRoot, { recursive: true });
|
|
32576
33118
|
const tasks = [];
|
|
32577
33119
|
const startedAt = performance.now();
|
|
32578
33120
|
try {
|
|
@@ -32637,12 +33179,12 @@ async function runBufferSurpriseTriggerBenchmark(options) {
|
|
|
32637
33179
|
};
|
|
32638
33180
|
}
|
|
32639
33181
|
async function runSingleCase(caseDef, options) {
|
|
32640
|
-
const memoryDir =
|
|
33182
|
+
const memoryDir = path33.join(
|
|
32641
33183
|
options.tmpRoot,
|
|
32642
33184
|
`${caseDef.id}-${options.label}`
|
|
32643
33185
|
);
|
|
32644
|
-
const workspaceDir =
|
|
32645
|
-
await
|
|
33186
|
+
const workspaceDir = path33.join(memoryDir, "workspace");
|
|
33187
|
+
await mkdir16(workspaceDir, { recursive: true });
|
|
32646
33188
|
const config = parseConfig4({
|
|
32647
33189
|
memoryDir,
|
|
32648
33190
|
workspaceDir,
|
|
@@ -34904,8 +35446,8 @@ async function runMemCorrectBenchmark(options) {
|
|
|
34904
35446
|
|
|
34905
35447
|
// src/benchmarks/remnic/bounded-memory-contracts/runner.ts
|
|
34906
35448
|
import { randomUUID as randomUUID32 } from "crypto";
|
|
34907
|
-
import { mkdir as
|
|
34908
|
-
import
|
|
35449
|
+
import { mkdir as mkdir17, writeFile as writeFile16 } from "fs/promises";
|
|
35450
|
+
import path34 from "path";
|
|
34909
35451
|
|
|
34910
35452
|
// src/benchmarks/remnic/bounded-memory-contracts/fixture.ts
|
|
34911
35453
|
import { createHash as createHash10 } from "crypto";
|
|
@@ -36137,24 +36679,24 @@ async function runBoundedMemoryContractsBenchmark(options) {
|
|
|
36137
36679
|
};
|
|
36138
36680
|
}
|
|
36139
36681
|
async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks) {
|
|
36140
|
-
const root =
|
|
36141
|
-
await
|
|
36142
|
-
await
|
|
36143
|
-
await
|
|
36144
|
-
await
|
|
36682
|
+
const root = path34.resolve(outputDir);
|
|
36683
|
+
await mkdir17(path34.join(root, "conditions"), { recursive: true });
|
|
36684
|
+
await mkdir17(path34.join(root, "prompts"), { recursive: true });
|
|
36685
|
+
await mkdir17(path34.join(root, "retrieval"), { recursive: true });
|
|
36686
|
+
await mkdir17(path34.join(root, "scores"), { recursive: true });
|
|
36145
36687
|
const csvRows = [
|
|
36146
36688
|
"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
36689
|
];
|
|
36148
36690
|
for (const condition of BOUNDED_MEMORY_CONDITIONS) {
|
|
36149
36691
|
const results = byCondition.get(condition);
|
|
36150
|
-
const condDir =
|
|
36151
|
-
await
|
|
36692
|
+
const condDir = path34.join(root, "conditions", condition);
|
|
36693
|
+
await mkdir17(condDir, { recursive: true });
|
|
36152
36694
|
for (const { task, pack, decision } of results) {
|
|
36153
36695
|
const scores = scoreTaskPair(task, pack, decision);
|
|
36154
36696
|
const promptMd = renderPromptPack(task, condition, pack);
|
|
36155
|
-
const promptPath =
|
|
36156
|
-
await
|
|
36157
|
-
await
|
|
36697
|
+
const promptPath = path34.join(root, "prompts", `${task.id}.${condition}.md`);
|
|
36698
|
+
await mkdir17(path34.dirname(promptPath), { recursive: true });
|
|
36699
|
+
await writeFile16(promptPath, promptMd, "utf8");
|
|
36158
36700
|
const retrievalJson = `${JSON.stringify(
|
|
36159
36701
|
{
|
|
36160
36702
|
taskId: task.id,
|
|
@@ -36177,8 +36719,8 @@ async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks
|
|
|
36177
36719
|
2
|
|
36178
36720
|
)}
|
|
36179
36721
|
`;
|
|
36180
|
-
const retrievalPath =
|
|
36181
|
-
await
|
|
36722
|
+
const retrievalPath = path34.join(root, "retrieval", `${task.id}.${condition}.json`);
|
|
36723
|
+
await writeFile16(retrievalPath, retrievalJson, "utf8");
|
|
36182
36724
|
csvRows.push(
|
|
36183
36725
|
[
|
|
36184
36726
|
task.id,
|
|
@@ -36198,24 +36740,24 @@ async function writeArtifacts(outputDir, byCondition, conditionAggregates, tasks
|
|
|
36198
36740
|
].join(",")
|
|
36199
36741
|
);
|
|
36200
36742
|
}
|
|
36201
|
-
await
|
|
36202
|
-
|
|
36743
|
+
await writeFile16(
|
|
36744
|
+
path34.join(condDir, "summary.json"),
|
|
36203
36745
|
`${JSON.stringify(conditionAggregates[condition], null, 2)}
|
|
36204
36746
|
`,
|
|
36205
36747
|
"utf8"
|
|
36206
36748
|
);
|
|
36207
36749
|
}
|
|
36208
|
-
await
|
|
36750
|
+
await writeFile16(path34.join(root, "scores", "per-task.csv"), `${csvRows.join("\n")}
|
|
36209
36751
|
`, "utf8");
|
|
36210
|
-
await
|
|
36211
|
-
|
|
36752
|
+
await writeFile16(
|
|
36753
|
+
path34.join(root, "scores", "aggregate.json"),
|
|
36212
36754
|
`${JSON.stringify(conditionAggregates, null, 2)}
|
|
36213
36755
|
`,
|
|
36214
36756
|
"utf8"
|
|
36215
36757
|
);
|
|
36216
36758
|
const report = renderReportMarkdown(tasks, conditionAggregates);
|
|
36217
|
-
await
|
|
36218
|
-
return
|
|
36759
|
+
await writeFile16(path34.join(root, "report.md"), report, "utf8");
|
|
36760
|
+
return path34.join(root, "report.md");
|
|
36219
36761
|
}
|
|
36220
36762
|
function renderPromptPack(task, condition, pack) {
|
|
36221
36763
|
const lines = [];
|
|
@@ -36440,8 +36982,8 @@ function finalizeBenchmarkResultConfig(result, options) {
|
|
|
36440
36982
|
}
|
|
36441
36983
|
|
|
36442
36984
|
// src/benchmark.ts
|
|
36443
|
-
var DEFAULT_BASELINE_PATH =
|
|
36444
|
-
var DEFAULT_REPORT_PATH =
|
|
36985
|
+
var DEFAULT_BASELINE_PATH = path35.join(process.cwd(), "benchmarks", "baseline.json");
|
|
36986
|
+
var DEFAULT_REPORT_PATH = path35.join(process.cwd(), "benchmarks", "report.json");
|
|
36445
36987
|
var BASELINE_VERSION = 1;
|
|
36446
36988
|
var DEFAULT_TOLERANCE = 10;
|
|
36447
36989
|
var DEFAULT_FULL_RUN_COUNT = 5;
|
|
@@ -36519,7 +37061,7 @@ async function runBenchmark(benchmarkId, options) {
|
|
|
36519
37061
|
if (!willWrapPrimary && !willWrapCross) {
|
|
36520
37062
|
return void 0;
|
|
36521
37063
|
}
|
|
36522
|
-
const cacheDir = options.judgeCacheDir ?
|
|
37064
|
+
const cacheDir = options.judgeCacheDir ? path35.resolve(expandTildePath3(options.judgeCacheDir)) : options.outputDir ? path35.join(path35.resolve(expandTildePath3(options.outputDir)), "judge-cache") : void 0;
|
|
36523
37065
|
if (cacheDir === void 0) {
|
|
36524
37066
|
return void 0;
|
|
36525
37067
|
}
|
|
@@ -36718,7 +37260,7 @@ function loadBaseline(baselinePath) {
|
|
|
36718
37260
|
return raw;
|
|
36719
37261
|
}
|
|
36720
37262
|
function saveBaseline(baselinePath, baseline) {
|
|
36721
|
-
fs2.mkdirSync(
|
|
37263
|
+
fs2.mkdirSync(path35.dirname(baselinePath), { recursive: true });
|
|
36722
37264
|
fs2.writeFileSync(baselinePath, `${JSON.stringify(baseline, null, 2)}
|
|
36723
37265
|
`);
|
|
36724
37266
|
}
|
|
@@ -36948,7 +37490,7 @@ function generateReport(results, reportPath) {
|
|
|
36948
37490
|
totalDurationMs: results.reduce((sum, result) => sum + result.totalDurationMs, 0)
|
|
36949
37491
|
};
|
|
36950
37492
|
if (reportPath) {
|
|
36951
|
-
fs2.mkdirSync(
|
|
37493
|
+
fs2.mkdirSync(path35.dirname(reportPath), { recursive: true });
|
|
36952
37494
|
fs2.writeFileSync(reportPath, `${JSON.stringify(report, null, 2)}
|
|
36953
37495
|
`);
|
|
36954
37496
|
}
|
|
@@ -37363,7 +37905,7 @@ function formatSignedScore(value) {
|
|
|
37363
37905
|
}
|
|
37364
37906
|
|
|
37365
37907
|
// src/integrity/sealed-qrels.ts
|
|
37366
|
-
import { readFile as
|
|
37908
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
37367
37909
|
function isSealedQrelsArtifact(value) {
|
|
37368
37910
|
if (!value || typeof value !== "object") {
|
|
37369
37911
|
return false;
|
|
@@ -37433,7 +37975,7 @@ function parseSealedQrels(raw, options = {}) {
|
|
|
37433
37975
|
};
|
|
37434
37976
|
}
|
|
37435
37977
|
async function loadSealedQrels(filePath, options = {}) {
|
|
37436
|
-
const raw = await
|
|
37978
|
+
const raw = await readFile20(filePath, "utf8");
|
|
37437
37979
|
return parseSealedQrels(raw, options);
|
|
37438
37980
|
}
|
|
37439
37981
|
function serializeSealedQrels(artifact) {
|
|
@@ -37553,7 +38095,7 @@ function selectFixtureVariant(variants, seed) {
|
|
|
37553
38095
|
}
|
|
37554
38096
|
|
|
37555
38097
|
// src/benchmarks/custom/loader.ts
|
|
37556
|
-
import { readFile as
|
|
38098
|
+
import { readFile as readFile21 } from "fs/promises";
|
|
37557
38099
|
import { parse as parseYaml } from "yaml";
|
|
37558
38100
|
var CUSTOM_SCORING_VALUES = /* @__PURE__ */ new Set([
|
|
37559
38101
|
"exact_match",
|
|
@@ -37573,7 +38115,7 @@ function parseCustomBenchmark(source) {
|
|
|
37573
38115
|
async function loadCustomBenchmarkFile(filePath) {
|
|
37574
38116
|
let source;
|
|
37575
38117
|
try {
|
|
37576
|
-
source = await
|
|
38118
|
+
source = await readFile21(filePath, "utf8");
|
|
37577
38119
|
} catch (error) {
|
|
37578
38120
|
throw new Error(
|
|
37579
38121
|
`Failed to read custom benchmark file ${filePath}: ${formatError(error)}`
|
|
@@ -37681,7 +38223,7 @@ function formatError(error) {
|
|
|
37681
38223
|
|
|
37682
38224
|
// src/benchmarks/custom/runner.ts
|
|
37683
38225
|
import { randomUUID as randomUUID33 } from "crypto";
|
|
37684
|
-
import
|
|
38226
|
+
import path36 from "path";
|
|
37685
38227
|
import { expandTildePath as expandTildePath4 } from "@remnic/core";
|
|
37686
38228
|
async function runCustomBenchmarkFile(filePath, options) {
|
|
37687
38229
|
const spec = await loadCustomBenchmarkFile(filePath);
|
|
@@ -37694,7 +38236,7 @@ async function runCustomBenchmarkFile(filePath, options) {
|
|
|
37694
38236
|
let cacheRestore;
|
|
37695
38237
|
let cacheCounters;
|
|
37696
38238
|
if (spec.scoring === "llm_judge" && runOptions.system.judge !== void 0 && !runOptions.noJudgeCache && (runOptions.judgeProvider ?? null) !== null) {
|
|
37697
|
-
const cacheDir = runOptions.judgeCacheDir ?
|
|
38239
|
+
const cacheDir = runOptions.judgeCacheDir ? path36.resolve(expandTildePath4(runOptions.judgeCacheDir)) : runOptions.outputDir ? path36.join(path36.resolve(expandTildePath4(runOptions.outputDir)), "judge-cache") : void 0;
|
|
37698
38240
|
if (cacheDir !== void 0) {
|
|
37699
38241
|
const originalJudge = runOptions.system.judge;
|
|
37700
38242
|
const wrapped = wrapJudgeWithCache({
|
|
@@ -37895,7 +38437,7 @@ async function scoreTask(scoring, options, question, actual, expected) {
|
|
|
37895
38437
|
}
|
|
37896
38438
|
}
|
|
37897
38439
|
function createCustomBenchmarkDefinition(benchmark, filePath) {
|
|
37898
|
-
const id = `custom:${slugify(
|
|
38440
|
+
const id = `custom:${slugify(path36.basename(filePath, path36.extname(filePath)) || benchmark.name)}`;
|
|
37899
38441
|
return {
|
|
37900
38442
|
id,
|
|
37901
38443
|
title: benchmark.name,
|
|
@@ -38766,8 +39308,8 @@ var chatFixture = {
|
|
|
38766
39308
|
|
|
38767
39309
|
// src/judges/calibration-slice.ts
|
|
38768
39310
|
import { createHash as createHash12, randomBytes as randomBytes3 } from "crypto";
|
|
38769
|
-
import { mkdir as
|
|
38770
|
-
import
|
|
39311
|
+
import { mkdir as mkdir18, readFile as readFile22, rename as rename4, unlink as unlink4, writeFile as writeFile17 } from "fs/promises";
|
|
39312
|
+
import path37 from "path";
|
|
38771
39313
|
|
|
38772
39314
|
// src/judges/cohen-kappa.ts
|
|
38773
39315
|
var DEFAULT_KAPPA_BOOTSTRAP_SAMPLES = 2e3;
|
|
@@ -38995,7 +39537,7 @@ function hashCalibrationAnswerSet(answers) {
|
|
|
38995
39537
|
]))).digest("hex");
|
|
38996
39538
|
}
|
|
38997
39539
|
async function writeJudgeCalibrationState(result, calibrationDir, identities, provenance) {
|
|
38998
|
-
await
|
|
39540
|
+
await mkdir18(calibrationDir, { recursive: true });
|
|
38999
39541
|
const state = {
|
|
39000
39542
|
kappa: result.kappa,
|
|
39001
39543
|
sampleSize: result.sampleSize,
|
|
@@ -39008,23 +39550,23 @@ async function writeJudgeCalibrationState(result, calibrationDir, identities, pr
|
|
|
39008
39550
|
...provenance ? provenance : {},
|
|
39009
39551
|
...identities ? identities : {}
|
|
39010
39552
|
};
|
|
39011
|
-
const filePath =
|
|
39553
|
+
const filePath = path37.join(calibrationDir, `${sanitizeCalibrationSegment(result.benchmarkId)}.json`);
|
|
39012
39554
|
const tempPath = `${filePath}.${randomBytes3(6).toString("hex")}.tmp`;
|
|
39013
|
-
await
|
|
39555
|
+
await writeFile17(tempPath, `${JSON.stringify(state, null, 2)}
|
|
39014
39556
|
`, "utf8");
|
|
39015
39557
|
try {
|
|
39016
|
-
await
|
|
39558
|
+
await rename4(tempPath, filePath);
|
|
39017
39559
|
} catch (error) {
|
|
39018
|
-
await
|
|
39560
|
+
await unlink4(tempPath).catch(() => void 0);
|
|
39019
39561
|
throw error;
|
|
39020
39562
|
}
|
|
39021
39563
|
return filePath;
|
|
39022
39564
|
}
|
|
39023
39565
|
async function loadJudgeCalibrationState(benchmarkId, calibrationDir) {
|
|
39024
|
-
const filePath =
|
|
39566
|
+
const filePath = path37.join(calibrationDir, `${sanitizeCalibrationSegment(benchmarkId)}.json`);
|
|
39025
39567
|
let raw;
|
|
39026
39568
|
try {
|
|
39027
|
-
raw = await
|
|
39569
|
+
raw = await readFile22(filePath, "utf8");
|
|
39028
39570
|
} catch {
|
|
39029
39571
|
return void 0;
|
|
39030
39572
|
}
|
|
@@ -39108,9 +39650,9 @@ function sanitizeCalibrationSegment(value) {
|
|
|
39108
39650
|
}
|
|
39109
39651
|
|
|
39110
39652
|
// src/benchmarks/remnic/procedural-recall/ablation.ts
|
|
39111
|
-
import { mkdir as
|
|
39112
|
-
import
|
|
39113
|
-
import
|
|
39653
|
+
import { mkdir as mkdir19, mkdtemp as mkdtemp12, rm as rm14, writeFile as writeFile18, readFile as readFile23 } from "fs/promises";
|
|
39654
|
+
import os11 from "os";
|
|
39655
|
+
import path38 from "path";
|
|
39114
39656
|
import {
|
|
39115
39657
|
StorageManager as StorageManager3,
|
|
39116
39658
|
parseConfig as parseConfig5,
|
|
@@ -39141,7 +39683,7 @@ async function runSide(scenarios, proceduralEnabled) {
|
|
|
39141
39683
|
const observed = [];
|
|
39142
39684
|
for (const scenario of scenarios) {
|
|
39143
39685
|
const dir = await mkdtemp12(
|
|
39144
|
-
|
|
39686
|
+
path38.join(os11.tmpdir(), "remnic-bench-proc-ablation-")
|
|
39145
39687
|
);
|
|
39146
39688
|
try {
|
|
39147
39689
|
const storage = new StorageManager3(dir);
|
|
@@ -39156,7 +39698,7 @@ ${body}`,
|
|
|
39156
39698
|
);
|
|
39157
39699
|
const config = parseConfig5({
|
|
39158
39700
|
memoryDir: dir,
|
|
39159
|
-
workspaceDir:
|
|
39701
|
+
workspaceDir: path38.join(dir, "ws"),
|
|
39160
39702
|
openaiApiKey: "bench-key",
|
|
39161
39703
|
procedural: {
|
|
39162
39704
|
enabled: proceduralEnabled,
|
|
@@ -39231,7 +39773,7 @@ async function runProceduralAblation(options) {
|
|
|
39231
39773
|
};
|
|
39232
39774
|
}
|
|
39233
39775
|
async function loadAblationFixture(fixturePath) {
|
|
39234
|
-
const raw = await
|
|
39776
|
+
const raw = await readFile23(fixturePath, "utf8");
|
|
39235
39777
|
let parsed;
|
|
39236
39778
|
try {
|
|
39237
39779
|
parsed = JSON.parse(raw);
|
|
@@ -39327,9 +39869,9 @@ async function runProceduralAblationCli(args) {
|
|
|
39327
39869
|
random: args.random,
|
|
39328
39870
|
seed: args.seed
|
|
39329
39871
|
});
|
|
39330
|
-
const outDir =
|
|
39331
|
-
await
|
|
39332
|
-
await
|
|
39872
|
+
const outDir = path38.dirname(path38.resolve(args.outPath));
|
|
39873
|
+
await mkdir19(outDir, { recursive: true });
|
|
39874
|
+
await writeFile18(args.outPath, JSON.stringify(artifact, null, 2) + "\n", "utf8");
|
|
39333
39875
|
return artifact;
|
|
39334
39876
|
}
|
|
39335
39877
|
|
|
@@ -40570,8 +41112,8 @@ import { performance as performance2 } from "perf_hooks";
|
|
|
40570
41112
|
import { mkdtemp as mkdtemp13, rm as rm15 } from "fs/promises";
|
|
40571
41113
|
import { statSync } from "fs";
|
|
40572
41114
|
import { tmpdir as tmpdir7 } from "os";
|
|
40573
|
-
import
|
|
40574
|
-
import
|
|
41115
|
+
import path39 from "path";
|
|
41116
|
+
import os12 from "os";
|
|
40575
41117
|
import {
|
|
40576
41118
|
GraphStore
|
|
40577
41119
|
} from "@remnic/coding-graph";
|
|
@@ -40597,14 +41139,14 @@ var CODING_GRAPH_BENCH_SCHEMA_VERSION = 2;
|
|
|
40597
41139
|
|
|
40598
41140
|
// src/coding-graph/harness.ts
|
|
40599
41141
|
function captureMachineFingerprint() {
|
|
40600
|
-
const cpus =
|
|
41142
|
+
const cpus = os12.cpus();
|
|
40601
41143
|
return {
|
|
40602
41144
|
arch: process.arch,
|
|
40603
41145
|
platform: process.platform,
|
|
40604
41146
|
nodeVersion: process.version,
|
|
40605
41147
|
cpuModel: cpus.length > 0 ? cpus[0].model : null,
|
|
40606
41148
|
cpuCores: cpus.length,
|
|
40607
|
-
totalMemoryMb: Math.round(
|
|
41149
|
+
totalMemoryMb: Math.round(os12.totalmem() / (1024 * 1024))
|
|
40608
41150
|
};
|
|
40609
41151
|
}
|
|
40610
41152
|
function percentile3(sorted, p) {
|
|
@@ -40667,15 +41209,15 @@ async function runCodingGraphBenchmark(config = {}) {
|
|
|
40667
41209
|
const sampleRss = () => {
|
|
40668
41210
|
peakRss = Math.max(peakRss, process.memoryUsage().rss);
|
|
40669
41211
|
};
|
|
40670
|
-
const dir = await mkdtemp13(
|
|
40671
|
-
const dbPath =
|
|
41212
|
+
const dir = await mkdtemp13(path39.join(tmpdir7(), "coding-graph-bench-"));
|
|
41213
|
+
const dbPath = path39.join(dir, "bench.sqlite");
|
|
40672
41214
|
try {
|
|
40673
41215
|
const store = await GraphStore.open({ dbPath });
|
|
40674
41216
|
try {
|
|
40675
41217
|
const FULL_INDEX_SAMPLES = 3;
|
|
40676
41218
|
const fullIndexSamples = [];
|
|
40677
41219
|
for (let s = 0; s < FULL_INDEX_SAMPLES; s++) {
|
|
40678
|
-
const sampleStore = s === 0 ? store : await GraphStore.open({ dbPath:
|
|
41220
|
+
const sampleStore = s === 0 ? store : await GraphStore.open({ dbPath: path39.join(dir, `bench-warm-${s}.sqlite`) });
|
|
40679
41221
|
const fi = await timeAsync(() => sampleStore.upsertFileBatch(storeFiles));
|
|
40680
41222
|
if (!fi.result.ok) {
|
|
40681
41223
|
if (sampleStore !== store) await sampleStore.close();
|
|
@@ -41067,6 +41609,7 @@ export {
|
|
|
41067
41609
|
SEALED_PROMPT_REGISTRY,
|
|
41068
41610
|
SINGLE_FLAG_ABLATION_MATRIX,
|
|
41069
41611
|
SYNTHETIC_MEMORIES,
|
|
41612
|
+
StructuredJudgeError,
|
|
41070
41613
|
ZepMemCorrectAdapter,
|
|
41071
41614
|
addContaminationEntry,
|
|
41072
41615
|
aggregateTaskScores,
|
|
@@ -41140,6 +41683,7 @@ export {
|
|
|
41140
41683
|
createResponderFromProvider,
|
|
41141
41684
|
createSeededRng,
|
|
41142
41685
|
createSpotCheckFileLogger,
|
|
41686
|
+
createStructuredBenchJudge,
|
|
41143
41687
|
createStructuredJudgeFromProvider,
|
|
41144
41688
|
createSyntheticEmailIngestionAdapter,
|
|
41145
41689
|
createSyntheticTarget,
|
|
@@ -41177,6 +41721,7 @@ export {
|
|
|
41177
41721
|
isContaminationManifest,
|
|
41178
41722
|
isSealedQrelsArtifact,
|
|
41179
41723
|
isSha256Hex,
|
|
41724
|
+
isStructuredJudgeProvider,
|
|
41180
41725
|
judgeMemCorrectCorrectionAcceptance,
|
|
41181
41726
|
judgeMemCorrectStaleMemoryHarm,
|
|
41182
41727
|
linkMatches,
|