@fre4x/benchmark 1.1.0-beta.0 → 1.1.0-beta.3
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 +122 -18
- package/dist/fallback-catalog.json +613 -0
- package/dist/index.js +1218 -343
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3223,8 +3223,8 @@ var require_utils = __commonJS({
|
|
|
3223
3223
|
}
|
|
3224
3224
|
return ind;
|
|
3225
3225
|
}
|
|
3226
|
-
function removeDotSegments(
|
|
3227
|
-
let input =
|
|
3226
|
+
function removeDotSegments(path4) {
|
|
3227
|
+
let input = path4;
|
|
3228
3228
|
const output = [];
|
|
3229
3229
|
let nextSlash = -1;
|
|
3230
3230
|
let len = 0;
|
|
@@ -3423,8 +3423,8 @@ var require_schemes = __commonJS({
|
|
|
3423
3423
|
wsComponent.secure = void 0;
|
|
3424
3424
|
}
|
|
3425
3425
|
if (wsComponent.resourceName) {
|
|
3426
|
-
const [
|
|
3427
|
-
wsComponent.path =
|
|
3426
|
+
const [path4, query] = wsComponent.resourceName.split("?");
|
|
3427
|
+
wsComponent.path = path4 && path4 !== "/" ? path4 : void 0;
|
|
3428
3428
|
wsComponent.query = query;
|
|
3429
3429
|
wsComponent.resourceName = void 0;
|
|
3430
3430
|
}
|
|
@@ -7878,10 +7878,10 @@ function mergeDefs(...defs) {
|
|
|
7878
7878
|
function cloneDef(schema) {
|
|
7879
7879
|
return mergeDefs(schema._zod.def);
|
|
7880
7880
|
}
|
|
7881
|
-
function getElementAtPath(obj,
|
|
7882
|
-
if (!
|
|
7881
|
+
function getElementAtPath(obj, path4) {
|
|
7882
|
+
if (!path4)
|
|
7883
7883
|
return obj;
|
|
7884
|
-
return
|
|
7884
|
+
return path4.reduce((acc, key) => acc?.[key], obj);
|
|
7885
7885
|
}
|
|
7886
7886
|
function promiseAllObject(promisesObj) {
|
|
7887
7887
|
const keys = Object.keys(promisesObj);
|
|
@@ -8264,11 +8264,11 @@ function aborted(x, startIndex = 0) {
|
|
|
8264
8264
|
}
|
|
8265
8265
|
return false;
|
|
8266
8266
|
}
|
|
8267
|
-
function prefixIssues(
|
|
8267
|
+
function prefixIssues(path4, issues) {
|
|
8268
8268
|
return issues.map((iss) => {
|
|
8269
8269
|
var _a2;
|
|
8270
8270
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
8271
|
-
iss.path.unshift(
|
|
8271
|
+
iss.path.unshift(path4);
|
|
8272
8272
|
return iss;
|
|
8273
8273
|
});
|
|
8274
8274
|
}
|
|
@@ -8451,7 +8451,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
|
|
|
8451
8451
|
}
|
|
8452
8452
|
function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
8453
8453
|
const result = { errors: [] };
|
|
8454
|
-
const processError = (error49,
|
|
8454
|
+
const processError = (error49, path4 = []) => {
|
|
8455
8455
|
var _a2, _b;
|
|
8456
8456
|
for (const issue2 of error49.issues) {
|
|
8457
8457
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
@@ -8461,7 +8461,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
8461
8461
|
} else if (issue2.code === "invalid_element") {
|
|
8462
8462
|
processError({ issues: issue2.issues }, issue2.path);
|
|
8463
8463
|
} else {
|
|
8464
|
-
const fullpath = [...
|
|
8464
|
+
const fullpath = [...path4, ...issue2.path];
|
|
8465
8465
|
if (fullpath.length === 0) {
|
|
8466
8466
|
result.errors.push(mapper(issue2));
|
|
8467
8467
|
continue;
|
|
@@ -8493,8 +8493,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
|
|
|
8493
8493
|
}
|
|
8494
8494
|
function toDotPath(_path) {
|
|
8495
8495
|
const segs = [];
|
|
8496
|
-
const
|
|
8497
|
-
for (const seg of
|
|
8496
|
+
const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
8497
|
+
for (const seg of path4) {
|
|
8498
8498
|
if (typeof seg === "number")
|
|
8499
8499
|
segs.push(`[${seg}]`);
|
|
8500
8500
|
else if (typeof seg === "symbol")
|
|
@@ -20471,13 +20471,13 @@ function resolveRef(ref, ctx) {
|
|
|
20471
20471
|
if (!ref.startsWith("#")) {
|
|
20472
20472
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
20473
20473
|
}
|
|
20474
|
-
const
|
|
20475
|
-
if (
|
|
20474
|
+
const path4 = ref.slice(1).split("/").filter(Boolean);
|
|
20475
|
+
if (path4.length === 0) {
|
|
20476
20476
|
return ctx.rootSchema;
|
|
20477
20477
|
}
|
|
20478
20478
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
20479
|
-
if (
|
|
20480
|
-
const key =
|
|
20479
|
+
if (path4[0] === defsKey) {
|
|
20480
|
+
const key = path4[1];
|
|
20481
20481
|
if (!key || !ctx.defs[key]) {
|
|
20482
20482
|
throw new Error(`Reference not found: ${ref}`);
|
|
20483
20483
|
}
|
|
@@ -21269,8 +21269,8 @@ function getErrorMap2() {
|
|
|
21269
21269
|
|
|
21270
21270
|
// ../node_modules/zod/v3/helpers/parseUtil.js
|
|
21271
21271
|
var makeIssue = (params) => {
|
|
21272
|
-
const { data, path:
|
|
21273
|
-
const fullPath = [...
|
|
21272
|
+
const { data, path: path4, errorMaps, issueData } = params;
|
|
21273
|
+
const fullPath = [...path4, ...issueData.path || []];
|
|
21274
21274
|
const fullIssue = {
|
|
21275
21275
|
...issueData,
|
|
21276
21276
|
path: fullPath
|
|
@@ -21385,11 +21385,11 @@ var errorUtil;
|
|
|
21385
21385
|
|
|
21386
21386
|
// ../node_modules/zod/v3/types.js
|
|
21387
21387
|
var ParseInputLazyPath = class {
|
|
21388
|
-
constructor(parent, value,
|
|
21388
|
+
constructor(parent, value, path4, key) {
|
|
21389
21389
|
this._cachedPath = [];
|
|
21390
21390
|
this.parent = parent;
|
|
21391
21391
|
this.data = value;
|
|
21392
|
-
this._path =
|
|
21392
|
+
this._path = path4;
|
|
21393
21393
|
this._key = key;
|
|
21394
21394
|
}
|
|
21395
21395
|
get path() {
|
|
@@ -30432,45 +30432,161 @@ var StdioServerTransport = class {
|
|
|
30432
30432
|
}
|
|
30433
30433
|
};
|
|
30434
30434
|
|
|
30435
|
-
// src/
|
|
30436
|
-
import {
|
|
30435
|
+
// src/attemptStore.ts
|
|
30436
|
+
import { randomUUID } from "node:crypto";
|
|
30437
|
+
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
30438
|
+
import os from "node:os";
|
|
30439
|
+
import path from "node:path";
|
|
30437
30440
|
|
|
30438
30441
|
// src/types.ts
|
|
30439
|
-
var
|
|
30440
|
-
|
|
30441
|
-
|
|
30442
|
-
|
|
30443
|
-
|
|
30444
|
-
|
|
30445
|
-
|
|
30446
|
-
|
|
30447
|
-
|
|
30448
|
-
|
|
30442
|
+
var primitiveValueSchema = external_exports.union([external_exports.string(), external_exports.number(), external_exports.boolean()]);
|
|
30443
|
+
var benchmarkFamilySchema = external_exports.enum(["code", "web", "os"]);
|
|
30444
|
+
var runnerKindSchema = external_exports.enum([
|
|
30445
|
+
"code_runner",
|
|
30446
|
+
"browser_runner",
|
|
30447
|
+
"os_runner"
|
|
30448
|
+
]);
|
|
30449
|
+
var responseFormatSchema = external_exports.enum(["text", "json"]);
|
|
30450
|
+
var assetEncodingSchema = external_exports.enum(["utf8", "base64"]);
|
|
30451
|
+
var assetTransportSchema = external_exports.enum(["inline"]);
|
|
30452
|
+
var assetMaterializationSchema = external_exports.enum(["inline", "workspace_file"]);
|
|
30453
|
+
var checkerKindSchema = external_exports.enum([
|
|
30454
|
+
"exact_text",
|
|
30455
|
+
"normalized_text",
|
|
30456
|
+
"regex_match",
|
|
30457
|
+
"contains_all_text",
|
|
30458
|
+
"json_field_equals",
|
|
30459
|
+
"runner_fact_equals",
|
|
30460
|
+
"runner_log_contains_text"
|
|
30461
|
+
]);
|
|
30462
|
+
var catalogModeSchema = external_exports.enum([
|
|
30463
|
+
"builtin",
|
|
30464
|
+
"file",
|
|
30465
|
+
"remote_url",
|
|
30466
|
+
"remote_cache",
|
|
30467
|
+
"mock"
|
|
30468
|
+
]);
|
|
30449
30469
|
var assetSchema = external_exports.object({
|
|
30450
30470
|
asset_id: external_exports.string(),
|
|
30451
30471
|
name: external_exports.string(),
|
|
30452
30472
|
mime_type: external_exports.string(),
|
|
30453
|
-
|
|
30473
|
+
transport: assetTransportSchema.default("inline"),
|
|
30474
|
+
materialization: assetMaterializationSchema.default("inline"),
|
|
30475
|
+
encoding: assetEncodingSchema.default("utf8"),
|
|
30454
30476
|
content: external_exports.string(),
|
|
30455
30477
|
description: external_exports.string().optional()
|
|
30456
30478
|
});
|
|
30457
|
-
var
|
|
30458
|
-
|
|
30479
|
+
var checkerBaseSchema = external_exports.object({
|
|
30480
|
+
checker_id: external_exports.string()
|
|
30481
|
+
});
|
|
30482
|
+
var exactTextCheckerSchema = checkerBaseSchema.extend({
|
|
30483
|
+
kind: external_exports.literal("exact_text"),
|
|
30484
|
+
expected: external_exports.string(),
|
|
30485
|
+
case_sensitive: external_exports.boolean().default(true)
|
|
30486
|
+
});
|
|
30487
|
+
var normalizedTextCheckerSchema = checkerBaseSchema.extend({
|
|
30488
|
+
kind: external_exports.literal("normalized_text"),
|
|
30489
|
+
expected: external_exports.string()
|
|
30490
|
+
});
|
|
30491
|
+
var regexMatchCheckerSchema = checkerBaseSchema.extend({
|
|
30492
|
+
kind: external_exports.literal("regex_match"),
|
|
30493
|
+
pattern: external_exports.string(),
|
|
30494
|
+
flags: external_exports.string().optional()
|
|
30495
|
+
});
|
|
30496
|
+
var containsAllTextCheckerSchema = checkerBaseSchema.extend({
|
|
30497
|
+
kind: external_exports.literal("contains_all_text"),
|
|
30498
|
+
terms: external_exports.array(external_exports.string()).min(1)
|
|
30499
|
+
});
|
|
30500
|
+
var jsonFieldEqualsCheckerSchema = checkerBaseSchema.extend({
|
|
30501
|
+
kind: external_exports.literal("json_field_equals"),
|
|
30502
|
+
field: external_exports.string(),
|
|
30503
|
+
expected: primitiveValueSchema
|
|
30504
|
+
});
|
|
30505
|
+
var runnerFactEqualsCheckerSchema = checkerBaseSchema.extend({
|
|
30506
|
+
kind: external_exports.literal("runner_fact_equals"),
|
|
30507
|
+
fact: external_exports.string(),
|
|
30508
|
+
expected: primitiveValueSchema
|
|
30509
|
+
});
|
|
30510
|
+
var runnerLogContainsTextCheckerSchema = checkerBaseSchema.extend({
|
|
30511
|
+
kind: external_exports.literal("runner_log_contains_text"),
|
|
30512
|
+
terms: external_exports.array(external_exports.string()).min(1)
|
|
30513
|
+
});
|
|
30514
|
+
var checkerSchema = external_exports.discriminatedUnion("kind", [
|
|
30515
|
+
exactTextCheckerSchema,
|
|
30516
|
+
normalizedTextCheckerSchema,
|
|
30517
|
+
regexMatchCheckerSchema,
|
|
30518
|
+
containsAllTextCheckerSchema,
|
|
30519
|
+
jsonFieldEqualsCheckerSchema,
|
|
30520
|
+
runnerFactEqualsCheckerSchema,
|
|
30521
|
+
runnerLogContainsTextCheckerSchema
|
|
30522
|
+
]);
|
|
30523
|
+
var runnerArtifactKindSchema = external_exports.enum([
|
|
30524
|
+
"materialized_asset",
|
|
30525
|
+
"submission",
|
|
30526
|
+
"runner_report"
|
|
30527
|
+
]);
|
|
30528
|
+
var taskSchema = external_exports.object({
|
|
30529
|
+
task_id: external_exports.string(),
|
|
30530
|
+
title: external_exports.string(),
|
|
30459
30531
|
prompt: external_exports.string(),
|
|
30460
|
-
|
|
30461
|
-
grading_mode: external_exports.enum(["exact", "normalized"]).default("normalized"),
|
|
30532
|
+
response_format: responseFormatSchema.default("text"),
|
|
30462
30533
|
difficulty: external_exports.number().int().min(1).max(3),
|
|
30463
|
-
assets: external_exports.array(assetSchema).default([])
|
|
30534
|
+
assets: external_exports.array(assetSchema).default([]),
|
|
30535
|
+
checkers: external_exports.array(checkerSchema).min(1)
|
|
30464
30536
|
});
|
|
30465
|
-
var challengeDefinitionSchema =
|
|
30466
|
-
|
|
30537
|
+
var challengeDefinitionSchema = external_exports.object({
|
|
30538
|
+
challenge_id: external_exports.string(),
|
|
30539
|
+
benchmark_id: external_exports.string(),
|
|
30540
|
+
family: benchmarkFamilySchema,
|
|
30541
|
+
runner_kind: runnerKindSchema,
|
|
30542
|
+
title: external_exports.string(),
|
|
30543
|
+
description: external_exports.string(),
|
|
30544
|
+
version: external_exports.string(),
|
|
30545
|
+
source: external_exports.string().default("external"),
|
|
30546
|
+
tasks: external_exports.array(taskSchema).min(1)
|
|
30467
30547
|
});
|
|
30468
|
-
var
|
|
30469
|
-
|
|
30548
|
+
var challengeSummarySchema = external_exports.object({
|
|
30549
|
+
challenge_id: external_exports.string(),
|
|
30550
|
+
benchmark_id: external_exports.string(),
|
|
30551
|
+
family: benchmarkFamilySchema,
|
|
30552
|
+
runner_kind: runnerKindSchema,
|
|
30553
|
+
title: external_exports.string(),
|
|
30554
|
+
description: external_exports.string(),
|
|
30555
|
+
version: external_exports.string(),
|
|
30556
|
+
source: external_exports.string(),
|
|
30557
|
+
total_tasks: external_exports.number().int().min(1),
|
|
30558
|
+
difficulty_levels: external_exports.array(external_exports.number().int().min(1).max(3)),
|
|
30559
|
+
supports_assets: external_exports.boolean(),
|
|
30560
|
+
checker_kinds: external_exports.array(checkerKindSchema).min(1)
|
|
30561
|
+
});
|
|
30562
|
+
var checkerEvidenceSchema = external_exports.object({
|
|
30563
|
+
checker_id: external_exports.string(),
|
|
30564
|
+
kind: checkerKindSchema,
|
|
30565
|
+
passed: external_exports.boolean(),
|
|
30566
|
+
message: external_exports.string()
|
|
30567
|
+
});
|
|
30568
|
+
var runnerExecutionArtifactSchema = external_exports.object({
|
|
30569
|
+
artifact_id: external_exports.string(),
|
|
30570
|
+
kind: runnerArtifactKindSchema,
|
|
30571
|
+
path: external_exports.string(),
|
|
30572
|
+
mime_type: external_exports.string(),
|
|
30573
|
+
description: external_exports.string().optional()
|
|
30574
|
+
});
|
|
30575
|
+
var runnerExecutionSchema = external_exports.object({
|
|
30576
|
+
runner_kind: runnerKindSchema,
|
|
30577
|
+
workspace_dir: external_exports.string(),
|
|
30578
|
+
logs: external_exports.array(external_exports.string()),
|
|
30579
|
+
facts: external_exports.record(external_exports.string(), primitiveValueSchema),
|
|
30580
|
+
artifacts: external_exports.array(runnerExecutionArtifactSchema)
|
|
30581
|
+
});
|
|
30582
|
+
var evaluationRecordSchema = external_exports.object({
|
|
30583
|
+
task_id: external_exports.string(),
|
|
30470
30584
|
solution: external_exports.string(),
|
|
30471
30585
|
accepted: external_exports.boolean(),
|
|
30472
30586
|
score_delta: external_exports.number().int().min(0),
|
|
30473
|
-
submitted_at: external_exports.string()
|
|
30587
|
+
submitted_at: external_exports.string(),
|
|
30588
|
+
evidence: external_exports.array(checkerEvidenceSchema),
|
|
30589
|
+
execution: runnerExecutionSchema
|
|
30474
30590
|
});
|
|
30475
30591
|
var attemptStatusSchema = external_exports.enum(["active", "completed", "cancelled"]);
|
|
30476
30592
|
var persistedAttemptSchema = external_exports.object({
|
|
@@ -30478,17 +30594,18 @@ var persistedAttemptSchema = external_exports.object({
|
|
|
30478
30594
|
benchmark_id: external_exports.string(),
|
|
30479
30595
|
challenge_id: external_exports.string(),
|
|
30480
30596
|
challenge_title: external_exports.string(),
|
|
30597
|
+
family: benchmarkFamilySchema,
|
|
30598
|
+
runner_kind: runnerKindSchema,
|
|
30481
30599
|
dataset_version: external_exports.string(),
|
|
30600
|
+
source: external_exports.string(),
|
|
30482
30601
|
status: attemptStatusSchema,
|
|
30483
|
-
|
|
30484
|
-
|
|
30602
|
+
revision: external_exports.number().int().min(1),
|
|
30603
|
+
current_task_index: external_exports.number().int().min(0),
|
|
30604
|
+
total_tasks: external_exports.number().int().min(1),
|
|
30485
30605
|
started_at: external_exports.string(),
|
|
30486
30606
|
updated_at: external_exports.string(),
|
|
30487
|
-
|
|
30488
|
-
|
|
30489
|
-
});
|
|
30490
|
-
var persistedAttemptsFileSchema = external_exports.object({
|
|
30491
|
-
attempts: external_exports.array(persistedAttemptSchema)
|
|
30607
|
+
tasks: external_exports.array(taskSchema),
|
|
30608
|
+
evaluations: external_exports.array(evaluationRecordSchema)
|
|
30492
30609
|
});
|
|
30493
30610
|
var listChallengesInputSchema = paginationSchema;
|
|
30494
30611
|
var startChallengeInputSchema = external_exports.object({
|
|
@@ -30496,210 +30613,773 @@ var startChallengeInputSchema = external_exports.object({
|
|
|
30496
30613
|
});
|
|
30497
30614
|
var submitSolutionInputSchema = external_exports.object({
|
|
30498
30615
|
attempt_id: external_exports.string().min(1).describe("Attempt id"),
|
|
30499
|
-
solution: external_exports.string().min(1).describe("Answer text")
|
|
30616
|
+
solution: external_exports.string().min(1).describe("Answer text or JSON")
|
|
30500
30617
|
});
|
|
30501
30618
|
var getAssetInputSchema = external_exports.object({
|
|
30502
30619
|
attempt_id: external_exports.string().min(1).describe("Attempt id"),
|
|
30503
30620
|
asset_id: external_exports.string().min(1).describe("Asset id")
|
|
30504
30621
|
});
|
|
30505
|
-
var getAttemptInputSchema =
|
|
30622
|
+
var getAttemptInputSchema = paginationSchema.extend({
|
|
30506
30623
|
attempt_id: external_exports.string().min(1).describe("Attempt id")
|
|
30507
30624
|
});
|
|
30508
30625
|
var cancelAttemptInputSchema = external_exports.object({
|
|
30509
30626
|
attempt_id: external_exports.string().min(1).describe("Attempt id")
|
|
30510
30627
|
});
|
|
30511
|
-
|
|
30512
|
-
|
|
30513
|
-
|
|
30514
|
-
|
|
30515
|
-
|
|
30516
|
-
|
|
30517
|
-
|
|
30518
|
-
|
|
30519
|
-
|
|
30520
|
-
|
|
30521
|
-
|
|
30522
|
-
|
|
30523
|
-
|
|
30524
|
-
|
|
30525
|
-
|
|
30526
|
-
|
|
30527
|
-
|
|
30528
|
-
|
|
30529
|
-
|
|
30530
|
-
|
|
30531
|
-
|
|
30532
|
-
|
|
30533
|
-
|
|
30534
|
-
|
|
30535
|
-
|
|
30536
|
-
|
|
30537
|
-
|
|
30538
|
-
|
|
30539
|
-
|
|
30540
|
-
"Jon Ortiz,9,7,8",
|
|
30541
|
-
"Asha Singh,7,8,9"
|
|
30542
|
-
].join("\n")
|
|
30543
|
-
}
|
|
30544
|
-
]
|
|
30545
|
-
},
|
|
30546
|
-
{
|
|
30547
|
-
question_id: "gaia-q2",
|
|
30548
|
-
prompt: "Read the attached briefing and reply with the two-word checkpoint callsign in lowercase.",
|
|
30549
|
-
expected_answer: "ember clock",
|
|
30550
|
-
grading_mode: "normalized",
|
|
30551
|
-
difficulty: 2,
|
|
30552
|
-
assets: [
|
|
30553
|
-
{
|
|
30554
|
-
asset_id: "gaia-q2-brief",
|
|
30555
|
-
name: "mission_brief.txt",
|
|
30556
|
-
mime_type: "text/plain",
|
|
30557
|
-
encoding: "utf8",
|
|
30558
|
-
description: "Briefing memo with a repeated callsign.",
|
|
30559
|
-
content: [
|
|
30560
|
-
"Field memo",
|
|
30561
|
-
"",
|
|
30562
|
-
"Checkpoint callsign: ember clock.",
|
|
30563
|
-
"All couriers must repeat ember clock before hand-off.",
|
|
30564
|
-
"The phrase ember clock remains active until rotation."
|
|
30565
|
-
].join("\n")
|
|
30566
|
-
}
|
|
30567
|
-
]
|
|
30568
|
-
}
|
|
30569
|
-
]
|
|
30570
|
-
}
|
|
30571
|
-
];
|
|
30572
|
-
async function loadChallengesFromFile(filePath) {
|
|
30573
|
-
const raw = await readFile(filePath, "utf8");
|
|
30574
|
-
const parsed = JSON.parse(raw);
|
|
30575
|
-
if (!Array.isArray(parsed)) {
|
|
30576
|
-
throw new Error("GAIA data file must contain a JSON array.");
|
|
30577
|
-
}
|
|
30578
|
-
return parsed.map((entry) => challengeDefinitionSchema.parse(entry));
|
|
30579
|
-
}
|
|
30580
|
-
var GaiaAdapter = class {
|
|
30581
|
-
benchmarkId = "gaia";
|
|
30582
|
-
dataFile = process.env.BENCHMARK_GAIA_DATA_FILE;
|
|
30583
|
-
async getChallenges() {
|
|
30584
|
-
if (!this.dataFile) {
|
|
30585
|
-
return DEFAULT_GAIA_CHALLENGES;
|
|
30586
|
-
}
|
|
30587
|
-
return await loadChallengesFromFile(this.dataFile);
|
|
30588
|
-
}
|
|
30589
|
-
async listChallenges() {
|
|
30590
|
-
const challenges = await this.getChallenges();
|
|
30591
|
-
return challenges.map(
|
|
30592
|
-
({ questions: _questions, ...summary }) => summary
|
|
30593
|
-
);
|
|
30594
|
-
}
|
|
30595
|
-
async getChallengeDefinition(challengeId) {
|
|
30596
|
-
const challenges = await this.getChallenges();
|
|
30597
|
-
return challenges.find(
|
|
30598
|
-
(challenge) => challenge.challenge_id === challengeId
|
|
30599
|
-
) ?? null;
|
|
30600
|
-
}
|
|
30601
|
-
};
|
|
30602
|
-
function createGaiaAdapter() {
|
|
30603
|
-
return new GaiaAdapter();
|
|
30628
|
+
var getCatalogStatusInputSchema = external_exports.object({});
|
|
30629
|
+
var syncCatalogInputSchema = external_exports.object({
|
|
30630
|
+
force: external_exports.boolean().default(false).describe("Ignore cache freshness and refetch")
|
|
30631
|
+
});
|
|
30632
|
+
function summarizeChallenge(challenge) {
|
|
30633
|
+
const difficultyLevels = [
|
|
30634
|
+
...new Set(challenge.tasks.map((task) => task.difficulty))
|
|
30635
|
+
].sort((left, right) => left - right);
|
|
30636
|
+
const checkerKinds = [
|
|
30637
|
+
...new Set(
|
|
30638
|
+
challenge.tasks.flatMap(
|
|
30639
|
+
(task) => task.checkers.map((checker) => checker.kind)
|
|
30640
|
+
)
|
|
30641
|
+
)
|
|
30642
|
+
];
|
|
30643
|
+
return {
|
|
30644
|
+
challenge_id: challenge.challenge_id,
|
|
30645
|
+
benchmark_id: challenge.benchmark_id,
|
|
30646
|
+
family: challenge.family,
|
|
30647
|
+
runner_kind: challenge.runner_kind,
|
|
30648
|
+
title: challenge.title,
|
|
30649
|
+
description: challenge.description,
|
|
30650
|
+
version: challenge.version,
|
|
30651
|
+
source: challenge.source,
|
|
30652
|
+
total_tasks: challenge.tasks.length,
|
|
30653
|
+
difficulty_levels: difficultyLevels,
|
|
30654
|
+
supports_assets: challenge.tasks.some((task) => task.assets.length > 0),
|
|
30655
|
+
checker_kinds: checkerKinds
|
|
30656
|
+
};
|
|
30604
30657
|
}
|
|
30605
30658
|
|
|
30606
30659
|
// src/attemptStore.ts
|
|
30607
|
-
import { mkdir, readFile as readFile2, rm, writeFile } from "node:fs/promises";
|
|
30608
|
-
import { randomUUID } from "node:crypto";
|
|
30609
|
-
import os from "node:os";
|
|
30610
|
-
import path from "node:path";
|
|
30611
30660
|
function nowIso() {
|
|
30612
30661
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
30613
30662
|
}
|
|
30614
30663
|
function getStateDir() {
|
|
30615
30664
|
return process.env.BENCHMARK_STATE_DIR ?? path.join(os.tmpdir(), "fre4x-benchmark-state");
|
|
30616
30665
|
}
|
|
30617
|
-
function
|
|
30618
|
-
return path.join(getStateDir(), "
|
|
30666
|
+
function getAttemptWorkspaceDir(attemptId) {
|
|
30667
|
+
return path.join(getStateDir(), "artifacts", attemptId);
|
|
30668
|
+
}
|
|
30669
|
+
function getAttemptsDir() {
|
|
30670
|
+
return path.join(getStateDir(), "attempts");
|
|
30671
|
+
}
|
|
30672
|
+
function getLocksDir() {
|
|
30673
|
+
return path.join(getStateDir(), "locks");
|
|
30674
|
+
}
|
|
30675
|
+
function getAttemptFilePath(attemptId) {
|
|
30676
|
+
return path.join(getAttemptsDir(), `${attemptId}.json`);
|
|
30677
|
+
}
|
|
30678
|
+
function getLockDirPath(attemptId) {
|
|
30679
|
+
return path.join(getLocksDir(), attemptId);
|
|
30619
30680
|
}
|
|
30620
|
-
async function
|
|
30621
|
-
|
|
30681
|
+
async function sleep(milliseconds) {
|
|
30682
|
+
await new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
30683
|
+
}
|
|
30684
|
+
async function ensureStateDirs() {
|
|
30685
|
+
await mkdir(getAttemptsDir(), { recursive: true });
|
|
30686
|
+
await mkdir(getLocksDir(), { recursive: true });
|
|
30687
|
+
}
|
|
30688
|
+
async function readAttemptFile(attemptId) {
|
|
30689
|
+
const filePath = getAttemptFilePath(attemptId);
|
|
30622
30690
|
try {
|
|
30623
|
-
const raw = await
|
|
30691
|
+
const raw = await readFile(filePath, "utf8");
|
|
30624
30692
|
const parsed = JSON.parse(raw);
|
|
30625
|
-
return
|
|
30693
|
+
return persistedAttemptSchema.parse(parsed);
|
|
30626
30694
|
} catch (error48) {
|
|
30627
30695
|
if (error48.code === "ENOENT") {
|
|
30628
|
-
return
|
|
30696
|
+
return null;
|
|
30629
30697
|
}
|
|
30630
30698
|
throw error48;
|
|
30631
30699
|
}
|
|
30632
30700
|
}
|
|
30633
|
-
async function
|
|
30634
|
-
|
|
30635
|
-
|
|
30636
|
-
|
|
30701
|
+
async function writeAttemptFile(attempt) {
|
|
30702
|
+
await ensureStateDirs();
|
|
30703
|
+
const filePath = getAttemptFilePath(attempt.attempt_id);
|
|
30704
|
+
const tempPath = `${filePath}.${randomUUID()}.tmp`;
|
|
30705
|
+
const serialized = JSON.stringify(attempt, null, 2);
|
|
30706
|
+
await writeFile(tempPath, serialized, "utf8");
|
|
30707
|
+
await rename(tempPath, filePath);
|
|
30708
|
+
}
|
|
30709
|
+
async function withAttemptLock(attemptId, operation) {
|
|
30710
|
+
await ensureStateDirs();
|
|
30711
|
+
const lockDir = getLockDirPath(attemptId);
|
|
30712
|
+
let retries = 0;
|
|
30713
|
+
while (true) {
|
|
30714
|
+
try {
|
|
30715
|
+
await mkdir(lockDir);
|
|
30716
|
+
break;
|
|
30717
|
+
} catch (error48) {
|
|
30718
|
+
const code = error48.code;
|
|
30719
|
+
if (code !== "EEXIST") {
|
|
30720
|
+
throw error48;
|
|
30721
|
+
}
|
|
30722
|
+
retries += 1;
|
|
30723
|
+
if (retries > 200) {
|
|
30724
|
+
throw new Error(`Attempt ${attemptId} is locked for too long.`);
|
|
30725
|
+
}
|
|
30726
|
+
await sleep(10);
|
|
30727
|
+
}
|
|
30728
|
+
}
|
|
30729
|
+
try {
|
|
30730
|
+
return await operation();
|
|
30731
|
+
} finally {
|
|
30732
|
+
await rm(lockDir, { recursive: true, force: true });
|
|
30733
|
+
}
|
|
30637
30734
|
}
|
|
30638
30735
|
async function createAttempt(challenge) {
|
|
30639
|
-
const state = await readStateFile();
|
|
30640
30736
|
const timestamp = nowIso();
|
|
30641
30737
|
const attempt = {
|
|
30642
30738
|
attempt_id: `attempt_${randomUUID()}`,
|
|
30643
30739
|
benchmark_id: challenge.benchmark_id,
|
|
30644
30740
|
challenge_id: challenge.challenge_id,
|
|
30645
30741
|
challenge_title: challenge.title,
|
|
30742
|
+
family: challenge.family,
|
|
30743
|
+
runner_kind: challenge.runner_kind,
|
|
30646
30744
|
dataset_version: challenge.version,
|
|
30745
|
+
source: challenge.source,
|
|
30647
30746
|
status: "active",
|
|
30648
|
-
|
|
30649
|
-
|
|
30747
|
+
revision: 1,
|
|
30748
|
+
current_task_index: 0,
|
|
30749
|
+
total_tasks: challenge.tasks.length,
|
|
30650
30750
|
started_at: timestamp,
|
|
30651
30751
|
updated_at: timestamp,
|
|
30652
|
-
|
|
30653
|
-
|
|
30752
|
+
tasks: challenge.tasks,
|
|
30753
|
+
evaluations: []
|
|
30654
30754
|
};
|
|
30655
|
-
|
|
30656
|
-
await
|
|
30755
|
+
await writeAttemptFile(attempt);
|
|
30756
|
+
await mkdir(getAttemptWorkspaceDir(attempt.attempt_id), {
|
|
30757
|
+
recursive: true
|
|
30758
|
+
});
|
|
30657
30759
|
return attempt;
|
|
30658
30760
|
}
|
|
30659
30761
|
async function getAttempt(attemptId) {
|
|
30660
|
-
|
|
30661
|
-
return state.attempts.find((attempt) => attempt.attempt_id === attemptId) ?? null;
|
|
30762
|
+
return await readAttemptFile(attemptId);
|
|
30662
30763
|
}
|
|
30663
|
-
async function
|
|
30664
|
-
|
|
30665
|
-
|
|
30666
|
-
(attempt)
|
|
30667
|
-
|
|
30668
|
-
|
|
30669
|
-
|
|
30764
|
+
async function appendEvaluation(attemptId, expectedTaskId, evaluation) {
|
|
30765
|
+
return await withAttemptLock(attemptId, async () => {
|
|
30766
|
+
const attempt = await readAttemptFile(attemptId);
|
|
30767
|
+
if (!attempt) {
|
|
30768
|
+
throw new Error(`Attempt ${attemptId} not found.`);
|
|
30769
|
+
}
|
|
30770
|
+
if (attempt.status !== "active") {
|
|
30771
|
+
throw new Error(`Attempt ${attemptId} is ${attempt.status}.`);
|
|
30772
|
+
}
|
|
30773
|
+
const currentTask = attempt.tasks[attempt.current_task_index];
|
|
30774
|
+
if (!currentTask) {
|
|
30775
|
+
throw new Error(`Attempt ${attemptId} has no current task.`);
|
|
30776
|
+
}
|
|
30777
|
+
if (currentTask.task_id !== expectedTaskId) {
|
|
30778
|
+
throw new Error(
|
|
30779
|
+
`Attempt ${attemptId} advanced to ${currentTask.task_id} before this submission was stored.`
|
|
30780
|
+
);
|
|
30781
|
+
}
|
|
30782
|
+
const nextAttempt = {
|
|
30783
|
+
...attempt,
|
|
30784
|
+
revision: attempt.revision + 1,
|
|
30785
|
+
evaluations: [...attempt.evaluations, evaluation],
|
|
30786
|
+
current_task_index: attempt.current_task_index + 1,
|
|
30787
|
+
updated_at: nowIso()
|
|
30788
|
+
};
|
|
30789
|
+
if (nextAttempt.current_task_index >= nextAttempt.total_tasks) {
|
|
30790
|
+
nextAttempt.status = "completed";
|
|
30791
|
+
}
|
|
30792
|
+
await writeAttemptFile(nextAttempt);
|
|
30793
|
+
return nextAttempt;
|
|
30794
|
+
});
|
|
30795
|
+
}
|
|
30796
|
+
async function cancelAttempt(attemptId) {
|
|
30797
|
+
return await withAttemptLock(attemptId, async () => {
|
|
30798
|
+
const attempt = await readAttemptFile(attemptId);
|
|
30799
|
+
if (!attempt) {
|
|
30800
|
+
throw new Error(`Attempt ${attemptId} not found.`);
|
|
30801
|
+
}
|
|
30802
|
+
const nextAttempt = {
|
|
30803
|
+
...attempt,
|
|
30804
|
+
revision: attempt.revision + 1,
|
|
30805
|
+
status: "cancelled",
|
|
30806
|
+
updated_at: nowIso()
|
|
30807
|
+
};
|
|
30808
|
+
await writeAttemptFile(nextAttempt);
|
|
30809
|
+
return nextAttempt;
|
|
30810
|
+
});
|
|
30811
|
+
}
|
|
30812
|
+
|
|
30813
|
+
// src/catalog.ts
|
|
30814
|
+
import os2 from "node:os";
|
|
30815
|
+
import path2 from "node:path";
|
|
30816
|
+
import { fileURLToPath } from "node:url";
|
|
30817
|
+
import { mkdir as mkdir2, readFile as readFile2, rename as rename2, rm as rm2, stat, writeFile as writeFile2 } from "node:fs/promises";
|
|
30818
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
30819
|
+
|
|
30820
|
+
// src/mock.ts
|
|
30821
|
+
function isMockEnabled() {
|
|
30822
|
+
return process.env.MOCK === "true" || process.env.BENCHMARK_MOCK === "true";
|
|
30823
|
+
}
|
|
30824
|
+
var IS_MOCK = isMockEnabled();
|
|
30825
|
+
|
|
30826
|
+
// src/catalog.ts
|
|
30827
|
+
var cachedCatalogSchema = external_exports.object({
|
|
30828
|
+
url: external_exports.string().url(),
|
|
30829
|
+
fetched_at: external_exports.string(),
|
|
30830
|
+
challenges: external_exports.array(challengeDefinitionSchema)
|
|
30831
|
+
});
|
|
30832
|
+
var builtinChallengesPromise = null;
|
|
30833
|
+
function getConfiguredCatalogFile() {
|
|
30834
|
+
return process.env.BENCHMARK_CATALOG_FILE ?? process.env.BENCHMARK_GAIA_DATA_FILE ?? null;
|
|
30835
|
+
}
|
|
30836
|
+
function getConfiguredCatalogUrl() {
|
|
30837
|
+
return process.env.BENCHMARK_CATALOG_URL ?? null;
|
|
30838
|
+
}
|
|
30839
|
+
function getStateDir2() {
|
|
30840
|
+
return process.env.BENCHMARK_STATE_DIR ?? path2.join(os2.tmpdir(), "fre4x-benchmark-state");
|
|
30841
|
+
}
|
|
30842
|
+
function getCacheDir() {
|
|
30843
|
+
return process.env.BENCHMARK_CACHE_DIR ?? path2.join(getStateDir2(), "catalog-cache");
|
|
30844
|
+
}
|
|
30845
|
+
function getCacheFilePath() {
|
|
30846
|
+
return path2.join(getCacheDir(), "catalog.json");
|
|
30847
|
+
}
|
|
30848
|
+
function getCacheTtlSeconds() {
|
|
30849
|
+
const raw = process.env.BENCHMARK_CACHE_TTL_SECONDS;
|
|
30850
|
+
if (!raw) {
|
|
30851
|
+
return 3600;
|
|
30852
|
+
}
|
|
30853
|
+
const parsed = Number.parseInt(raw, 10);
|
|
30854
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : 3600;
|
|
30855
|
+
}
|
|
30856
|
+
async function ensureCacheDir() {
|
|
30857
|
+
await mkdir2(getCacheDir(), { recursive: true });
|
|
30858
|
+
}
|
|
30859
|
+
async function loadChallengesFromFile(filePath) {
|
|
30860
|
+
const raw = await readFile2(filePath, "utf8");
|
|
30861
|
+
const parsed = JSON.parse(raw);
|
|
30862
|
+
if (!Array.isArray(parsed)) {
|
|
30863
|
+
throw new Error("Benchmark catalog file must contain a JSON array.");
|
|
30670
30864
|
}
|
|
30671
|
-
|
|
30672
|
-
await writeStateFile(state);
|
|
30865
|
+
return parsed.map((entry) => challengeDefinitionSchema.parse(entry));
|
|
30673
30866
|
}
|
|
30674
|
-
async function
|
|
30675
|
-
|
|
30676
|
-
|
|
30677
|
-
|
|
30678
|
-
|
|
30679
|
-
|
|
30867
|
+
async function getBuiltinChallenges() {
|
|
30868
|
+
builtinChallengesPromise ??= (async () => {
|
|
30869
|
+
const candidatePaths = [
|
|
30870
|
+
fileURLToPath(new URL("./fallback-catalog.json", import.meta.url)),
|
|
30871
|
+
fileURLToPath(
|
|
30872
|
+
new URL("../catalogs/expanded-catalog.json", import.meta.url)
|
|
30873
|
+
)
|
|
30874
|
+
];
|
|
30875
|
+
for (const candidatePath of candidatePaths) {
|
|
30876
|
+
try {
|
|
30877
|
+
return await loadChallengesFromFile(candidatePath);
|
|
30878
|
+
} catch (error48) {
|
|
30879
|
+
if (error48.code === "ENOENT") {
|
|
30880
|
+
continue;
|
|
30881
|
+
}
|
|
30882
|
+
throw error48;
|
|
30883
|
+
}
|
|
30884
|
+
}
|
|
30885
|
+
throw new Error("No bundled fallback catalog was found.");
|
|
30886
|
+
})();
|
|
30887
|
+
return await builtinChallengesPromise;
|
|
30888
|
+
}
|
|
30889
|
+
async function mergeWithBuiltins(externalChallenges) {
|
|
30890
|
+
const builtinChallenges = await getBuiltinChallenges();
|
|
30891
|
+
const merged = /* @__PURE__ */ new Map();
|
|
30892
|
+
for (const challenge of builtinChallenges) {
|
|
30893
|
+
merged.set(challenge.challenge_id, challenge);
|
|
30894
|
+
}
|
|
30895
|
+
for (const challenge of externalChallenges) {
|
|
30896
|
+
merged.set(challenge.challenge_id, challenge);
|
|
30897
|
+
}
|
|
30898
|
+
return [...merged.values()];
|
|
30899
|
+
}
|
|
30900
|
+
async function readCachedCatalog() {
|
|
30901
|
+
try {
|
|
30902
|
+
const raw = await readFile2(getCacheFilePath(), "utf8");
|
|
30903
|
+
const parsed = JSON.parse(raw);
|
|
30904
|
+
return cachedCatalogSchema.parse(parsed);
|
|
30905
|
+
} catch (error48) {
|
|
30906
|
+
if (error48.code === "ENOENT") {
|
|
30907
|
+
return null;
|
|
30908
|
+
}
|
|
30909
|
+
throw error48;
|
|
30910
|
+
}
|
|
30911
|
+
}
|
|
30912
|
+
async function writeCachedCatalog(url2, challenges) {
|
|
30913
|
+
await ensureCacheDir();
|
|
30914
|
+
const cache = {
|
|
30915
|
+
url: url2,
|
|
30916
|
+
fetched_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30917
|
+
challenges
|
|
30680
30918
|
};
|
|
30681
|
-
|
|
30682
|
-
|
|
30919
|
+
const filePath = getCacheFilePath();
|
|
30920
|
+
const tempPath = `${filePath}.${randomUUID2()}.tmp`;
|
|
30921
|
+
await writeFile2(tempPath, JSON.stringify(cache, null, 2), "utf8");
|
|
30922
|
+
await rename2(tempPath, filePath);
|
|
30923
|
+
return cache;
|
|
30924
|
+
}
|
|
30925
|
+
function getAgeSeconds(timestamp) {
|
|
30926
|
+
const now = Date.now();
|
|
30927
|
+
const value = Date.parse(timestamp);
|
|
30928
|
+
if (!Number.isFinite(value)) {
|
|
30929
|
+
return Number.MAX_SAFE_INTEGER;
|
|
30930
|
+
}
|
|
30931
|
+
return Math.max(0, Math.floor((now - value) / 1e3));
|
|
30932
|
+
}
|
|
30933
|
+
async function isCacheFresh(cache) {
|
|
30934
|
+
if (!cache) {
|
|
30935
|
+
return false;
|
|
30936
|
+
}
|
|
30937
|
+
return getAgeSeconds(cache.fetched_at) <= getCacheTtlSeconds();
|
|
30938
|
+
}
|
|
30939
|
+
async function fetchChallengesFromUrl(url2) {
|
|
30940
|
+
const response = await fetch(url2, {
|
|
30941
|
+
headers: {
|
|
30942
|
+
accept: "application/json"
|
|
30943
|
+
}
|
|
30944
|
+
});
|
|
30945
|
+
if (!response.ok) {
|
|
30946
|
+
throw new Error(
|
|
30947
|
+
`Catalog fetch failed with status ${response.status} ${response.statusText}.`
|
|
30948
|
+
);
|
|
30949
|
+
}
|
|
30950
|
+
const parsed = await response.json();
|
|
30951
|
+
if (!Array.isArray(parsed)) {
|
|
30952
|
+
throw new Error("Remote catalog must contain a JSON array.");
|
|
30953
|
+
}
|
|
30954
|
+
return parsed.map((entry) => challengeDefinitionSchema.parse(entry));
|
|
30955
|
+
}
|
|
30956
|
+
async function loadRemoteCatalog(forceRefresh) {
|
|
30957
|
+
const configuredUrl = getConfiguredCatalogUrl();
|
|
30958
|
+
if (!configuredUrl) {
|
|
30959
|
+
return {
|
|
30960
|
+
challenges: await getBuiltinChallenges(),
|
|
30961
|
+
mode: "builtin",
|
|
30962
|
+
lastError: null
|
|
30963
|
+
};
|
|
30964
|
+
}
|
|
30965
|
+
const cache = await readCachedCatalog();
|
|
30966
|
+
if (cache && !forceRefresh && await isCacheFresh(cache)) {
|
|
30967
|
+
return {
|
|
30968
|
+
challenges: await mergeWithBuiltins(cache.challenges),
|
|
30969
|
+
mode: "remote_cache",
|
|
30970
|
+
lastError: null
|
|
30971
|
+
};
|
|
30972
|
+
}
|
|
30973
|
+
try {
|
|
30974
|
+
const remoteChallenges = await fetchChallengesFromUrl(configuredUrl);
|
|
30975
|
+
await writeCachedCatalog(configuredUrl, remoteChallenges);
|
|
30976
|
+
return {
|
|
30977
|
+
challenges: await mergeWithBuiltins(remoteChallenges),
|
|
30978
|
+
mode: "remote_url",
|
|
30979
|
+
lastError: null
|
|
30980
|
+
};
|
|
30981
|
+
} catch (error48) {
|
|
30982
|
+
if (cache) {
|
|
30983
|
+
const message = error48 instanceof Error ? error48.message : "Remote catalog fetch failed.";
|
|
30984
|
+
return {
|
|
30985
|
+
challenges: await mergeWithBuiltins(cache.challenges),
|
|
30986
|
+
mode: "remote_cache",
|
|
30987
|
+
lastError: message
|
|
30988
|
+
};
|
|
30989
|
+
}
|
|
30990
|
+
throw error48;
|
|
30683
30991
|
}
|
|
30684
|
-
await saveAttempt(nextAttempt);
|
|
30685
|
-
return nextAttempt;
|
|
30686
30992
|
}
|
|
30687
|
-
async function
|
|
30688
|
-
|
|
30689
|
-
|
|
30690
|
-
|
|
30691
|
-
|
|
30993
|
+
async function loadCatalog(forceRefresh = false) {
|
|
30994
|
+
if (isMockEnabled()) {
|
|
30995
|
+
return {
|
|
30996
|
+
challenges: await getBuiltinChallenges(),
|
|
30997
|
+
mode: "mock",
|
|
30998
|
+
lastError: null
|
|
30999
|
+
};
|
|
31000
|
+
}
|
|
31001
|
+
const catalogFile = getConfiguredCatalogFile();
|
|
31002
|
+
if (catalogFile) {
|
|
31003
|
+
return {
|
|
31004
|
+
challenges: await mergeWithBuiltins(
|
|
31005
|
+
await loadChallengesFromFile(catalogFile)
|
|
31006
|
+
),
|
|
31007
|
+
mode: "file",
|
|
31008
|
+
lastError: null
|
|
31009
|
+
};
|
|
31010
|
+
}
|
|
31011
|
+
return await loadRemoteCatalog(forceRefresh);
|
|
31012
|
+
}
|
|
31013
|
+
async function listChallenges() {
|
|
31014
|
+
const catalog = await loadCatalog();
|
|
31015
|
+
return catalog.challenges.map((challenge) => summarizeChallenge(challenge));
|
|
31016
|
+
}
|
|
31017
|
+
async function getChallengeDefinition(challengeId) {
|
|
31018
|
+
const catalog = await loadCatalog();
|
|
31019
|
+
return catalog.challenges.find(
|
|
31020
|
+
(challenge) => challenge.challenge_id === challengeId
|
|
31021
|
+
) ?? null;
|
|
31022
|
+
}
|
|
31023
|
+
async function syncCatalog(forceRefresh) {
|
|
31024
|
+
if (isMockEnabled()) {
|
|
31025
|
+
return {
|
|
31026
|
+
status: await getCatalogStatus(),
|
|
31027
|
+
challenges: await getBuiltinChallenges()
|
|
31028
|
+
};
|
|
31029
|
+
}
|
|
31030
|
+
const configuredFile = getConfiguredCatalogFile();
|
|
31031
|
+
if (configuredFile) {
|
|
31032
|
+
const challenges = await mergeWithBuiltins(
|
|
31033
|
+
await loadChallengesFromFile(configuredFile)
|
|
31034
|
+
);
|
|
31035
|
+
return {
|
|
31036
|
+
status: await getCatalogStatus(challenges, "file", null),
|
|
31037
|
+
challenges
|
|
31038
|
+
};
|
|
31039
|
+
}
|
|
31040
|
+
const configuredUrl = getConfiguredCatalogUrl();
|
|
31041
|
+
if (!configuredUrl) {
|
|
31042
|
+
throw new Error(
|
|
31043
|
+
"BENCHMARK_CATALOG_URL is required for remote catalog sync."
|
|
31044
|
+
);
|
|
31045
|
+
}
|
|
31046
|
+
const loaded = await loadCatalog(forceRefresh);
|
|
31047
|
+
return {
|
|
31048
|
+
status: await getCatalogStatus(
|
|
31049
|
+
loaded.challenges,
|
|
31050
|
+
loaded.mode,
|
|
31051
|
+
loaded.lastError
|
|
31052
|
+
),
|
|
31053
|
+
challenges: loaded.challenges
|
|
31054
|
+
};
|
|
31055
|
+
}
|
|
31056
|
+
async function getCatalogStatus(knownChallenges, forcedMode, lastErrorOverride) {
|
|
31057
|
+
const configuredFile = getConfiguredCatalogFile();
|
|
31058
|
+
const configuredUrl = getConfiguredCatalogUrl();
|
|
31059
|
+
const cacheFile = getCacheFilePath();
|
|
31060
|
+
const ttlSeconds = getCacheTtlSeconds();
|
|
31061
|
+
const cache = await readCachedCatalog();
|
|
31062
|
+
const cacheFetchedAt = cache?.fetched_at ?? null;
|
|
31063
|
+
const cacheAgeSeconds = cacheFetchedAt ? getAgeSeconds(cacheFetchedAt) : null;
|
|
31064
|
+
const mode = forcedMode ? catalogModeSchema.parse(forcedMode) : isMockEnabled() ? "mock" : configuredFile ? "file" : configuredUrl ? cache ? "remote_cache" : "remote_url" : "builtin";
|
|
31065
|
+
let challengeCount = knownChallenges?.length ?? null;
|
|
31066
|
+
if (challengeCount === null) {
|
|
31067
|
+
if (mode === "mock" || mode === "builtin") {
|
|
31068
|
+
challengeCount = (await getBuiltinChallenges()).length;
|
|
31069
|
+
} else if (configuredFile) {
|
|
31070
|
+
try {
|
|
31071
|
+
challengeCount = (await mergeWithBuiltins(
|
|
31072
|
+
await loadChallengesFromFile(configuredFile)
|
|
31073
|
+
)).length;
|
|
31074
|
+
} catch {
|
|
31075
|
+
challengeCount = null;
|
|
31076
|
+
}
|
|
31077
|
+
} else if (cache) {
|
|
31078
|
+
challengeCount = (await mergeWithBuiltins(cache.challenges)).length;
|
|
31079
|
+
}
|
|
31080
|
+
}
|
|
31081
|
+
let cacheExists = false;
|
|
31082
|
+
try {
|
|
31083
|
+
await stat(cacheFile);
|
|
31084
|
+
cacheExists = true;
|
|
31085
|
+
} catch (error48) {
|
|
31086
|
+
if (error48.code !== "ENOENT") {
|
|
31087
|
+
throw error48;
|
|
31088
|
+
}
|
|
31089
|
+
}
|
|
31090
|
+
return {
|
|
31091
|
+
mode,
|
|
31092
|
+
configured_file: configuredFile,
|
|
31093
|
+
configured_url: configuredUrl,
|
|
31094
|
+
cache_file: cacheFile,
|
|
31095
|
+
cache_exists: cacheExists,
|
|
31096
|
+
cache_ttl_seconds: mode === "remote_cache" || mode === "remote_url" ? ttlSeconds : null,
|
|
31097
|
+
cache_fetched_at: cacheFetchedAt,
|
|
31098
|
+
cache_age_seconds: cacheAgeSeconds,
|
|
31099
|
+
can_sync: !isMockEnabled() && !configuredFile && Boolean(configuredUrl),
|
|
31100
|
+
challenge_count: challengeCount,
|
|
31101
|
+
last_error: lastErrorOverride ?? null
|
|
30692
31102
|
};
|
|
30693
|
-
await saveAttempt(nextAttempt);
|
|
30694
|
-
return nextAttempt;
|
|
30695
31103
|
}
|
|
30696
31104
|
|
|
30697
|
-
// src/
|
|
30698
|
-
|
|
31105
|
+
// src/checkers.ts
|
|
31106
|
+
function normalizeText(value) {
|
|
31107
|
+
return value.trim().toLowerCase().replace(/\s+/g, " ");
|
|
31108
|
+
}
|
|
31109
|
+
function isRecord(value) {
|
|
31110
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31111
|
+
}
|
|
31112
|
+
function getPrimitiveAtPath(value, fieldPath) {
|
|
31113
|
+
let current = value;
|
|
31114
|
+
for (const segment of fieldPath.split(".")) {
|
|
31115
|
+
if (!isRecord(current) || !(segment in current)) {
|
|
31116
|
+
return void 0;
|
|
31117
|
+
}
|
|
31118
|
+
current = current[segment];
|
|
31119
|
+
}
|
|
31120
|
+
if (typeof current === "string" || typeof current === "number" || typeof current === "boolean") {
|
|
31121
|
+
return current;
|
|
31122
|
+
}
|
|
31123
|
+
return void 0;
|
|
31124
|
+
}
|
|
31125
|
+
function renderPrimitive(value) {
|
|
31126
|
+
return typeof value === "string" ? value : String(value);
|
|
31127
|
+
}
|
|
31128
|
+
function evaluateChecker(checker, solution, execution) {
|
|
31129
|
+
switch (checker.kind) {
|
|
31130
|
+
case "exact_text": {
|
|
31131
|
+
const actual = checker.case_sensitive ? solution.trim() : solution.trim().toLowerCase();
|
|
31132
|
+
const expected = checker.case_sensitive ? checker.expected.trim() : checker.expected.trim().toLowerCase();
|
|
31133
|
+
const passed = actual === expected;
|
|
31134
|
+
return {
|
|
31135
|
+
checker_id: checker.checker_id,
|
|
31136
|
+
kind: checker.kind,
|
|
31137
|
+
passed,
|
|
31138
|
+
message: passed ? "Exact text matched." : `Expected "${checker.expected}" but received "${solution.trim()}".`
|
|
31139
|
+
};
|
|
31140
|
+
}
|
|
31141
|
+
case "normalized_text": {
|
|
31142
|
+
const actual = normalizeText(solution);
|
|
31143
|
+
const expected = normalizeText(checker.expected);
|
|
31144
|
+
const passed = actual === expected;
|
|
31145
|
+
return {
|
|
31146
|
+
checker_id: checker.checker_id,
|
|
31147
|
+
kind: checker.kind,
|
|
31148
|
+
passed,
|
|
31149
|
+
message: passed ? "Normalized text matched." : `Expected normalized "${checker.expected}" but received "${solution.trim()}".`
|
|
31150
|
+
};
|
|
31151
|
+
}
|
|
31152
|
+
case "regex_match": {
|
|
31153
|
+
try {
|
|
31154
|
+
const expression = new RegExp(checker.pattern, checker.flags);
|
|
31155
|
+
const passed = expression.test(solution);
|
|
31156
|
+
return {
|
|
31157
|
+
checker_id: checker.checker_id,
|
|
31158
|
+
kind: checker.kind,
|
|
31159
|
+
passed,
|
|
31160
|
+
message: passed ? "Regex matched the solution." : `Pattern /${checker.pattern}/${checker.flags ?? ""} did not match.`
|
|
31161
|
+
};
|
|
31162
|
+
} catch (error48) {
|
|
31163
|
+
const message = error48 instanceof Error ? error48.message : "Invalid regular expression.";
|
|
31164
|
+
return {
|
|
31165
|
+
checker_id: checker.checker_id,
|
|
31166
|
+
kind: checker.kind,
|
|
31167
|
+
passed: false,
|
|
31168
|
+
message
|
|
31169
|
+
};
|
|
31170
|
+
}
|
|
31171
|
+
}
|
|
31172
|
+
case "contains_all_text": {
|
|
31173
|
+
const actual = normalizeText(solution);
|
|
31174
|
+
const missing = checker.terms.filter(
|
|
31175
|
+
(term) => !actual.includes(normalizeText(term))
|
|
31176
|
+
);
|
|
31177
|
+
return {
|
|
31178
|
+
checker_id: checker.checker_id,
|
|
31179
|
+
kind: checker.kind,
|
|
31180
|
+
passed: missing.length === 0,
|
|
31181
|
+
message: missing.length === 0 ? "All required terms were present." : `Missing terms: ${missing.join(", ")}.`
|
|
31182
|
+
};
|
|
31183
|
+
}
|
|
31184
|
+
case "json_field_equals": {
|
|
31185
|
+
try {
|
|
31186
|
+
const parsed = JSON.parse(solution);
|
|
31187
|
+
const actual = getPrimitiveAtPath(parsed, checker.field);
|
|
31188
|
+
const passed = actual === checker.expected;
|
|
31189
|
+
return {
|
|
31190
|
+
checker_id: checker.checker_id,
|
|
31191
|
+
kind: checker.kind,
|
|
31192
|
+
passed,
|
|
31193
|
+
message: actual === void 0 ? `Field "${checker.field}" was missing or not primitive.` : passed ? `Field "${checker.field}" matched ${renderPrimitive(checker.expected)}.` : `Field "${checker.field}" expected ${renderPrimitive(checker.expected)} but received ${renderPrimitive(actual)}.`
|
|
31194
|
+
};
|
|
31195
|
+
} catch (error48) {
|
|
31196
|
+
const message = error48 instanceof Error ? error48.message : "Solution was not valid JSON.";
|
|
31197
|
+
return {
|
|
31198
|
+
checker_id: checker.checker_id,
|
|
31199
|
+
kind: checker.kind,
|
|
31200
|
+
passed: false,
|
|
31201
|
+
message
|
|
31202
|
+
};
|
|
31203
|
+
}
|
|
31204
|
+
}
|
|
31205
|
+
case "runner_fact_equals": {
|
|
31206
|
+
const actual = execution.facts[checker.fact];
|
|
31207
|
+
const passed = actual === checker.expected;
|
|
31208
|
+
return {
|
|
31209
|
+
checker_id: checker.checker_id,
|
|
31210
|
+
kind: checker.kind,
|
|
31211
|
+
passed,
|
|
31212
|
+
message: actual === void 0 ? `Runner fact "${checker.fact}" was missing.` : passed ? `Runner fact "${checker.fact}" matched ${renderPrimitive(checker.expected)}.` : `Runner fact "${checker.fact}" expected ${renderPrimitive(checker.expected)} but received ${renderPrimitive(actual)}.`
|
|
31213
|
+
};
|
|
31214
|
+
}
|
|
31215
|
+
case "runner_log_contains_text": {
|
|
31216
|
+
const normalizedLogs = normalizeText(execution.logs.join("\n"));
|
|
31217
|
+
const missing = checker.terms.filter(
|
|
31218
|
+
(term) => !normalizedLogs.includes(normalizeText(term))
|
|
31219
|
+
);
|
|
31220
|
+
return {
|
|
31221
|
+
checker_id: checker.checker_id,
|
|
31222
|
+
kind: checker.kind,
|
|
31223
|
+
passed: missing.length === 0,
|
|
31224
|
+
message: missing.length === 0 ? "Runner logs contained all required terms." : `Runner logs missing terms: ${missing.join(", ")}.`
|
|
31225
|
+
};
|
|
31226
|
+
}
|
|
31227
|
+
}
|
|
31228
|
+
}
|
|
31229
|
+
function evaluateTask(task, solution, execution) {
|
|
31230
|
+
const evidence = task.checkers.map(
|
|
31231
|
+
(checker) => evaluateChecker(checker, solution, execution)
|
|
31232
|
+
);
|
|
31233
|
+
return {
|
|
31234
|
+
accepted: evidence.every((entry) => entry.passed),
|
|
31235
|
+
evidence
|
|
31236
|
+
};
|
|
31237
|
+
}
|
|
31238
|
+
|
|
31239
|
+
// src/runners.ts
|
|
31240
|
+
import { mkdir as mkdir3, writeFile as writeFile3 } from "node:fs/promises";
|
|
31241
|
+
import path3 from "node:path";
|
|
31242
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
31243
|
+
function nowStamp() {
|
|
31244
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
31245
|
+
}
|
|
31246
|
+
function createArtifact(kind, filePath, mimeType, description) {
|
|
31247
|
+
return {
|
|
31248
|
+
artifact_id: `${kind}_${randomUUID3()}`,
|
|
31249
|
+
kind,
|
|
31250
|
+
path: filePath,
|
|
31251
|
+
mime_type: mimeType,
|
|
31252
|
+
...description ? { description } : {}
|
|
31253
|
+
};
|
|
31254
|
+
}
|
|
31255
|
+
async function ensureTaskWorkspace(attemptId, taskId) {
|
|
31256
|
+
const workspaceDir = path3.join(getAttemptWorkspaceDir(attemptId), taskId);
|
|
31257
|
+
await mkdir3(workspaceDir, { recursive: true });
|
|
31258
|
+
return workspaceDir;
|
|
31259
|
+
}
|
|
31260
|
+
async function materializeAsset(workspaceDir, taskId, asset) {
|
|
31261
|
+
if (asset.materialization !== "workspace_file") {
|
|
31262
|
+
return null;
|
|
31263
|
+
}
|
|
31264
|
+
const assetDir = path3.join(workspaceDir, "assets");
|
|
31265
|
+
await mkdir3(assetDir, { recursive: true });
|
|
31266
|
+
const fileName = `${taskId}-${asset.name}`;
|
|
31267
|
+
const filePath = path3.join(assetDir, fileName);
|
|
31268
|
+
await writeFile3(filePath, asset.content, "utf8");
|
|
31269
|
+
return createArtifact(
|
|
31270
|
+
"materialized_asset",
|
|
31271
|
+
filePath,
|
|
31272
|
+
asset.mime_type,
|
|
31273
|
+
asset.description
|
|
31274
|
+
);
|
|
31275
|
+
}
|
|
31276
|
+
async function writeSubmissionArtifact(workspaceDir, task, solution) {
|
|
31277
|
+
const extension = task.response_format === "json" ? "json" : "txt";
|
|
31278
|
+
const filePath = path3.join(workspaceDir, `submission.${extension}`);
|
|
31279
|
+
await writeFile3(filePath, solution, "utf8");
|
|
31280
|
+
return createArtifact(
|
|
31281
|
+
"submission",
|
|
31282
|
+
filePath,
|
|
31283
|
+
task.response_format === "json" ? "application/json" : "text/plain",
|
|
31284
|
+
"Submitted solution payload."
|
|
31285
|
+
);
|
|
31286
|
+
}
|
|
31287
|
+
async function writeRunnerReport(workspaceDir, task, logs, facts) {
|
|
31288
|
+
const reportPath = path3.join(
|
|
31289
|
+
workspaceDir,
|
|
31290
|
+
`runner-report-${nowStamp()}.json`
|
|
31291
|
+
);
|
|
31292
|
+
await writeFile3(
|
|
31293
|
+
reportPath,
|
|
31294
|
+
JSON.stringify(
|
|
31295
|
+
{
|
|
31296
|
+
task_id: task.task_id,
|
|
31297
|
+
logs,
|
|
31298
|
+
facts
|
|
31299
|
+
},
|
|
31300
|
+
null,
|
|
31301
|
+
2
|
|
31302
|
+
),
|
|
31303
|
+
"utf8"
|
|
31304
|
+
);
|
|
31305
|
+
return createArtifact(
|
|
31306
|
+
"runner_report",
|
|
31307
|
+
reportPath,
|
|
31308
|
+
"application/json",
|
|
31309
|
+
"Execution report with runner facts and logs."
|
|
31310
|
+
);
|
|
31311
|
+
}
|
|
31312
|
+
function countWorkspaceAssets(task) {
|
|
31313
|
+
return task.assets.filter(
|
|
31314
|
+
(asset) => asset.materialization === "workspace_file"
|
|
31315
|
+
).length;
|
|
31316
|
+
}
|
|
31317
|
+
async function executeTaskRunner(attempt, task, solution) {
|
|
31318
|
+
const workspaceDir = await ensureTaskWorkspace(
|
|
31319
|
+
attempt.attempt_id,
|
|
31320
|
+
task.task_id
|
|
31321
|
+
);
|
|
31322
|
+
const artifacts = [];
|
|
31323
|
+
const logs = [
|
|
31324
|
+
`runner ${attempt.runner_kind} started for task ${task.task_id}`
|
|
31325
|
+
];
|
|
31326
|
+
for (const asset of task.assets) {
|
|
31327
|
+
const artifact = await materializeAsset(
|
|
31328
|
+
workspaceDir,
|
|
31329
|
+
task.task_id,
|
|
31330
|
+
asset
|
|
31331
|
+
);
|
|
31332
|
+
if (artifact) {
|
|
31333
|
+
artifacts.push(artifact);
|
|
31334
|
+
logs.push(
|
|
31335
|
+
`materialized asset ${asset.asset_id} to ${artifact.path}`
|
|
31336
|
+
);
|
|
31337
|
+
} else {
|
|
31338
|
+
logs.push(`kept asset ${asset.asset_id} inline`);
|
|
31339
|
+
}
|
|
31340
|
+
}
|
|
31341
|
+
const submissionArtifact = await writeSubmissionArtifact(
|
|
31342
|
+
workspaceDir,
|
|
31343
|
+
task,
|
|
31344
|
+
solution
|
|
31345
|
+
);
|
|
31346
|
+
artifacts.push(submissionArtifact);
|
|
31347
|
+
logs.push(`wrote submission artifact ${submissionArtifact.path}`);
|
|
31348
|
+
const facts = {
|
|
31349
|
+
materialized_asset_count: countWorkspaceAssets(task),
|
|
31350
|
+
total_asset_count: task.assets.length,
|
|
31351
|
+
response_format: task.response_format,
|
|
31352
|
+
family: attempt.family
|
|
31353
|
+
};
|
|
31354
|
+
if (attempt.runner_kind === "code_runner") {
|
|
31355
|
+
facts.domain = "code";
|
|
31356
|
+
logs.push("prepared code workspace inputs");
|
|
31357
|
+
} else if (attempt.runner_kind === "browser_runner") {
|
|
31358
|
+
facts.domain = "web";
|
|
31359
|
+
logs.push("prepared browser snapshot workspace");
|
|
31360
|
+
} else {
|
|
31361
|
+
facts.domain = "os";
|
|
31362
|
+
logs.push("prepared os workspace inventory");
|
|
31363
|
+
}
|
|
31364
|
+
const reportArtifact = await writeRunnerReport(
|
|
31365
|
+
workspaceDir,
|
|
31366
|
+
task,
|
|
31367
|
+
logs,
|
|
31368
|
+
facts
|
|
31369
|
+
);
|
|
31370
|
+
artifacts.push(reportArtifact);
|
|
31371
|
+
logs.push(`wrote runner report ${reportArtifact.path}`);
|
|
31372
|
+
return {
|
|
31373
|
+
runner_kind: attempt.runner_kind,
|
|
31374
|
+
workspace_dir: workspaceDir,
|
|
31375
|
+
logs,
|
|
31376
|
+
facts,
|
|
31377
|
+
artifacts
|
|
31378
|
+
};
|
|
31379
|
+
}
|
|
30699
31380
|
|
|
30700
31381
|
// src/index.ts
|
|
30701
31382
|
var PACKAGE_VERSION = getPackageVersion(import.meta.url);
|
|
30702
|
-
var ADAPTERS = [createGaiaAdapter()];
|
|
30703
31383
|
var server = new McpServer({
|
|
30704
31384
|
name: "@fre4x/benchmark",
|
|
30705
31385
|
version: PACKAGE_VERSION
|
|
@@ -30715,29 +31395,47 @@ function toPublicAssetDescriptor(asset) {
|
|
|
30715
31395
|
asset_id: asset.asset_id,
|
|
30716
31396
|
name: asset.name,
|
|
30717
31397
|
mime_type: asset.mime_type,
|
|
31398
|
+
transport: asset.transport,
|
|
31399
|
+
materialization: asset.materialization,
|
|
30718
31400
|
...asset.description ? { description: asset.description } : {}
|
|
30719
31401
|
};
|
|
30720
31402
|
}
|
|
30721
|
-
function
|
|
31403
|
+
function toPublicTask(task) {
|
|
30722
31404
|
return {
|
|
30723
|
-
|
|
30724
|
-
|
|
30725
|
-
|
|
30726
|
-
|
|
30727
|
-
|
|
30728
|
-
|
|
30729
|
-
|
|
30730
|
-
|
|
30731
|
-
}
|
|
30732
|
-
function
|
|
30733
|
-
|
|
30734
|
-
|
|
30735
|
-
}
|
|
30736
|
-
return
|
|
31405
|
+
task_id: task.task_id,
|
|
31406
|
+
title: task.title,
|
|
31407
|
+
prompt: task.prompt,
|
|
31408
|
+
response_format: task.response_format,
|
|
31409
|
+
difficulty: task.difficulty,
|
|
31410
|
+
assets: task.assets.map(toPublicAssetDescriptor),
|
|
31411
|
+
checker_kinds: task.checkers.map((checker) => checker.kind)
|
|
31412
|
+
};
|
|
31413
|
+
}
|
|
31414
|
+
function formatRunnerExecution(execution) {
|
|
31415
|
+
const logLines = execution.logs.map((entry) => `- ${entry}`).join("\n");
|
|
31416
|
+
const factLines = Object.entries(execution.facts).map(([key, value]) => `- \`${key}\`: ${value}`).join("\n");
|
|
31417
|
+
const artifactLines = execution.artifacts.map((artifact) => `- \`${artifact.kind}\`: ${artifact.path}`).join("\n");
|
|
31418
|
+
return [
|
|
31419
|
+
"## Runner Execution",
|
|
31420
|
+
"",
|
|
31421
|
+
`**Workspace Dir:** ${execution.workspace_dir}`,
|
|
31422
|
+
"",
|
|
31423
|
+
"### Facts",
|
|
31424
|
+
"",
|
|
31425
|
+
factLines || "_No facts recorded._",
|
|
31426
|
+
"",
|
|
31427
|
+
"### Logs",
|
|
31428
|
+
"",
|
|
31429
|
+
logLines || "_No logs recorded._",
|
|
31430
|
+
"",
|
|
31431
|
+
"### Artifacts",
|
|
31432
|
+
"",
|
|
31433
|
+
artifactLines || "_No artifacts recorded._"
|
|
31434
|
+
].join("\n");
|
|
30737
31435
|
}
|
|
30738
31436
|
function sumScore(attempt) {
|
|
30739
|
-
return attempt.
|
|
30740
|
-
(total,
|
|
31437
|
+
return attempt.evaluations.reduce(
|
|
31438
|
+
(total, evaluation) => total + evaluation.score_delta,
|
|
30741
31439
|
0
|
|
30742
31440
|
);
|
|
30743
31441
|
}
|
|
@@ -30749,16 +31447,19 @@ function createGuidanceStep(action, recommendedTool, reason, exampleArguments) {
|
|
|
30749
31447
|
...exampleArguments ? { example_arguments: exampleArguments } : {}
|
|
30750
31448
|
};
|
|
30751
31449
|
}
|
|
30752
|
-
function
|
|
30753
|
-
|
|
31450
|
+
function createSubmitExample(task) {
|
|
31451
|
+
return task.response_format === "json" ? '{"field":"value"}' : "your final answer";
|
|
31452
|
+
}
|
|
31453
|
+
function getTaskGuidance(attemptId, task) {
|
|
31454
|
+
if (task.assets.length > 0) {
|
|
30754
31455
|
return {
|
|
30755
31456
|
primary: createGuidanceStep(
|
|
30756
31457
|
"review_asset",
|
|
30757
31458
|
"benchmark_get_asset",
|
|
30758
|
-
"This
|
|
31459
|
+
"This task includes an attachment.",
|
|
30759
31460
|
{
|
|
30760
31461
|
attempt_id: attemptId,
|
|
30761
|
-
asset_id:
|
|
31462
|
+
asset_id: task.assets[0].asset_id
|
|
30762
31463
|
}
|
|
30763
31464
|
),
|
|
30764
31465
|
alternatives: [
|
|
@@ -30768,7 +31469,7 @@ function getQuestionGuidance(attemptId, question) {
|
|
|
30768
31469
|
"Submit after reviewing the attachment.",
|
|
30769
31470
|
{
|
|
30770
31471
|
attempt_id: attemptId,
|
|
30771
|
-
solution:
|
|
31472
|
+
solution: createSubmitExample(task)
|
|
30772
31473
|
}
|
|
30773
31474
|
)
|
|
30774
31475
|
]
|
|
@@ -30778,10 +31479,10 @@ function getQuestionGuidance(attemptId, question) {
|
|
|
30778
31479
|
primary: createGuidanceStep(
|
|
30779
31480
|
"submit_solution",
|
|
30780
31481
|
"benchmark_submit_solution",
|
|
30781
|
-
"This
|
|
31482
|
+
"This task is ready for deterministic grading.",
|
|
30782
31483
|
{
|
|
30783
31484
|
attempt_id: attemptId,
|
|
30784
|
-
solution:
|
|
31485
|
+
solution: createSubmitExample(task)
|
|
30785
31486
|
}
|
|
30786
31487
|
),
|
|
30787
31488
|
alternatives: [
|
|
@@ -30789,24 +31490,17 @@ function getQuestionGuidance(attemptId, question) {
|
|
|
30789
31490
|
"inspect_attempt",
|
|
30790
31491
|
"benchmark_get_attempt",
|
|
30791
31492
|
"Review the current attempt state.",
|
|
30792
|
-
{
|
|
31493
|
+
{
|
|
31494
|
+
attempt_id: attemptId,
|
|
31495
|
+
limit: "20",
|
|
31496
|
+
offset: "0"
|
|
31497
|
+
}
|
|
30793
31498
|
)
|
|
30794
31499
|
]
|
|
30795
31500
|
};
|
|
30796
31501
|
}
|
|
30797
|
-
function
|
|
30798
|
-
return
|
|
30799
|
-
(adapter) => challengeId.startsWith(`${adapter.benchmarkId}_`)
|
|
30800
|
-
) ?? null;
|
|
30801
|
-
}
|
|
30802
|
-
async function listAllChallenges() {
|
|
30803
|
-
const groups = await Promise.all(
|
|
30804
|
-
ADAPTERS.map(async (adapter) => await adapter.listChallenges())
|
|
30805
|
-
);
|
|
30806
|
-
return groups.flat();
|
|
30807
|
-
}
|
|
30808
|
-
function getCurrentQuestion(attempt) {
|
|
30809
|
-
return attempt.questions[attempt.current_question_index] ?? null;
|
|
31502
|
+
function getCurrentTask(attempt) {
|
|
31503
|
+
return attempt.tasks[attempt.current_task_index] ?? null;
|
|
30810
31504
|
}
|
|
30811
31505
|
function formatChallengeSummary(summary) {
|
|
30812
31506
|
return [
|
|
@@ -30814,25 +31508,40 @@ function formatChallengeSummary(summary) {
|
|
|
30814
31508
|
formatFields([
|
|
30815
31509
|
["Challenge ID", summary.challenge_id],
|
|
30816
31510
|
["Benchmark", summary.benchmark_id],
|
|
31511
|
+
["Family", summary.family],
|
|
31512
|
+
["Runner", summary.runner_kind],
|
|
30817
31513
|
["Version", summary.version],
|
|
30818
|
-
["
|
|
31514
|
+
["Source", summary.source],
|
|
31515
|
+
["Tasks", summary.total_tasks],
|
|
30819
31516
|
["Difficulties", summary.difficulty_levels.join(", ")],
|
|
31517
|
+
["Checker Kinds", summary.checker_kinds.join(", ")],
|
|
30820
31518
|
["Assets", summary.supports_assets ? "yes" : "no"]
|
|
30821
31519
|
]),
|
|
30822
31520
|
"",
|
|
30823
31521
|
summary.description
|
|
30824
31522
|
].join("\n");
|
|
30825
31523
|
}
|
|
30826
|
-
function
|
|
30827
|
-
const assetLines =
|
|
30828
|
-
|
|
30829
|
-
(asset) => `- \`${asset.asset_id}\` (${asset.name}, ${asset.mime_type})`
|
|
31524
|
+
function formatTaskBlock(attemptId, taskIndex, totalTasks, task) {
|
|
31525
|
+
const assetLines = task.assets.length > 0 ? formatListItems(
|
|
31526
|
+
task.assets,
|
|
31527
|
+
(asset) => `- \`${asset.asset_id}\` (${asset.name}, ${asset.mime_type}, ${asset.materialization})`
|
|
30830
31528
|
) : "_No assets attached._";
|
|
30831
|
-
const guidance =
|
|
31529
|
+
const guidance = getTaskGuidance(attemptId, task);
|
|
30832
31530
|
return [
|
|
30833
|
-
`#
|
|
31531
|
+
`# Task ${taskIndex} of ${totalTasks}`,
|
|
30834
31532
|
"",
|
|
30835
|
-
|
|
31533
|
+
`## ${task.title}`,
|
|
31534
|
+
"",
|
|
31535
|
+
task.prompt,
|
|
31536
|
+
"",
|
|
31537
|
+
formatFields([
|
|
31538
|
+
["Response Format", task.response_format],
|
|
31539
|
+
["Difficulty", task.difficulty],
|
|
31540
|
+
[
|
|
31541
|
+
"Checker Kinds",
|
|
31542
|
+
task.checkers.map((checker) => checker.kind).join(", ")
|
|
31543
|
+
]
|
|
31544
|
+
]),
|
|
30836
31545
|
"",
|
|
30837
31546
|
"## Assets",
|
|
30838
31547
|
"",
|
|
@@ -30845,9 +31554,71 @@ function formatQuestionBlock(attemptId, questionIndex, totalQuestions, question)
|
|
|
30845
31554
|
`- **Reason**: ${guidance.primary.reason}`
|
|
30846
31555
|
].join("\n");
|
|
30847
31556
|
}
|
|
31557
|
+
function formatCatalogStatus(status) {
|
|
31558
|
+
return [
|
|
31559
|
+
"# Catalog Status",
|
|
31560
|
+
"",
|
|
31561
|
+
formatFields([
|
|
31562
|
+
["Mode", status.mode],
|
|
31563
|
+
["Configured File", status.configured_file],
|
|
31564
|
+
["Configured URL", status.configured_url],
|
|
31565
|
+
["Cache File", status.cache_file],
|
|
31566
|
+
["Cache Exists", status.cache_exists ? "yes" : "no"],
|
|
31567
|
+
["Cache TTL Seconds", status.cache_ttl_seconds],
|
|
31568
|
+
["Cache Fetched At", status.cache_fetched_at],
|
|
31569
|
+
["Cache Age Seconds", status.cache_age_seconds],
|
|
31570
|
+
["Can Sync", status.can_sync ? "yes" : "no"],
|
|
31571
|
+
["Challenge Count", status.challenge_count],
|
|
31572
|
+
["Last Error", status.last_error]
|
|
31573
|
+
])
|
|
31574
|
+
].join("\n");
|
|
31575
|
+
}
|
|
31576
|
+
async function handleGetCatalogStatus() {
|
|
31577
|
+
try {
|
|
31578
|
+
const status = await getCatalogStatus();
|
|
31579
|
+
return buildTextResult(formatCatalogStatus(status), {
|
|
31580
|
+
catalog: status
|
|
31581
|
+
});
|
|
31582
|
+
} catch (error48) {
|
|
31583
|
+
return createInternalError(error48);
|
|
31584
|
+
}
|
|
31585
|
+
}
|
|
31586
|
+
async function handleSyncCatalog(params) {
|
|
31587
|
+
try {
|
|
31588
|
+
const result = await syncCatalog(params.force);
|
|
31589
|
+
const status = result.status;
|
|
31590
|
+
return buildTextResult(
|
|
31591
|
+
[
|
|
31592
|
+
"# Catalog Synced",
|
|
31593
|
+
"",
|
|
31594
|
+
formatFields([
|
|
31595
|
+
["Mode", status.mode],
|
|
31596
|
+
["Configured URL", status.configured_url],
|
|
31597
|
+
["Cache File", status.cache_file],
|
|
31598
|
+
["Challenge Count", status.challenge_count],
|
|
31599
|
+
["Last Error", status.last_error]
|
|
31600
|
+
])
|
|
31601
|
+
].join("\n"),
|
|
31602
|
+
{
|
|
31603
|
+
catalog: status,
|
|
31604
|
+
synced_challenges: result.challenges.map(
|
|
31605
|
+
(challenge) => challenge.challenge_id
|
|
31606
|
+
)
|
|
31607
|
+
}
|
|
31608
|
+
);
|
|
31609
|
+
} catch (error48) {
|
|
31610
|
+
if (error48 instanceof Error && error48.message.includes("BENCHMARK_CATALOG_URL")) {
|
|
31611
|
+
return createValidationError(
|
|
31612
|
+
"BENCHMARK_CATALOG_URL",
|
|
31613
|
+
"configure a remote catalog URL before syncing"
|
|
31614
|
+
);
|
|
31615
|
+
}
|
|
31616
|
+
return createInternalError(error48);
|
|
31617
|
+
}
|
|
31618
|
+
}
|
|
30848
31619
|
async function handleListChallenges(params) {
|
|
30849
31620
|
try {
|
|
30850
|
-
const challenges = await
|
|
31621
|
+
const challenges = await listChallenges();
|
|
30851
31622
|
const paginated = applyPagination(challenges, params);
|
|
30852
31623
|
const guidance = paginated.items.length > 0 ? createGuidanceStep(
|
|
30853
31624
|
"start_challenge",
|
|
@@ -30860,7 +31631,7 @@ async function handleListChallenges(params) {
|
|
|
30860
31631
|
"No benchmark suites are currently available."
|
|
30861
31632
|
);
|
|
30862
31633
|
const markdown = [
|
|
30863
|
-
"# Benchmark Challenges",
|
|
31634
|
+
"# Deterministic Benchmark Challenges",
|
|
30864
31635
|
"",
|
|
30865
31636
|
formatListItems(
|
|
30866
31637
|
paginated.items,
|
|
@@ -30896,29 +31667,18 @@ async function handleListChallenges(params) {
|
|
|
30896
31667
|
}
|
|
30897
31668
|
async function handleStartChallenge(params) {
|
|
30898
31669
|
try {
|
|
30899
|
-
const
|
|
30900
|
-
if (!adapter) {
|
|
30901
|
-
return createNotFoundError(`challenge ${params.challenge_id}`);
|
|
30902
|
-
}
|
|
30903
|
-
const challenge = await adapter.getChallengeDefinition(
|
|
30904
|
-
params.challenge_id
|
|
30905
|
-
);
|
|
31670
|
+
const challenge = await getChallengeDefinition(params.challenge_id);
|
|
30906
31671
|
if (!challenge) {
|
|
30907
31672
|
return createNotFoundError(`challenge ${params.challenge_id}`);
|
|
30908
31673
|
}
|
|
30909
31674
|
const attempt = await createAttempt(challenge);
|
|
30910
|
-
const
|
|
30911
|
-
if (!
|
|
31675
|
+
const currentTask = getCurrentTask(attempt);
|
|
31676
|
+
if (!currentTask) {
|
|
30912
31677
|
return createInternalError(
|
|
30913
|
-
new Error(
|
|
30914
|
-
`Challenge ${challenge.challenge_id} has no questions.`
|
|
30915
|
-
)
|
|
31678
|
+
new Error(`Challenge ${challenge.challenge_id} has no tasks.`)
|
|
30916
31679
|
);
|
|
30917
31680
|
}
|
|
30918
|
-
const guidance =
|
|
30919
|
-
attempt.attempt_id,
|
|
30920
|
-
currentQuestion
|
|
30921
|
-
);
|
|
31681
|
+
const guidance = getTaskGuidance(attempt.attempt_id, currentTask);
|
|
30922
31682
|
return buildTextResult(
|
|
30923
31683
|
[
|
|
30924
31684
|
`# ${challenge.title}`,
|
|
@@ -30926,15 +31686,17 @@ async function handleStartChallenge(params) {
|
|
|
30926
31686
|
formatFields([
|
|
30927
31687
|
["Attempt ID", attempt.attempt_id],
|
|
30928
31688
|
["Benchmark", attempt.benchmark_id],
|
|
31689
|
+
["Family", attempt.family],
|
|
31690
|
+
["Runner", attempt.runner_kind],
|
|
30929
31691
|
["Version", attempt.dataset_version],
|
|
30930
|
-
["
|
|
31692
|
+
["Tasks", attempt.total_tasks]
|
|
30931
31693
|
]),
|
|
30932
31694
|
"",
|
|
30933
|
-
|
|
31695
|
+
formatTaskBlock(
|
|
30934
31696
|
attempt.attempt_id,
|
|
30935
31697
|
1,
|
|
30936
|
-
attempt.
|
|
30937
|
-
|
|
31698
|
+
attempt.total_tasks,
|
|
31699
|
+
currentTask
|
|
30938
31700
|
)
|
|
30939
31701
|
].join("\n"),
|
|
30940
31702
|
{
|
|
@@ -30942,9 +31704,14 @@ async function handleStartChallenge(params) {
|
|
|
30942
31704
|
challenge_id: attempt.challenge_id,
|
|
30943
31705
|
benchmark_id: attempt.benchmark_id,
|
|
30944
31706
|
challenge_title: attempt.challenge_title,
|
|
31707
|
+
family: attempt.family,
|
|
31708
|
+
runner_kind: attempt.runner_kind,
|
|
31709
|
+
task_index: 1,
|
|
30945
31710
|
question_index: 1,
|
|
30946
|
-
|
|
30947
|
-
|
|
31711
|
+
total_tasks: attempt.total_tasks,
|
|
31712
|
+
total_questions: attempt.total_tasks,
|
|
31713
|
+
task: toPublicTask(currentTask),
|
|
31714
|
+
question: toPublicTask(currentTask),
|
|
30948
31715
|
done: false,
|
|
30949
31716
|
guidance
|
|
30950
31717
|
}
|
|
@@ -30965,26 +31732,39 @@ async function handleSubmitSolution(params) {
|
|
|
30965
31732
|
`attempt is ${attempt.status} and cannot accept submissions`
|
|
30966
31733
|
);
|
|
30967
31734
|
}
|
|
30968
|
-
const
|
|
30969
|
-
if (!
|
|
31735
|
+
const currentTask = getCurrentTask(attempt);
|
|
31736
|
+
if (!currentTask) {
|
|
30970
31737
|
return createInternalError(
|
|
30971
|
-
new Error(
|
|
30972
|
-
`Attempt ${attempt.attempt_id} has no current question.`
|
|
30973
|
-
)
|
|
31738
|
+
new Error(`Attempt ${attempt.attempt_id} has no current task.`)
|
|
30974
31739
|
);
|
|
30975
31740
|
}
|
|
30976
|
-
const
|
|
30977
|
-
|
|
30978
|
-
|
|
30979
|
-
|
|
30980
|
-
|
|
30981
|
-
|
|
30982
|
-
|
|
30983
|
-
|
|
30984
|
-
|
|
31741
|
+
const execution = await executeTaskRunner(
|
|
31742
|
+
attempt,
|
|
31743
|
+
currentTask,
|
|
31744
|
+
params.solution
|
|
31745
|
+
);
|
|
31746
|
+
const evaluation = evaluateTask(
|
|
31747
|
+
currentTask,
|
|
31748
|
+
params.solution,
|
|
31749
|
+
execution
|
|
31750
|
+
);
|
|
31751
|
+
const scoreDelta = evaluation.accepted ? 1 : 0;
|
|
31752
|
+
const updatedAttempt = await appendEvaluation(
|
|
31753
|
+
attempt.attempt_id,
|
|
31754
|
+
currentTask.task_id,
|
|
31755
|
+
{
|
|
31756
|
+
task_id: currentTask.task_id,
|
|
31757
|
+
solution: params.solution,
|
|
31758
|
+
accepted: evaluation.accepted,
|
|
31759
|
+
score_delta: scoreDelta,
|
|
31760
|
+
submitted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
31761
|
+
evidence: evaluation.evidence,
|
|
31762
|
+
execution
|
|
31763
|
+
}
|
|
31764
|
+
);
|
|
30985
31765
|
const totalScore = sumScore(updatedAttempt);
|
|
30986
|
-
const
|
|
30987
|
-
if (!
|
|
31766
|
+
const nextTask = getCurrentTask(updatedAttempt);
|
|
31767
|
+
if (!nextTask) {
|
|
30988
31768
|
const finalGuidance = {
|
|
30989
31769
|
primary: createGuidanceStep(
|
|
30990
31770
|
"complete",
|
|
@@ -30996,25 +31776,37 @@ async function handleSubmitSolution(params) {
|
|
|
30996
31776
|
"inspect_attempt",
|
|
30997
31777
|
"benchmark_get_attempt",
|
|
30998
31778
|
"Review the completed attempt summary.",
|
|
30999
|
-
{
|
|
31779
|
+
{
|
|
31780
|
+
attempt_id: updatedAttempt.attempt_id,
|
|
31781
|
+
limit: "20",
|
|
31782
|
+
offset: "0"
|
|
31783
|
+
}
|
|
31000
31784
|
)
|
|
31001
31785
|
]
|
|
31002
31786
|
};
|
|
31787
|
+
const evidenceLines2 = formatListItems(
|
|
31788
|
+
evaluation.evidence,
|
|
31789
|
+
(entry) => `- ${entry.passed ? "pass" : "fail"} \`${entry.checker_id}\`: ${entry.message}`
|
|
31790
|
+
);
|
|
31003
31791
|
return buildTextResult(
|
|
31004
31792
|
[
|
|
31005
31793
|
"# Challenge Complete",
|
|
31006
31794
|
"",
|
|
31007
31795
|
formatFields([
|
|
31008
31796
|
["Attempt ID", updatedAttempt.attempt_id],
|
|
31009
|
-
["Accepted", accepted ? "yes" : "no"],
|
|
31797
|
+
["Accepted", evaluation.accepted ? "yes" : "no"],
|
|
31010
31798
|
["Score Delta", scoreDelta],
|
|
31011
31799
|
[
|
|
31012
31800
|
"Total Score",
|
|
31013
|
-
`${totalScore}/${updatedAttempt.
|
|
31801
|
+
`${totalScore}/${updatedAttempt.total_tasks}`
|
|
31014
31802
|
]
|
|
31015
31803
|
]),
|
|
31016
31804
|
"",
|
|
31017
|
-
|
|
31805
|
+
"## Checker Evidence",
|
|
31806
|
+
"",
|
|
31807
|
+
evidenceLines2,
|
|
31808
|
+
"",
|
|
31809
|
+
formatRunnerExecution(execution),
|
|
31018
31810
|
"",
|
|
31019
31811
|
"## Next Step",
|
|
31020
31812
|
"",
|
|
@@ -31024,22 +31816,25 @@ async function handleSubmitSolution(params) {
|
|
|
31024
31816
|
].join("\n"),
|
|
31025
31817
|
{
|
|
31026
31818
|
attempt_id: updatedAttempt.attempt_id,
|
|
31027
|
-
accepted,
|
|
31819
|
+
accepted: evaluation.accepted,
|
|
31028
31820
|
score_delta: scoreDelta,
|
|
31029
31821
|
total_score: totalScore,
|
|
31030
31822
|
done: true,
|
|
31823
|
+
evidence: evaluation.evidence,
|
|
31824
|
+
execution,
|
|
31031
31825
|
final_result: {
|
|
31032
31826
|
total_score: totalScore,
|
|
31033
|
-
max_score: updatedAttempt.
|
|
31034
|
-
passed: totalScore === updatedAttempt.
|
|
31827
|
+
max_score: updatedAttempt.total_tasks,
|
|
31828
|
+
passed: totalScore === updatedAttempt.total_tasks
|
|
31035
31829
|
},
|
|
31036
31830
|
guidance: finalGuidance
|
|
31037
31831
|
}
|
|
31038
31832
|
);
|
|
31039
31833
|
}
|
|
31040
|
-
const guidance =
|
|
31041
|
-
|
|
31042
|
-
|
|
31834
|
+
const guidance = getTaskGuidance(updatedAttempt.attempt_id, nextTask);
|
|
31835
|
+
const evidenceLines = formatListItems(
|
|
31836
|
+
evaluation.evidence,
|
|
31837
|
+
(entry) => `- ${entry.passed ? "pass" : "fail"} \`${entry.checker_id}\`: ${entry.message}`
|
|
31043
31838
|
);
|
|
31044
31839
|
return buildTextResult(
|
|
31045
31840
|
[
|
|
@@ -31047,31 +31842,40 @@ async function handleSubmitSolution(params) {
|
|
|
31047
31842
|
"",
|
|
31048
31843
|
formatFields([
|
|
31049
31844
|
["Attempt ID", updatedAttempt.attempt_id],
|
|
31050
|
-
["Accepted", accepted ? "yes" : "no"],
|
|
31845
|
+
["Accepted", evaluation.accepted ? "yes" : "no"],
|
|
31051
31846
|
["Score Delta", scoreDelta],
|
|
31052
31847
|
[
|
|
31053
31848
|
"Total Score",
|
|
31054
|
-
`${totalScore}/${updatedAttempt.
|
|
31849
|
+
`${totalScore}/${updatedAttempt.total_tasks}`
|
|
31055
31850
|
]
|
|
31056
31851
|
]),
|
|
31057
31852
|
"",
|
|
31058
|
-
|
|
31853
|
+
"## Checker Evidence",
|
|
31854
|
+
"",
|
|
31855
|
+
evidenceLines,
|
|
31856
|
+
"",
|
|
31857
|
+
formatRunnerExecution(execution),
|
|
31059
31858
|
"",
|
|
31060
|
-
|
|
31859
|
+
formatTaskBlock(
|
|
31061
31860
|
updatedAttempt.attempt_id,
|
|
31062
|
-
updatedAttempt.
|
|
31063
|
-
updatedAttempt.
|
|
31064
|
-
|
|
31861
|
+
updatedAttempt.current_task_index + 1,
|
|
31862
|
+
updatedAttempt.total_tasks,
|
|
31863
|
+
nextTask
|
|
31065
31864
|
)
|
|
31066
31865
|
].join("\n"),
|
|
31067
31866
|
{
|
|
31068
31867
|
attempt_id: updatedAttempt.attempt_id,
|
|
31069
|
-
accepted,
|
|
31868
|
+
accepted: evaluation.accepted,
|
|
31070
31869
|
score_delta: scoreDelta,
|
|
31071
31870
|
total_score: totalScore,
|
|
31072
|
-
|
|
31073
|
-
|
|
31074
|
-
|
|
31871
|
+
task_index: updatedAttempt.current_task_index + 1,
|
|
31872
|
+
question_index: updatedAttempt.current_task_index + 1,
|
|
31873
|
+
total_tasks: updatedAttempt.total_tasks,
|
|
31874
|
+
total_questions: updatedAttempt.total_tasks,
|
|
31875
|
+
evidence: evaluation.evidence,
|
|
31876
|
+
execution,
|
|
31877
|
+
next_task: toPublicTask(nextTask),
|
|
31878
|
+
next_question: toPublicTask(nextTask),
|
|
31075
31879
|
done: false,
|
|
31076
31880
|
guidance
|
|
31077
31881
|
}
|
|
@@ -31086,15 +31890,15 @@ async function handleGetAsset(params) {
|
|
|
31086
31890
|
if (!attempt) {
|
|
31087
31891
|
return createNotFoundError(`attempt ${params.attempt_id}`);
|
|
31088
31892
|
}
|
|
31089
|
-
const
|
|
31893
|
+
const task = attempt.tasks.find(
|
|
31090
31894
|
(candidate) => candidate.assets.some(
|
|
31091
31895
|
(asset2) => asset2.asset_id === params.asset_id
|
|
31092
31896
|
)
|
|
31093
31897
|
);
|
|
31094
|
-
const asset =
|
|
31898
|
+
const asset = task?.assets.find(
|
|
31095
31899
|
(candidate) => candidate.asset_id === params.asset_id
|
|
31096
31900
|
);
|
|
31097
|
-
if (!asset || !
|
|
31901
|
+
if (!asset || !task) {
|
|
31098
31902
|
return createNotFoundError(`asset ${params.asset_id}`);
|
|
31099
31903
|
}
|
|
31100
31904
|
const guidance = {
|
|
@@ -31104,15 +31908,19 @@ async function handleGetAsset(params) {
|
|
|
31104
31908
|
"Submit the answer after reviewing the asset.",
|
|
31105
31909
|
{
|
|
31106
31910
|
attempt_id: attempt.attempt_id,
|
|
31107
|
-
solution:
|
|
31911
|
+
solution: createSubmitExample(task)
|
|
31108
31912
|
}
|
|
31109
31913
|
),
|
|
31110
31914
|
alternatives: [
|
|
31111
31915
|
createGuidanceStep(
|
|
31112
31916
|
"inspect_attempt",
|
|
31113
31917
|
"benchmark_get_attempt",
|
|
31114
|
-
"Review the current
|
|
31115
|
-
{
|
|
31918
|
+
"Review the current task again.",
|
|
31919
|
+
{
|
|
31920
|
+
attempt_id: attempt.attempt_id,
|
|
31921
|
+
limit: "20",
|
|
31922
|
+
offset: "0"
|
|
31923
|
+
}
|
|
31116
31924
|
)
|
|
31117
31925
|
]
|
|
31118
31926
|
};
|
|
@@ -31122,8 +31930,10 @@ async function handleGetAsset(params) {
|
|
|
31122
31930
|
"",
|
|
31123
31931
|
formatFields([
|
|
31124
31932
|
["Attempt ID", attempt.attempt_id],
|
|
31125
|
-
["
|
|
31933
|
+
["Task ID", task.task_id],
|
|
31126
31934
|
["Mime Type", asset.mime_type],
|
|
31935
|
+
["Transport", asset.transport],
|
|
31936
|
+
["Materialization", asset.materialization],
|
|
31127
31937
|
["Encoding", asset.encoding]
|
|
31128
31938
|
]),
|
|
31129
31939
|
"",
|
|
@@ -31143,6 +31953,8 @@ async function handleGetAsset(params) {
|
|
|
31143
31953
|
asset_id: asset.asset_id,
|
|
31144
31954
|
name: asset.name,
|
|
31145
31955
|
mime_type: asset.mime_type,
|
|
31956
|
+
transport: asset.transport,
|
|
31957
|
+
materialization: asset.materialization,
|
|
31146
31958
|
encoding: asset.encoding,
|
|
31147
31959
|
description: asset.description,
|
|
31148
31960
|
content: asset.content
|
|
@@ -31160,8 +31972,9 @@ async function handleGetAttempt(params) {
|
|
|
31160
31972
|
if (!attempt) {
|
|
31161
31973
|
return createNotFoundError(`attempt ${params.attempt_id}`);
|
|
31162
31974
|
}
|
|
31163
|
-
const
|
|
31164
|
-
const
|
|
31975
|
+
const currentTask = getCurrentTask(attempt);
|
|
31976
|
+
const evaluationPage = applyPagination(attempt.evaluations, params);
|
|
31977
|
+
const guidance = currentTask && attempt.status === "active" ? getTaskGuidance(attempt.attempt_id, currentTask) : {
|
|
31165
31978
|
primary: createGuidanceStep(
|
|
31166
31979
|
"complete",
|
|
31167
31980
|
null,
|
|
@@ -31169,6 +31982,27 @@ async function handleGetAttempt(params) {
|
|
|
31169
31982
|
),
|
|
31170
31983
|
alternatives: []
|
|
31171
31984
|
};
|
|
31985
|
+
const historyText = formatListItems(
|
|
31986
|
+
evaluationPage.items,
|
|
31987
|
+
(evaluation, index) => {
|
|
31988
|
+
const evidenceLines = evaluation.evidence.map(
|
|
31989
|
+
(entry) => ` - ${entry.passed ? "pass" : "fail"} \`${entry.checker_id}\`: ${entry.message}`
|
|
31990
|
+
).join("\n");
|
|
31991
|
+
return [
|
|
31992
|
+
`### Evaluation ${evaluationPage.offset + index + 1}`,
|
|
31993
|
+
formatFields([
|
|
31994
|
+
["Task ID", evaluation.task_id],
|
|
31995
|
+
["Accepted", evaluation.accepted ? "yes" : "no"],
|
|
31996
|
+
["Score Delta", evaluation.score_delta]
|
|
31997
|
+
]),
|
|
31998
|
+
"",
|
|
31999
|
+
formatRunnerExecution(evaluation.execution),
|
|
32000
|
+
"",
|
|
32001
|
+
evidenceLines
|
|
32002
|
+
].join("\n");
|
|
32003
|
+
},
|
|
32004
|
+
"_No submissions recorded yet._"
|
|
32005
|
+
);
|
|
31172
32006
|
return buildTextResult(
|
|
31173
32007
|
[
|
|
31174
32008
|
"# Attempt Status",
|
|
@@ -31176,32 +32010,50 @@ async function handleGetAttempt(params) {
|
|
|
31176
32010
|
formatFields([
|
|
31177
32011
|
["Attempt ID", attempt.attempt_id],
|
|
31178
32012
|
["Challenge", attempt.challenge_title],
|
|
32013
|
+
["Family", attempt.family],
|
|
32014
|
+
["Runner", attempt.runner_kind],
|
|
31179
32015
|
["Status", attempt.status],
|
|
32016
|
+
["Revision", attempt.revision],
|
|
31180
32017
|
[
|
|
31181
32018
|
"Progress",
|
|
31182
|
-
`${attempt.
|
|
32019
|
+
`${attempt.current_task_index}/${attempt.total_tasks}`
|
|
31183
32020
|
],
|
|
31184
|
-
[
|
|
31185
|
-
"Score",
|
|
31186
|
-
`${sumScore(attempt)}/${attempt.total_questions}`
|
|
31187
|
-
]
|
|
32021
|
+
["Score", `${sumScore(attempt)}/${attempt.total_tasks}`]
|
|
31188
32022
|
]),
|
|
31189
32023
|
"",
|
|
31190
|
-
|
|
32024
|
+
currentTask ? formatTaskBlock(
|
|
31191
32025
|
attempt.attempt_id,
|
|
31192
|
-
attempt.
|
|
31193
|
-
attempt.
|
|
31194
|
-
|
|
31195
|
-
) : "No current
|
|
31196
|
-
|
|
32026
|
+
attempt.current_task_index + 1,
|
|
32027
|
+
attempt.total_tasks,
|
|
32028
|
+
currentTask
|
|
32029
|
+
) : "No current task is available.",
|
|
32030
|
+
"",
|
|
32031
|
+
"## Evaluation History",
|
|
32032
|
+
"",
|
|
32033
|
+
historyText,
|
|
32034
|
+
evaluationPage.hasMore ? formatPaginationFooter(
|
|
32035
|
+
evaluationPage.offset,
|
|
32036
|
+
evaluationPage.limit,
|
|
32037
|
+
evaluationPage.total
|
|
32038
|
+
) : ""
|
|
32039
|
+
].filter(Boolean).join("\n"),
|
|
31197
32040
|
{
|
|
31198
32041
|
attempt_id: attempt.attempt_id,
|
|
31199
32042
|
challenge_id: attempt.challenge_id,
|
|
31200
32043
|
status: attempt.status,
|
|
31201
32044
|
total_score: sumScore(attempt),
|
|
31202
|
-
|
|
31203
|
-
|
|
31204
|
-
|
|
32045
|
+
total_tasks: attempt.total_tasks,
|
|
32046
|
+
total_questions: attempt.total_tasks,
|
|
32047
|
+
current_task_index: attempt.current_task_index,
|
|
32048
|
+
current_question_index: attempt.current_task_index,
|
|
32049
|
+
current_task: currentTask ? toPublicTask(currentTask) : null,
|
|
32050
|
+
current_question: currentTask ? toPublicTask(currentTask) : null,
|
|
32051
|
+
evaluations: evaluationPage.items,
|
|
32052
|
+
history: evaluationPage.items,
|
|
32053
|
+
history_total: evaluationPage.total,
|
|
32054
|
+
offset: evaluationPage.offset,
|
|
32055
|
+
limit: evaluationPage.limit,
|
|
32056
|
+
has_more: evaluationPage.hasMore,
|
|
31205
32057
|
guidance
|
|
31206
32058
|
}
|
|
31207
32059
|
);
|
|
@@ -31221,7 +32073,7 @@ async function handleCancelAttempt(params) {
|
|
|
31221
32073
|
`attempt is already ${attempt.status}`
|
|
31222
32074
|
);
|
|
31223
32075
|
}
|
|
31224
|
-
const cancelled = await cancelAttempt(attempt);
|
|
32076
|
+
const cancelled = await cancelAttempt(attempt.attempt_id);
|
|
31225
32077
|
return buildTextResult(
|
|
31226
32078
|
[
|
|
31227
32079
|
"# Attempt Cancelled",
|
|
@@ -31229,7 +32081,8 @@ async function handleCancelAttempt(params) {
|
|
|
31229
32081
|
formatFields([
|
|
31230
32082
|
["Attempt ID", cancelled.attempt_id],
|
|
31231
32083
|
["Challenge", cancelled.challenge_title],
|
|
31232
|
-
["Status", cancelled.status]
|
|
32084
|
+
["Status", cancelled.status],
|
|
32085
|
+
["Revision", cancelled.revision]
|
|
31233
32086
|
])
|
|
31234
32087
|
].join("\n"),
|
|
31235
32088
|
{
|
|
@@ -31253,7 +32106,7 @@ server.registerTool(
|
|
|
31253
32106
|
"benchmark_list_challenges",
|
|
31254
32107
|
{
|
|
31255
32108
|
title: "List Challenges",
|
|
31256
|
-
description: "List benchmark suites and
|
|
32109
|
+
description: "List deterministic benchmark suites and metadata.",
|
|
31257
32110
|
inputSchema: listChallengesInputSchema,
|
|
31258
32111
|
annotations: {
|
|
31259
32112
|
readOnlyHint: true,
|
|
@@ -31262,11 +32115,36 @@ server.registerTool(
|
|
|
31262
32115
|
},
|
|
31263
32116
|
handleListChallenges
|
|
31264
32117
|
);
|
|
32118
|
+
server.registerTool(
|
|
32119
|
+
"benchmark_get_catalog_status",
|
|
32120
|
+
{
|
|
32121
|
+
title: "Get Catalog Status",
|
|
32122
|
+
description: "Inspect catalog source and cache status.",
|
|
32123
|
+
inputSchema: getCatalogStatusInputSchema,
|
|
32124
|
+
annotations: {
|
|
32125
|
+
readOnlyHint: true,
|
|
32126
|
+
idempotentHint: true
|
|
32127
|
+
}
|
|
32128
|
+
},
|
|
32129
|
+
handleGetCatalogStatus
|
|
32130
|
+
);
|
|
32131
|
+
server.registerTool(
|
|
32132
|
+
"benchmark_sync_catalog",
|
|
32133
|
+
{
|
|
32134
|
+
title: "Sync Catalog",
|
|
32135
|
+
description: "Fetch and cache the remote benchmark catalog.",
|
|
32136
|
+
inputSchema: syncCatalogInputSchema,
|
|
32137
|
+
annotations: {
|
|
32138
|
+
idempotentHint: true
|
|
32139
|
+
}
|
|
32140
|
+
},
|
|
32141
|
+
handleSyncCatalog
|
|
32142
|
+
);
|
|
31265
32143
|
server.registerTool(
|
|
31266
32144
|
"benchmark_start_challenge",
|
|
31267
32145
|
{
|
|
31268
32146
|
title: "Start Challenge",
|
|
31269
|
-
description: "Start an attempt and return the first
|
|
32147
|
+
description: "Start an attempt and return the first task.",
|
|
31270
32148
|
inputSchema: startChallengeInputSchema
|
|
31271
32149
|
},
|
|
31272
32150
|
handleStartChallenge
|
|
@@ -31275,7 +32153,7 @@ server.registerTool(
|
|
|
31275
32153
|
"benchmark_submit_solution",
|
|
31276
32154
|
{
|
|
31277
32155
|
title: "Submit Solution",
|
|
31278
|
-
description: "Grade one
|
|
32156
|
+
description: "Grade one task and advance the attempt.",
|
|
31279
32157
|
inputSchema: submitSolutionInputSchema
|
|
31280
32158
|
},
|
|
31281
32159
|
handleSubmitSolution
|
|
@@ -31297,7 +32175,7 @@ server.registerTool(
|
|
|
31297
32175
|
"benchmark_get_attempt",
|
|
31298
32176
|
{
|
|
31299
32177
|
title: "Get Attempt",
|
|
31300
|
-
description: "Inspect attempt status and
|
|
32178
|
+
description: "Inspect attempt status, tasks, and evidence.",
|
|
31301
32179
|
inputSchema: getAttemptInputSchema,
|
|
31302
32180
|
annotations: {
|
|
31303
32181
|
readOnlyHint: true,
|
|
@@ -31310,24 +32188,19 @@ server.registerTool(
|
|
|
31310
32188
|
"benchmark_cancel_attempt",
|
|
31311
32189
|
{
|
|
31312
32190
|
title: "Cancel Attempt",
|
|
31313
|
-
description: "Cancel an active
|
|
32191
|
+
description: "Cancel an active attempt.",
|
|
31314
32192
|
inputSchema: cancelAttemptInputSchema
|
|
31315
32193
|
},
|
|
31316
32194
|
handleCancelAttempt
|
|
31317
32195
|
);
|
|
31318
32196
|
async function main() {
|
|
31319
|
-
if (IS_MOCK) {
|
|
31320
|
-
console.error(
|
|
31321
|
-
"[benchmark] Running in MOCK mode \u2014 using built-in benchmark fixtures."
|
|
31322
|
-
);
|
|
31323
|
-
}
|
|
31324
32197
|
const transport = new StdioServerTransport();
|
|
31325
32198
|
await server.connect(transport);
|
|
31326
32199
|
console.error("[benchmark] MCP server running via stdio");
|
|
31327
32200
|
}
|
|
31328
|
-
if (process.
|
|
32201
|
+
if (process.argv[1] && import.meta.url.endsWith(process.argv[1])) {
|
|
31329
32202
|
main().catch((error48) => {
|
|
31330
|
-
console.error("
|
|
32203
|
+
console.error("[benchmark] fatal error", error48);
|
|
31331
32204
|
process.exit(1);
|
|
31332
32205
|
});
|
|
31333
32206
|
}
|
|
@@ -31335,8 +32208,10 @@ export {
|
|
|
31335
32208
|
handleCancelAttempt,
|
|
31336
32209
|
handleGetAsset,
|
|
31337
32210
|
handleGetAttempt,
|
|
32211
|
+
handleGetCatalogStatus,
|
|
31338
32212
|
handleListChallenges,
|
|
31339
32213
|
handleStartChallenge,
|
|
31340
32214
|
handleSubmitSolution,
|
|
32215
|
+
handleSyncCatalog,
|
|
31341
32216
|
server
|
|
31342
32217
|
};
|