oasis_test 0.1.81 → 0.1.82

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.
Files changed (2) hide show
  1. package/dist/index.js +1259 -301
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2243,61 +2243,181 @@ var init_collab_view = __esm({
2243
2243
  });
2244
2244
 
2245
2245
  // ../contract/src/evaluation.ts
2246
- function calculateSpecialtyScore(dimensions) {
2247
- if (dimensions.length !== 5 || dimensions.some((dimension) => dimension.score === null)) {
2248
- return null;
2249
- }
2250
- const scores = dimensions.map((dimension) => dimension.score);
2251
- if (scores.some((score2) => score2 < 1 || score2 > 5)) {
2252
- throw new Error("S \u4E13\u9879\u7EF4\u5EA6\u5206\u5FC5\u987B\u5728 1-5 \u4E4B\u95F4");
2253
- }
2254
- const score = scores.reduce((sum, value2) => sum + value2, 0) / scores.length;
2255
- return { score, score100: score * 20 };
2256
- }
2257
2246
  function assertScore(value2, min2, max, label, nullable2 = false) {
2258
2247
  if (nullable2 && value2 === null) return;
2259
2248
  if (typeof value2 !== "number" || !Number.isFinite(value2) || value2 < min2 || value2 > max) {
2260
2249
  throw new Error(`${label} \u5FC5\u987B\u5728 ${min2}-${max} \u4E4B\u95F4${nullable2 ? "\u6216\u4E3A null" : ""}`);
2261
2250
  }
2262
2251
  }
2263
- function validateEvaluationResult(value2) {
2264
- if (!value2 || typeof value2 !== "object") throw new Error("\u8BC4\u5206\u7ED3\u679C\u5FC5\u987B\u662F\u5BF9\u8C61");
2265
- const result = value2;
2266
- if (!Array.isArray(result.common?.dimensions) || result.common.dimensions.length !== 7) {
2267
- throw new Error("\u901A\u7528\u80FD\u529B\u5FC5\u987B\u5305\u542B G1-G7 \u4E03\u4E2A\u7EF4\u5EA6");
2268
- }
2269
- const commonIds = result.common.dimensions.map((dimension) => dimension.id);
2270
- for (const id of ["G1", "G2", "G3", "G4", "G5", "G6", "G7"]) {
2271
- if (!commonIds.includes(id)) throw new Error(`\u901A\u7528\u80FD\u529B\u7F3A\u5C11 ${id}`);
2252
+ function validateSection(result, spec) {
2253
+ const section = sectionOf(result, spec.sectionKey);
2254
+ if (!section) throw new Error(`\u7F3A\u5C11\u8BC4\u5206\u6BB5 ${spec.sectionKey}`);
2255
+ if (!spec.dimensions.length) {
2256
+ if (!Array.isArray(section["items"])) throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7F3A\u5C11\u8BC4\u5206\u9879`);
2257
+ return;
2272
2258
  }
2273
- for (const dimension of result.common.dimensions) {
2274
- assertScore(dimension.score, 1, 5, dimension.id, dimension.id === "G6");
2259
+ const dimensions = section["dimensions"];
2260
+ if (!Array.isArray(dimensions) || dimensions.length !== spec.dimensions.length) {
2261
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u5FC5\u987B\u5305\u542B ${spec.dimensions.length} \u4E2A\u7EF4\u5EA6`);
2275
2262
  }
2276
- if (!Array.isArray(result.specialty?.dimensions)) throw new Error("\u7F3A\u5C11 S \u4E13\u9879\u7EF4\u5EA6");
2277
- if (result.specialty.dimensions.length !== 5) throw new Error("S \u4E13\u9879\u5FC5\u987B\u5305\u542B\u4E94\u4E2A\u7EF4\u5EA6");
2278
- const calculated = calculateSpecialtyScore(result.specialty.dimensions);
2279
- if (calculated) {
2280
- if (Math.abs((result.specialty.score ?? Number.NaN) - calculated.score) > 1e-9) {
2281
- throw new Error("S \u4E13\u9879\u5E73\u5747\u5206\u4E0E\u4E94\u4E2A\u7EF4\u5EA6\u4E0D\u4E00\u81F4");
2263
+ const byId = new Map(
2264
+ dimensions.map((dimension) => [dimension?.id, dimension])
2265
+ );
2266
+ spec.dimensions.forEach((expected, index) => {
2267
+ const dimension = spec.strictIds === false ? dimensions[index] : byId.get(expected.id);
2268
+ if (!dimension) throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7F3A\u5C11 ${expected.id}`);
2269
+ assertScore(dimension.score, expected.min, expected.max, expected.id, expected.nullable === true);
2270
+ });
2271
+ if (spec.aggregation !== "mean") return;
2272
+ const scores = dimensions.map((dimension) => dimension.score);
2273
+ const complete = scores.every((value2) => typeof value2 === "number");
2274
+ const score = section["score"];
2275
+ const score100 = section["score100"];
2276
+ if (complete) {
2277
+ const mean = scores.reduce((sum, value2) => sum + value2, 0) / scores.length;
2278
+ const max = spec.dimensions[0]?.max ?? 5;
2279
+ if (Math.abs((typeof score === "number" ? score : Number.NaN) - mean) > 1e-9) {
2280
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7684\u5E73\u5747\u5206\u4E0E\u7EF4\u5EA6\u4E0D\u4E00\u81F4`);
2282
2281
  }
2283
- if (Math.abs((result.specialty.score100 ?? Number.NaN) - calculated.score100) > 1e-9) {
2284
- throw new Error("S \u4E13\u9879\u767E\u5206\u5236\u5206\u6570\u4E0E\u4E94\u4E2A\u7EF4\u5EA6\u4E0D\u4E00\u81F4");
2282
+ if (Math.abs((typeof score100 === "number" ? score100 : Number.NaN) - mean * (100 / max)) > 1e-9) {
2283
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7684\u767E\u5206\u5236\u5206\u6570\u4E0E\u7EF4\u5EA6\u4E0D\u4E00\u81F4`);
2285
2284
  }
2286
- } else if (result.specialty.score !== null || result.specialty.score100 !== null) {
2287
- throw new Error("S \u4E13\u9879\u7EF4\u5EA6\u4E0D\u5B8C\u6574\u65F6\u4E0D\u80FD\u751F\u6210\u4E13\u9879\u5206");
2285
+ } else if (score !== null || score100 !== null) {
2286
+ throw new Error(`\u8BC4\u5206\u6BB5 ${spec.sectionKey} \u7EF4\u5EA6\u4E0D\u5B8C\u6574\u65F6\u4E0D\u80FD\u751F\u6210\u6BB5\u5206`);
2288
2287
  }
2289
- if (!Array.isArray(result.caseSpecial?.items)) throw new Error("\u7F3A\u5C11 Case Special \u8BC4\u5206\u9879");
2290
- assertScore(result.caseSpecial.score100, 0, 100, "Case Special", true);
2291
- if (!result.runtimeMetrics || typeof result.runtimeMetrics !== "object") {
2288
+ }
2289
+ function validateEvaluationResult(value2, specs = BUILTIN_OUTPUT_SPECS) {
2290
+ if (!value2 || typeof value2 !== "object") throw new Error("\u8BC4\u5206\u7ED3\u679C\u5FC5\u987B\u662F\u5BF9\u8C61");
2291
+ const result = value2;
2292
+ for (const spec of specs.length ? specs : BUILTIN_OUTPUT_SPECS) validateSection(result, spec);
2293
+ const caseSpecial = sectionOf(result, "caseSpecial");
2294
+ if (caseSpecial) assertScore(caseSpecial["score100"], 0, 100, "Case Special", true);
2295
+ if (!result["runtimeMetrics"] || typeof result["runtimeMetrics"] !== "object") {
2292
2296
  throw new Error("\u7F3A\u5C11\u8FD0\u884C\u6307\u6807");
2293
2297
  }
2294
2298
  return structuredClone(result);
2295
2299
  }
2296
- var isEvaluationEligibleWorkorder;
2300
+ var isEvaluationEligibleWorkorder, BUILTIN_COMMON_OUTPUT_SPEC, BUILTIN_SPECIALTY_OUTPUT_SPEC, BUILTIN_CASE_SPECIAL_OUTPUT_SPEC, BUILTIN_OUTPUT_SPECS, sectionOf;
2297
2301
  var init_evaluation = __esm({
2298
2302
  "../contract/src/evaluation.ts"() {
2299
2303
  "use strict";
2300
2304
  isEvaluationEligibleWorkorder = (workorder) => workorder.stage === "concluded";
2305
+ BUILTIN_COMMON_OUTPUT_SPEC = {
2306
+ sectionKey: "common",
2307
+ aggregation: "none",
2308
+ dimensions: [
2309
+ { id: "G1", label: "G1", min: 1, max: 5 },
2310
+ { id: "G2", label: "G2", min: 1, max: 5 },
2311
+ { id: "G3", label: "G3", min: 1, max: 5 },
2312
+ { id: "G4", label: "G4", min: 1, max: 5 },
2313
+ { id: "G5", label: "G5", min: 1, max: 5 },
2314
+ { id: "G6", label: "G6", min: 1, max: 5, nullable: true },
2315
+ { id: "G7", label: "G7", min: 1, max: 5 }
2316
+ ]
2317
+ };
2318
+ BUILTIN_SPECIALTY_OUTPUT_SPEC = {
2319
+ sectionKey: "specialty",
2320
+ aggregation: "mean",
2321
+ // strictIds=false:五项的 id 由各 S 类标准自己定,历史校验也只数个数不认 id。
2322
+ strictIds: false,
2323
+ // nullable:S 专项允许整段不评分(没有可读专业产物时五项全 null,段分随之为 null)——
2324
+ // 这是既有语义,见 enforceSpecialtyArtifactBoundary。段分一致性由 aggregation 那条兜住。
2325
+ dimensions: Array.from({ length: 5 }, (_unused, index) => ({
2326
+ id: `S${index + 1}`,
2327
+ label: `S${index + 1}`,
2328
+ min: 1,
2329
+ max: 5,
2330
+ nullable: true
2331
+ }))
2332
+ };
2333
+ BUILTIN_CASE_SPECIAL_OUTPUT_SPEC = {
2334
+ sectionKey: "caseSpecial",
2335
+ aggregation: "none",
2336
+ dimensions: []
2337
+ };
2338
+ BUILTIN_OUTPUT_SPECS = [
2339
+ BUILTIN_COMMON_OUTPUT_SPEC,
2340
+ BUILTIN_SPECIALTY_OUTPUT_SPEC,
2341
+ BUILTIN_CASE_SPECIAL_OUTPUT_SPEC
2342
+ ];
2343
+ sectionOf = (result, key) => {
2344
+ const section = result[key];
2345
+ return section && typeof section === "object" && !Array.isArray(section) ? section : void 0;
2346
+ };
2347
+ }
2348
+ });
2349
+
2350
+ // ../contract/src/evaluation-rubric.ts
2351
+ function validateEvaluationRubricOutputSpec(value2) {
2352
+ if (!value2 || typeof value2 !== "object") throw new Error("\u8F93\u51FA\u5951\u7EA6\u5FC5\u987B\u662F\u5BF9\u8C61");
2353
+ const spec = value2;
2354
+ if (typeof spec.sectionKey !== "string" || !spec.sectionKey.trim()) {
2355
+ throw new Error("\u8F93\u51FA\u5951\u7EA6\u7F3A\u5C11 sectionKey");
2356
+ }
2357
+ if (spec.aggregation !== "none" && spec.aggregation !== "mean") {
2358
+ throw new Error("aggregation \u53EA\u80FD\u662F none \u6216 mean");
2359
+ }
2360
+ if (!Array.isArray(spec.dimensions)) throw new Error("dimensions \u5FC5\u987B\u662F\u6570\u7EC4");
2361
+ const seen = /* @__PURE__ */ new Set();
2362
+ for (const dimension of spec.dimensions) {
2363
+ if (!dimension || typeof dimension !== "object") throw new Error("\u7EF4\u5EA6\u5FC5\u987B\u662F\u5BF9\u8C61");
2364
+ if (typeof dimension.id !== "string" || !DIMENSION_ID.test(dimension.id)) {
2365
+ throw new Error(`\u7EF4\u5EA6 id \u975E\u6CD5\uFF1A${String(dimension.id)}`);
2366
+ }
2367
+ if (seen.has(dimension.id)) throw new Error(`\u7EF4\u5EA6 id \u91CD\u590D\uFF1A${dimension.id}`);
2368
+ seen.add(dimension.id);
2369
+ if (typeof dimension.label !== "string" || !dimension.label.trim()) {
2370
+ throw new Error(`\u7EF4\u5EA6 ${dimension.id} \u7F3A\u5C11 label`);
2371
+ }
2372
+ if (typeof dimension.min !== "number" || typeof dimension.max !== "number" || !Number.isFinite(dimension.min) || !Number.isFinite(dimension.max) || dimension.min >= dimension.max) {
2373
+ throw new Error(`\u7EF4\u5EA6 ${dimension.id} \u7684\u5206\u503C\u533A\u95F4\u975E\u6CD5`);
2374
+ }
2375
+ }
2376
+ return {
2377
+ sectionKey: spec.sectionKey.trim(),
2378
+ aggregation: spec.aggregation,
2379
+ ...spec.strictIds === false ? { strictIds: false } : {},
2380
+ dimensions: spec.dimensions.map((dimension) => ({
2381
+ id: dimension.id,
2382
+ label: dimension.label,
2383
+ min: dimension.min,
2384
+ max: dimension.max,
2385
+ ...dimension.nullable ? { nullable: true } : {}
2386
+ }))
2387
+ };
2388
+ }
2389
+ function validateUpsertEvaluationRubricInput(value2) {
2390
+ if (!value2 || typeof value2 !== "object") throw new Error("\u8BC4\u5206\u6807\u51C6\u5FC5\u987B\u662F\u5BF9\u8C61");
2391
+ const input = value2;
2392
+ if (typeof input.name !== "string" || !input.name.trim()) throw new Error("\u8BC4\u5206\u6807\u51C6\u7F3A\u5C11\u540D\u79F0");
2393
+ if (input.kind !== "common" && input.kind !== "specialty" && input.kind !== "case_special") {
2394
+ throw new Error("kind \u53EA\u80FD\u662F common / specialty / case_special");
2395
+ }
2396
+ if (typeof input.promptSection !== "string" || !input.promptSection.trim()) {
2397
+ throw new Error("\u8BC4\u5206\u6807\u51C6\u6B63\u6587\u4E0D\u80FD\u4E3A\u7A7A");
2398
+ }
2399
+ if (input.status !== void 0 && input.status !== "active" && input.status !== "archived") {
2400
+ throw new Error("status \u53EA\u80FD\u662F active \u6216 archived");
2401
+ }
2402
+ return {
2403
+ ...typeof input.rubricId === "string" && input.rubricId ? { rubricId: input.rubricId } : {},
2404
+ name: input.name.trim(),
2405
+ kind: input.kind,
2406
+ ...typeof input.description === "string" && input.description.trim() ? { description: input.description.trim() } : {},
2407
+ promptSection: input.promptSection,
2408
+ outputSpec: validateEvaluationRubricOutputSpec(input.outputSpec),
2409
+ ...input.status ? { status: input.status } : {}
2410
+ };
2411
+ }
2412
+ function rubricVersionOf(rubrics, fallback) {
2413
+ if (!rubrics.length) return fallback;
2414
+ return rubrics.map((rubric) => `${rubric.rubricId}@${rubric.version}`).join("+");
2415
+ }
2416
+ var DIMENSION_ID;
2417
+ var init_evaluation_rubric = __esm({
2418
+ "../contract/src/evaluation-rubric.ts"() {
2419
+ "use strict";
2420
+ DIMENSION_ID = /^[A-Za-z][A-Za-z0-9_.-]{0,31}$/;
2301
2421
  }
2302
2422
  });
2303
2423
 
@@ -2615,6 +2735,7 @@ var init_src = __esm({
2615
2735
  init_annotation();
2616
2736
  init_collab_view();
2617
2737
  init_evaluation();
2738
+ init_evaluation_rubric();
2618
2739
  init_inbox_read();
2619
2740
  init_workorder_quality();
2620
2741
  init_workorder_attachments();
@@ -7541,11 +7662,88 @@ var init_store = __esm({
7541
7662
  }
7542
7663
  });
7543
7664
 
7665
+ // ../core/src/evaluation/rubric-store.ts
7666
+ var import_node_crypto4, bindingKey, MemoryEvaluationRubricStore;
7667
+ var init_rubric_store = __esm({
7668
+ "../core/src/evaluation/rubric-store.ts"() {
7669
+ "use strict";
7670
+ import_node_crypto4 = require("node:crypto");
7671
+ bindingKey = (companyId, caseId) => JSON.stringify([companyId, caseId]);
7672
+ MemoryEvaluationRubricStore = class {
7673
+ rubrics = /* @__PURE__ */ new Map();
7674
+ bindings = /* @__PURE__ */ new Map();
7675
+ async listRubrics(companyId) {
7676
+ return [...this.rubrics.values()].filter((rubric) => rubric.companyId === companyId).sort((left, right) => left.name.localeCompare(right.name)).map((rubric) => structuredClone(rubric));
7677
+ }
7678
+ async getRubric(rubricId) {
7679
+ const rubric = this.rubrics.get(rubricId);
7680
+ return rubric ? structuredClone(rubric) : null;
7681
+ }
7682
+ async upsertRubric(input, at) {
7683
+ const existing = input.rubricId ? this.rubrics.get(input.rubricId) : void 0;
7684
+ if (existing && existing.companyId !== input.companyId) {
7685
+ throw new Error(`\u8BC4\u5206\u6807\u51C6 ${input.rubricId} \u4E0D\u5C5E\u4E8E\u5F53\u524D\u516C\u53F8`);
7686
+ }
7687
+ const rubric = {
7688
+ rubricId: existing?.rubricId ?? input.rubricId ?? (0, import_node_crypto4.randomUUID)(),
7689
+ companyId: input.companyId,
7690
+ name: input.name,
7691
+ kind: input.kind,
7692
+ ...input.description ? { description: input.description } : {},
7693
+ promptSection: input.promptSection,
7694
+ outputSpec: structuredClone(input.outputSpec),
7695
+ // 版本随每次保存自增:判分记录靠 rubricId@version 复现「当时用的是哪一版标准」。
7696
+ version: (existing?.version ?? 0) + 1,
7697
+ status: input.status ?? existing?.status ?? "active",
7698
+ createdBy: existing?.createdBy ?? input.actor,
7699
+ createdAt: existing?.createdAt ?? at,
7700
+ updatedBy: input.actor,
7701
+ updatedAt: at
7702
+ };
7703
+ this.rubrics.set(rubric.rubricId, rubric);
7704
+ return structuredClone(rubric);
7705
+ }
7706
+ async deleteRubric(rubricId, companyId) {
7707
+ const rubric = this.rubrics.get(rubricId);
7708
+ if (!rubric || rubric.companyId !== companyId) return;
7709
+ this.rubrics.delete(rubricId);
7710
+ for (const [key, binding] of this.bindings) {
7711
+ if (binding.companyId !== companyId || !binding.rubricIds.includes(rubricId)) continue;
7712
+ this.bindings.set(key, {
7713
+ ...binding,
7714
+ rubricIds: binding.rubricIds.filter((id) => id !== rubricId)
7715
+ });
7716
+ }
7717
+ }
7718
+ async listBindings(companyId) {
7719
+ return [...this.bindings.values()].filter((binding) => binding.companyId === companyId).map((binding) => structuredClone(binding));
7720
+ }
7721
+ async getBinding(companyId, caseId) {
7722
+ const binding = this.bindings.get(bindingKey(companyId, caseId));
7723
+ return binding ? structuredClone(binding) : null;
7724
+ }
7725
+ async putBinding(input, at) {
7726
+ const binding = {
7727
+ companyId: input.companyId,
7728
+ caseId: input.caseId,
7729
+ rubricIds: [...input.rubricIds],
7730
+ judgeActorId: input.judgeActorId,
7731
+ updatedBy: input.actor,
7732
+ updatedAt: at
7733
+ };
7734
+ this.bindings.set(bindingKey(input.companyId, input.caseId), binding);
7735
+ return structuredClone(binding);
7736
+ }
7737
+ };
7738
+ }
7739
+ });
7740
+
7544
7741
  // ../core/src/evaluation/index.ts
7545
7742
  var init_evaluation2 = __esm({
7546
7743
  "../core/src/evaluation/index.ts"() {
7547
7744
  "use strict";
7548
7745
  init_store();
7746
+ init_rubric_store();
7549
7747
  }
7550
7748
  });
7551
7749
 
@@ -7845,11 +8043,11 @@ var init_parse = __esm({
7845
8043
 
7846
8044
  // ../channels/src/feishu/crypto.ts
7847
8045
  function decryptFeishu(encrypt, encryptKey) {
7848
- const key = (0, import_node_crypto4.createHash)("sha256").update(encryptKey).digest();
8046
+ const key = (0, import_node_crypto5.createHash)("sha256").update(encryptKey).digest();
7849
8047
  const data = Buffer.from(encrypt, "base64");
7850
8048
  const iv = data.subarray(0, 16);
7851
8049
  const ciphertext = data.subarray(16);
7852
- const decipher = (0, import_node_crypto4.createDecipheriv)("aes-256-cbc", key, iv);
8050
+ const decipher = (0, import_node_crypto5.createDecipheriv)("aes-256-cbc", key, iv);
7853
8051
  decipher.setAutoPadding(true);
7854
8052
  return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
7855
8053
  }
@@ -7883,11 +8081,11 @@ function verifyToken(decoded, expected) {
7883
8081
  const token = headerToken ?? decoded["token"];
7884
8082
  return token === expected;
7885
8083
  }
7886
- var import_node_crypto4;
8084
+ var import_node_crypto5;
7887
8085
  var init_crypto = __esm({
7888
8086
  "../channels/src/feishu/crypto.ts"() {
7889
8087
  "use strict";
7890
- import_node_crypto4 = require("node:crypto");
8088
+ import_node_crypto5 = require("node:crypto");
7891
8089
  }
7892
8090
  });
7893
8091
 
@@ -8023,11 +8221,11 @@ var init_src3 = __esm({
8023
8221
  function errMsg(e) {
8024
8222
  return e instanceof Error ? e.message : String(e);
8025
8223
  }
8026
- var import_node_crypto5, FEISHU, ChannelService, CardStreamer;
8224
+ var import_node_crypto6, FEISHU, ChannelService, CardStreamer;
8027
8225
  var init_service = __esm({
8028
8226
  "../server/src/channels/service.ts"() {
8029
8227
  "use strict";
8030
- import_node_crypto5 = require("node:crypto");
8228
+ import_node_crypto6 = require("node:crypto");
8031
8229
  init_src3();
8032
8230
  FEISHU = "feishu";
8033
8231
  ChannelService = class {
@@ -8107,7 +8305,7 @@ var init_service = __esm({
8107
8305
  return existing.chatSessionId;
8108
8306
  }
8109
8307
  }
8110
- const id = (0, import_node_crypto5.randomUUID)();
8308
+ const id = (0, import_node_crypto6.randomUUID)();
8111
8309
  const now = this.now();
8112
8310
  if (cs) {
8113
8311
  const rt = await this.deps.resolveRuntime?.(a.aiActorId).catch(() => null);
@@ -8143,7 +8341,7 @@ var init_service = __esm({
8143
8341
  if (cs) {
8144
8342
  const sess = await cs.getSession(intent.chatSessionId).catch(() => null);
8145
8343
  resumeRt = sess?.runtimeSessionId ?? void 0;
8146
- await cs.appendMessage({ id: (0, import_node_crypto5.randomUUID)(), sessionId: intent.chatSessionId, role: "user", content: intent.message, createdAt: this.now() }).catch(() => void 0);
8344
+ await cs.appendMessage({ id: (0, import_node_crypto6.randomUUID)(), sessionId: intent.chatSessionId, role: "user", content: intent.message, createdAt: this.now() }).catch(() => void 0);
8147
8345
  }
8148
8346
  let session;
8149
8347
  try {
@@ -8165,7 +8363,7 @@ var init_service = __esm({
8165
8363
  const reply = streamer.text();
8166
8364
  if (reply || session.runId) {
8167
8365
  await cs.appendMessage({
8168
- id: (0, import_node_crypto5.randomUUID)(),
8366
+ id: (0, import_node_crypto6.randomUUID)(),
8169
8367
  sessionId: intent.chatSessionId,
8170
8368
  role: "assistant",
8171
8369
  content: reply,
@@ -137636,7 +137834,7 @@ var init_live_chat = __esm({
137636
137834
  }
137637
137835
  if (!res.accepted) return say(res, { from: "runtime" });
137638
137836
  if (this.turns.get(chatSessionId) !== turn || turn.status !== "running") {
137639
- return say({ accepted: true, reason: "turn-finished" }, { turnStatus: turn.status, replaced: this.turns.get(chatSessionId) !== turn });
137837
+ return say({ accepted: false, reason: "turn-finished" }, { turnStatus: turn.status, replaced: this.turns.get(chatSessionId) !== turn });
137640
137838
  }
137641
137839
  const withSeq = { type: "user", text: text2, seq: ++turn.seq };
137642
137840
  turn.buffer.push(withSeq);
@@ -138196,7 +138394,7 @@ function slug4(name) {
138196
138394
  return s2 || "user";
138197
138395
  }
138198
138396
  function short6() {
138199
- return (0, import_node_crypto6.randomBytes)(4).toString("hex").slice(0, 6);
138397
+ return (0, import_node_crypto7.randomBytes)(4).toString("hex").slice(0, 6);
138200
138398
  }
138201
138399
  async function assertBindingWritePermission(caller, targetHumanId, deps) {
138202
138400
  if (caller === targetHumanId) return true;
@@ -138261,11 +138459,11 @@ async function resolveWorkorderPrincipals(caller, cliOverrides, deps) {
138261
138459
  }
138262
138460
  return { error: "UNBOUND_AGENT_NO_OWNER", message: `owner \u65E0\u6CD5\u89E3\u6790\uFF1A\u8C03\u7528\u65B9 ${caller} \u65E2\u975E\u5728\u5C97\u771F\u4EBA\u4E5F\u975E\u5DF2\u7ED1\u52A9\u7406` };
138263
138461
  }
138264
- var import_node_crypto6, DEFAULT_ASSISTANT_PROMPT, DEFAULT_ASSISTANT_SKILLS, DEFAULT_ASSISTANT_RUNTIME_KIND, ASSISTANT_ARCHIVED_CODE, AssistantLazyCreateError, AssistantsService;
138462
+ var import_node_crypto7, DEFAULT_ASSISTANT_PROMPT, DEFAULT_ASSISTANT_SKILLS, DEFAULT_ASSISTANT_RUNTIME_KIND, ASSISTANT_ARCHIVED_CODE, AssistantLazyCreateError, AssistantsService;
138265
138463
  var init_assistants = __esm({
138266
138464
  "../server/src/domains/actors/assistants.ts"() {
138267
138465
  "use strict";
138268
- import_node_crypto6 = require("node:crypto");
138466
+ import_node_crypto7 = require("node:crypto");
138269
138467
  init_src();
138270
138468
  DEFAULT_ASSISTANT_PROMPT = "\u4F60\u662F\u8FD9\u540D\u771F\u4EBA\u5458\u5DE5\u7684\u4E13\u5C5E\u4E2A\u4EBA\u52A9\u7406\u3002\u4F60\u4EE5\u5176\u300C\u5DE5\u5355\u7BA1\u7406\u8005\u300D\u8EAB\u4EFD\u4EE3\u8DD1\uFF0C\u9075\u5FAA\u4E09\u6863\u6743\u9650\u6A21\u578B\uFF1A\u6863 A\uFF08\u52A0\u8FB9\u3001\u65B0\u5EFA\u8282\u70B9\u3001\u6539\u6807\u9898\u4E0E brief\u3001\u5E38\u89C4\u8BC4\u8BBA\u7B54\u7591\u3001\u63A8\u8FDB\u81EA\u5DF1\u63A5\u7684\u6D3B\uFF09\u53EF\u9006\u6539\u52A8\u76F4\u63A5\u751F\u6548\uFF1B\u6863 B\uFF08\u65AD\u8FB9\u3001\u5E9F\u8282\u70B9\u3001\u6539\u6D3E\u3001\u64A4\u90E8\u4EF6\uFF09\u9500\u6BC1\u6027\u6539\u52A8\u81EA\u52A8\u6253\u5305\u6210\u5F85\u786E\u8BA4\u63D0\u6848\uFF0C\u4EA4\u7531\u672C\u4EBA\u786E\u8BA4\u540E\u751F\u6548\uFF1B\u6863 C\uFF08force-conclude\u3001promote \u7B49\u6CBB\u7406\u547D\u4EE4\uFF09\u8D70\u4EBA\u5DE5\u6388\u6743\u5361\u3002\u4F60\u4E0D\u627F\u62C5\u4E1A\u52A1\u4E13\u4E1A\u5C97\u4F4D\u804C\u8D23\uFF0C\u53EA\u5728\u5176\u6388\u6743\u8303\u56F4\u5185\u534F\u52A9\u5EFA\u5355\u3001\u8DDF\u8FDB\u4E0E\u6C9F\u901A\u3002";
138271
138469
  DEFAULT_ASSISTANT_SKILLS = [];
@@ -141643,7 +141841,7 @@ var init_prepare_job = __esm({
141643
141841
  function deriveBoardKey(artifactId) {
141644
141842
  const tail = artifactId.split(":").pop() ?? artifactId;
141645
141843
  const ascii = tail.replace(/[^a-zA-Z0-9-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 24);
141646
- const sha8 = (0, import_node_crypto7.createHash)("sha256").update(artifactId).digest("hex").slice(0, 8);
141844
+ const sha8 = (0, import_node_crypto8.createHash)("sha256").update(artifactId).digest("hex").slice(0, 8);
141647
141845
  return ascii ? `od-${ascii}-${sha8}` : `od-${sha8}`;
141648
141846
  }
141649
141847
  async function odApi(base, fetchImpl, method, p2, body) {
@@ -141686,7 +141884,7 @@ function materializeContext(resolvedDir, files) {
141686
141884
  }
141687
141885
  }
141688
141886
  async function putVisibleUserTurn(base, fetchImpl, args) {
141689
- const messageId = (0, import_node_crypto7.randomUUID)();
141887
+ const messageId = (0, import_node_crypto8.randomUUID)();
141690
141888
  await odApi(
141691
141889
  base,
141692
141890
  fetchImpl,
@@ -141701,8 +141899,8 @@ async function startDesignRun(base, fetchImpl, args) {
141701
141899
  agentId: args.agentId,
141702
141900
  projectId: args.boardKey,
141703
141901
  conversationId: args.conversationId,
141704
- assistantMessageId: (0, import_node_crypto7.randomUUID)(),
141705
- clientRequestId: (0, import_node_crypto7.randomUUID)(),
141902
+ assistantMessageId: (0, import_node_crypto8.randomUUID)(),
141903
+ clientRequestId: (0, import_node_crypto8.randomUUID)(),
141706
141904
  message: args.message,
141707
141905
  // 提案 design-conversational-driving 坑②:systemPrompt 从写死改为可选——缺省用引擎侧默认,
141708
141906
  // 让设计意图由驱动方每轮的话(message)表达,而非焊死一句。
@@ -141883,11 +142081,11 @@ async function runDesignChatTurn(opts) {
141883
142081
  const { artifacts, fileCount } = await fetchResultPackage(opts.base, fetchImpl, runId);
141884
142082
  return { boardKey, conversationId, runId, userMessageId, artifacts, fileCount };
141885
142083
  }
141886
- var import_node_crypto7, fs5, os, path4;
142084
+ var import_node_crypto8, fs5, os, path4;
141887
142085
  var init_driver = __esm({
141888
142086
  "../adapters/src/open-design/driver.ts"() {
141889
142087
  "use strict";
141890
- import_node_crypto7 = require("node:crypto");
142088
+ import_node_crypto8 = require("node:crypto");
141891
142089
  fs5 = __toESM(require("node:fs"), 1);
141892
142090
  os = __toESM(require("node:os"), 1);
141893
142091
  path4 = __toESM(require("node:path"), 1);
@@ -141998,7 +142196,7 @@ function resolveWorkRoots(workRoot) {
141998
142196
  }
141999
142197
  function slug5(workdirKey) {
142000
142198
  const safe = workdirKey.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 48);
142001
- const h = (0, import_node_crypto8.createHash)("sha256").update(workdirKey).digest("hex").slice(0, 8);
142199
+ const h = (0, import_node_crypto9.createHash)("sha256").update(workdirKey).digest("hex").slice(0, 8);
142002
142200
  return `${safe}-${h}`;
142003
142201
  }
142004
142202
  function sessionDirFor(workRoot, runtimeKind, workdirKey) {
@@ -142130,11 +142328,11 @@ function prepareWorkdir(args) {
142130
142328
  function legacyChatSessionDir(workRoot, rtId) {
142131
142329
  return import_node_path8.default.join(resolveLegacyWorkRoot(workRoot), "oasis-chat-sessions", rtId.replace(/[^a-zA-Z0-9_-]+/g, "_"));
142132
142330
  }
142133
- var import_node_crypto8, import_node_fs6, import_node_os4, import_node_path8, META_FILE, LOCK_FILE, NEW_WORK_ROOT, LEGACY_ROOTS, LEGACY_ONESHOT_PREFIX;
142331
+ var import_node_crypto9, import_node_fs6, import_node_os4, import_node_path8, META_FILE, LOCK_FILE, NEW_WORK_ROOT, LEGACY_ROOTS, LEGACY_ONESHOT_PREFIX;
142134
142332
  var init_session_paths = __esm({
142135
142333
  "../adapters/src/_core/session-paths.ts"() {
142136
142334
  "use strict";
142137
- import_node_crypto8 = require("node:crypto");
142335
+ import_node_crypto9 = require("node:crypto");
142138
142336
  import_node_fs6 = __toESM(require("node:fs"), 1);
142139
142337
  import_node_os4 = __toESM(require("node:os"), 1);
142140
142338
  import_node_path8 = __toESM(require("node:path"), 1);
@@ -142337,12 +142535,12 @@ function classifyExit(result) {
142337
142535
  if (status === 429 || status === 529) return "rate-limit";
142338
142536
  return "error";
142339
142537
  }
142340
- var import_node_child_process8, import_node_crypto9, fs9, path7, readline, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
142538
+ var import_node_child_process8, import_node_crypto10, fs9, path7, readline, ONE_SHOT_UNSAFE_TOOLS, ClaudeCodeAdapter;
142341
142539
  var init_claude_code = __esm({
142342
142540
  "../adapters/src/claude-code/index.ts"() {
142343
142541
  "use strict";
142344
142542
  import_node_child_process8 = require("node:child_process");
142345
- import_node_crypto9 = require("node:crypto");
142543
+ import_node_crypto10 = require("node:crypto");
142346
142544
  fs9 = __toESM(require("node:fs"), 1);
142347
142545
  path7 = __toESM(require("node:path"), 1);
142348
142546
  readline = __toESM(require("node:readline"), 1);
@@ -142383,7 +142581,7 @@ var init_claude_code = __esm({
142383
142581
  }
142384
142582
  async spawn(job) {
142385
142583
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
142386
- const id = `claude-${slug6}-${(0, import_node_crypto9.randomUUID)().slice(0, 8)}`;
142584
+ const id = `claude-${slug6}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
142387
142585
  const dir = job.workdirKey ? prepareWorkdir({
142388
142586
  workRoot: this.opts.workRoot,
142389
142587
  runtimeKind: "claude",
@@ -143749,12 +143947,12 @@ function normalizeCodexConsoleLine(line, state = createCodexNormalizeState()) {
143749
143947
  tool.output.push(line);
143750
143948
  return [];
143751
143949
  }
143752
- var import_node_child_process10, import_node_crypto10, fs10, os4, path9, readline2, CODEX_ARGV_PROMPT_MAX_BYTES, CodexAdapter;
143950
+ var import_node_child_process10, import_node_crypto11, fs10, os4, path9, readline2, CODEX_ARGV_PROMPT_MAX_BYTES, CodexAdapter;
143753
143951
  var init_codex = __esm({
143754
143952
  "../adapters/src/codex/index.ts"() {
143755
143953
  "use strict";
143756
143954
  import_node_child_process10 = require("node:child_process");
143757
- import_node_crypto10 = require("node:crypto");
143955
+ import_node_crypto11 = require("node:crypto");
143758
143956
  fs10 = __toESM(require("node:fs"), 1);
143759
143957
  os4 = __toESM(require("node:os"), 1);
143760
143958
  path9 = __toESM(require("node:path"), 1);
@@ -143781,7 +143979,7 @@ var init_codex = __esm({
143781
143979
  capabilities = { appendInput: false };
143782
143980
  async spawn(job) {
143783
143981
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
143784
- const id = `codex-${slug6}-${(0, import_node_crypto10.randomUUID)().slice(0, 8)}`;
143982
+ const id = `codex-${slug6}-${(0, import_node_crypto11.randomUUID)().slice(0, 8)}`;
143785
143983
  const startedAtMs = Date.now();
143786
143984
  const dir = job.workdirKey ? prepareWorkdir({
143787
143985
  workRoot: this.opts.workRoot,
@@ -144528,7 +144726,7 @@ function buildReportedUsage(acc, model, inputTokensIncludeCacheRead) {
144528
144726
  async function runACPSession(job, cfg) {
144529
144727
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
144530
144728
  const binTag = path10.basename(cfg.bin).replace(/[^a-zA-Z0-9]/g, "").slice(0, 12) || "acp";
144531
- const id = `${binTag}-${slug6}-${(0, import_node_crypto11.randomUUID)().slice(0, 8)}`;
144729
+ const id = `${binTag}-${slug6}-${(0, import_node_crypto12.randomUUID)().slice(0, 8)}`;
144532
144730
  const dir = job.workdirKey ? prepareWorkdir({
144533
144731
  workRoot: cfg.workRoot,
144534
144732
  runtimeKind: cfg.runtimeKind ?? "subprocess",
@@ -144832,12 +145030,12 @@ ${task2}` : task2;
144832
145030
  }
144833
145031
  };
144834
145032
  }
144835
- var import_node_child_process11, import_node_crypto11, fs11, path10, readline3, ACPClient;
145033
+ var import_node_child_process11, import_node_crypto12, fs11, path10, readline3, ACPClient;
144836
145034
  var init_acp = __esm({
144837
145035
  "../adapters/src/_core/acp.ts"() {
144838
145036
  "use strict";
144839
145037
  import_node_child_process11 = require("node:child_process");
144840
- import_node_crypto11 = require("node:crypto");
145038
+ import_node_crypto12 = require("node:crypto");
144841
145039
  fs11 = __toESM(require("node:fs"), 1);
144842
145040
  path10 = __toESM(require("node:path"), 1);
144843
145041
  readline3 = __toESM(require("node:readline"), 1);
@@ -145189,7 +145387,7 @@ var init_kiro = __esm({
145189
145387
  // ../adapters/src/_core/subprocess.ts
145190
145388
  async function materialize(job, cfg) {
145191
145389
  const slug6 = job.artifactId.replace(/[^a-zA-Z0-9_-]+/g, "_").slice(0, 32);
145192
- const id = `${slug6}-${(0, import_node_crypto12.randomUUID)().slice(0, 8)}`;
145390
+ const id = `${slug6}-${(0, import_node_crypto13.randomUUID)().slice(0, 8)}`;
145193
145391
  const dir = job.workdirKey ? prepareWorkdir({
145194
145392
  workRoot: cfg.workRoot,
145195
145393
  runtimeKind: cfg.runtimeKind ?? "subprocess",
@@ -145411,12 +145609,12 @@ async function runOneShotText(job, cfg) {
145411
145609
  }
145412
145610
  });
145413
145611
  }
145414
- var import_node_child_process12, import_node_crypto12, fs12, path11, readline4;
145612
+ var import_node_child_process12, import_node_crypto13, fs12, path11, readline4;
145415
145613
  var init_subprocess = __esm({
145416
145614
  "../adapters/src/_core/subprocess.ts"() {
145417
145615
  "use strict";
145418
145616
  import_node_child_process12 = require("node:child_process");
145419
- import_node_crypto12 = require("node:crypto");
145617
+ import_node_crypto13 = require("node:crypto");
145420
145618
  fs12 = __toESM(require("node:fs"), 1);
145421
145619
  path11 = __toESM(require("node:path"), 1);
145422
145620
  readline4 = __toESM(require("node:readline"), 1);
@@ -145830,11 +146028,11 @@ function normalizeOpenClaw(line) {
145830
146028
  }
145831
146029
  return [];
145832
146030
  }
145833
- var import_node_crypto13, OpenClawAdapter;
146031
+ var import_node_crypto14, OpenClawAdapter;
145834
146032
  var init_openclaw = __esm({
145835
146033
  "../adapters/src/openclaw/index.ts"() {
145836
146034
  "use strict";
145837
- import_node_crypto13 = require("node:crypto");
146035
+ import_node_crypto14 = require("node:crypto");
145838
146036
  init_subprocess();
145839
146037
  OpenClawAdapter = class {
145840
146038
  constructor(opts = {}) {
@@ -145852,7 +146050,7 @@ var init_openclaw = __esm({
145852
146050
  ---
145853
146051
 
145854
146052
  ${task2}` : task2;
145855
- const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto13.randomUUID)().slice(0, 8)}`;
146053
+ const sessionId = job2.runtimeSessionId ?? `oasis-${(0, import_node_crypto14.randomUUID)().slice(0, 8)}`;
145856
146054
  return [
145857
146055
  "agent",
145858
146056
  ...opts.mode !== "gateway" ? ["--local"] : [],
@@ -147591,12 +147789,12 @@ async function startOasisServer(opts) {
147591
147789
  if (!store || !dispatch) return;
147592
147790
  const session = await store.getSession(origin).catch(() => null);
147593
147791
  if (!session) return;
147594
- const { randomUUID: randomUUID29 } = await import("node:crypto");
147792
+ const { randomUUID: randomUUID31 } = await import("node:crypto");
147595
147793
  const approved = resolution.status === "approved";
147596
147794
  const by = ctx.authorizedBy ?? "\u7BA1\u7406\u8005";
147597
147795
  const label = ctx.effectLabel || ctx.command || "";
147598
147796
  const statusText = approved ? `\u547D\u4EE4\u5DF2\u7531 ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C${label ? `\uFF1A${label}` : ""}\u3002` : `\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${ctx.reason ? `\uFF1A${ctx.reason}` : ""}\u3002`;
147599
- await store.appendMessage({ id: randomUUID29(), sessionId: origin, role: "system", content: statusText, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
147797
+ await store.appendMessage({ id: randomUUID31(), sessionId: origin, role: "system", content: statusText, createdAt: (/* @__PURE__ */ new Date()).toISOString() }).catch(() => void 0);
147600
147798
  if (liveChat.isRunning(origin)) return;
147601
147799
  const prompt = approved ? `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u6279\u51C6\u5E76\u4EE5\u5176\u540D\u4E49\u6267\u884C\uFF08\u547D\u4EE4\uFF1A${label}\uFF09\u3002\u8BF7\u7EE7\u7EED\u539F\u4EFB\u52A1\u3002` : `\u4E0A\u4E00\u6761\u5F85\u6388\u6743\u547D\u4EE4\u5DF2\u88AB ${by} \u9A73\u56DE${ctx.reason ? `\uFF08\u7406\u7531\uFF1A${ctx.reason}\uFF09` : ""}\u3002\u522B\u91CD\u8BD5\u540C\u4E00\u6761\u2014\u2014\u8BF7\u6539\u65B9\u6848\u6216\u5148\u5411\u53D1\u8D77\u4EBA\u95EE\u6E05\u695A\u3002`;
147602
147800
  let dispatched;
@@ -147617,7 +147815,7 @@ async function startOasisServer(opts) {
147617
147815
  void dispatched.done.then(async () => {
147618
147816
  if (text2 || dispatched.runId) {
147619
147817
  await store.appendMessage({
147620
- id: randomUUID29(),
147818
+ id: randomUUID31(),
147621
147819
  sessionId: origin,
147622
147820
  role: "assistant",
147623
147821
  content: text2,
@@ -148268,11 +148466,11 @@ async function startOasisServer(opts) {
148268
148466
  const itemKey = `${baseItemKey}:${ctx.ownerId}`;
148269
148467
  let chatSessionId;
148270
148468
  if (chatStore) {
148271
- const { randomUUID: randomUUID29 } = await import("node:crypto");
148469
+ const { randomUUID: randomUUID31 } = await import("node:crypto");
148272
148470
  const known = discussSessions.get(itemKey);
148273
148471
  if (known && await chatStore.getSession(known).catch(() => null)) chatSessionId = known;
148274
148472
  if (!chatSessionId) {
148275
- chatSessionId = randomUUID29();
148473
+ chatSessionId = randomUUID31();
148276
148474
  const now = (/* @__PURE__ */ new Date()).toISOString();
148277
148475
  const title = `\u89E3\u51B3\uFF1A${ctx.seed.slice(ctx.seed.indexOf("\uFF1A") + 1, ctx.seed.indexOf("\uFF1A") + 25) || "\u5DE5\u5355\u5361\u70B9"}`;
148278
148476
  const reg0 = (await resolveEngine(currentCompanyId).catch(() => null))?.registry ?? opts.registry;
@@ -148722,14 +148920,14 @@ async function startOasisServer(opts) {
148722
148920
  runtimeSessionId: session.nativeSessionId ?? session.id
148723
148921
  }).catch(() => void 0);
148724
148922
  }
148725
- const { randomUUID: randomUUID30 } = await import("node:crypto");
148923
+ const { randomUUID: randomUUID32 } = await import("node:crypto");
148726
148924
  const persistAttachments = attachments.map((a) => ({
148727
148925
  name: a.name,
148728
148926
  ...a.blobRef !== void 0 ? { blobRef: a.blobRef } : {},
148729
148927
  ...a.contentType !== void 0 ? { contentType: a.contentType } : {}
148730
148928
  }));
148731
148929
  await chatStore.appendMessage({
148732
- id: randomUUID30(),
148930
+ id: randomUUID32(),
148733
148931
  sessionId: persistTarget.id,
148734
148932
  role: "user",
148735
148933
  content: persistedUserMessage,
@@ -148739,8 +148937,8 @@ async function startOasisServer(opts) {
148739
148937
  }
148740
148938
  let assistantMsgId;
148741
148939
  if (chatStore && persistTarget) {
148742
- const { randomUUID: randomUUID30 } = await import("node:crypto");
148743
- const id = randomUUID30();
148940
+ const { randomUUID: randomUUID32 } = await import("node:crypto");
148941
+ const id = randomUUID32();
148744
148942
  await chatStore.appendMessage({
148745
148943
  id,
148746
148944
  sessionId: persistTarget.id,
@@ -148776,9 +148974,9 @@ async function startOasisServer(opts) {
148776
148974
  }).catch(() => void 0);
148777
148975
  } else {
148778
148976
  if (!assistantText && !session.runId && parts.length === 0) return;
148779
- const { randomUUID: randomUUID30 } = await import("node:crypto");
148977
+ const { randomUUID: randomUUID32 } = await import("node:crypto");
148780
148978
  await chatStore.appendMessage({
148781
- id: randomUUID30(),
148979
+ id: randomUUID32(),
148782
148980
  sessionId: persistTarget.id,
148783
148981
  role: "assistant",
148784
148982
  content: assistantText,
@@ -149011,8 +149209,8 @@ async function startOasisServer(opts) {
149011
149209
  }
149012
149210
  }
149013
149211
  const { spawn: spawn7 } = await import("node:child_process");
149014
- const { randomUUID: randomUUID29 } = await import("node:crypto");
149015
- const sessionId = body.sessionId ?? randomUUID29();
149212
+ const { randomUUID: randomUUID31 } = await import("node:crypto");
149213
+ const sessionId = body.sessionId ?? randomUUID31();
149016
149214
  const args = [
149017
149215
  "-p",
149018
149216
  body.message,
@@ -149574,7 +149772,7 @@ function createNodeTokenStore(file) {
149574
149772
  return {
149575
149773
  issue(nodeId) {
149576
149774
  const table = read();
149577
- const token = `ont_${(0, import_node_crypto14.randomBytes)(24).toString("base64url")}`;
149775
+ const token = `ont_${(0, import_node_crypto15.randomBytes)(24).toString("base64url")}`;
149578
149776
  table[token] = nodeId;
149579
149777
  write(table);
149580
149778
  return token;
@@ -149616,7 +149814,7 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
149616
149814
  return {
149617
149815
  issue(name, ttlMs = defaultTtlMs) {
149618
149816
  const m2 = prune();
149619
- const token = `ent_${(0, import_node_crypto14.randomBytes)(24).toString("base64url")}`;
149817
+ const token = `ent_${(0, import_node_crypto15.randomBytes)(24).toString("base64url")}`;
149620
149818
  const expiresAt = Date.now() + ttlMs;
149621
149819
  m2.set(token, { name, expiresAt });
149622
149820
  write(m2);
@@ -149646,33 +149844,33 @@ function createEnrollTokenStore(defaultTtlMs = 30 * 60 * 1e3, file) {
149646
149844
  }
149647
149845
  };
149648
149846
  }
149649
- var import_node_crypto14, fs14, path13, SESSION_TOKEN_PREFIX, b64url, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
149847
+ var import_node_crypto15, fs14, path13, SESSION_TOKEN_PREFIX, b64url, fromB64url, readOrCreateSecret, sign, signatureMatches, isTokenClaims;
149650
149848
  var init_tokens = __esm({
149651
149849
  "../server/src/tokens.ts"() {
149652
149850
  "use strict";
149653
- import_node_crypto14 = require("node:crypto");
149851
+ import_node_crypto15 = require("node:crypto");
149654
149852
  fs14 = __toESM(require("node:fs"), 1);
149655
149853
  path13 = __toESM(require("node:path"), 1);
149656
149854
  SESSION_TOKEN_PREFIX = "oat_v2_";
149657
149855
  b64url = (value2) => Buffer.from(value2).toString("base64url");
149658
149856
  fromB64url = (value2) => Buffer.from(value2, "base64url").toString("utf8");
149659
149857
  readOrCreateSecret = (file) => {
149660
- if (!file) return (0, import_node_crypto14.randomBytes)(32);
149858
+ if (!file) return (0, import_node_crypto15.randomBytes)(32);
149661
149859
  try {
149662
149860
  const raw = fs14.readFileSync(file, "utf8").trim();
149663
149861
  if (raw) return Buffer.from(raw, "base64url");
149664
149862
  } catch {
149665
149863
  }
149666
- const secret = (0, import_node_crypto14.randomBytes)(32);
149864
+ const secret = (0, import_node_crypto15.randomBytes)(32);
149667
149865
  fs14.mkdirSync(path13.dirname(file), { recursive: true });
149668
149866
  fs14.writeFileSync(file, secret.toString("base64url"), { mode: 384 });
149669
149867
  return secret;
149670
149868
  };
149671
- sign = (secret, payload) => (0, import_node_crypto14.createHmac)("sha256", secret).update(payload).digest("base64url");
149869
+ sign = (secret, payload) => (0, import_node_crypto15.createHmac)("sha256", secret).update(payload).digest("base64url");
149672
149870
  signatureMatches = (actual, expected) => {
149673
149871
  const a = Buffer.from(actual);
149674
149872
  const b2 = Buffer.from(expected);
149675
- return a.length === b2.length && (0, import_node_crypto14.timingSafeEqual)(a, b2);
149873
+ return a.length === b2.length && (0, import_node_crypto15.timingSafeEqual)(a, b2);
149676
149874
  };
149677
149875
  isTokenClaims = (value2) => {
149678
149876
  if (value2 === null || typeof value2 !== "object") return false;
@@ -150889,11 +151087,11 @@ function onlyHits(pool, q) {
150889
151087
  if (!q.requireMatch || q.keywords.length === 0) return [...pool];
150890
151088
  return pool.filter((r) => memoryMatchScore(r, q.keywords) > 0);
150891
151089
  }
150892
- var import_node_crypto15, MemoryActorMemoryStore, toIndexEntry;
151090
+ var import_node_crypto16, MemoryActorMemoryStore, toIndexEntry;
150893
151091
  var init_memory_actor_memory_store = __esm({
150894
151092
  "../testkit/src/memory-actor-memory-store.ts"() {
150895
151093
  "use strict";
150896
- import_node_crypto15 = require("node:crypto");
151094
+ import_node_crypto16 = require("node:crypto");
150897
151095
  init_src();
150898
151096
  MemoryActorMemoryStore = class {
150899
151097
  rows = /* @__PURE__ */ new Map();
@@ -150947,7 +151145,7 @@ var init_memory_actor_memory_store = __esm({
150947
151145
  async write(input, now) {
150948
151146
  if (input.memId === void 0) {
150949
151147
  const rec = {
150950
- memId: `mem:${(0, import_node_crypto15.randomUUID)()}`,
151148
+ memId: `mem:${(0, import_node_crypto16.randomUUID)()}`,
150951
151149
  actorId: input.actorId,
150952
151150
  projectId: input.projectId,
150953
151151
  keywords: [...input.keywords],
@@ -152662,11 +152860,11 @@ var init_service2 = __esm({
152662
152860
  });
152663
152861
 
152664
152862
  // ../server/src/dev-store.ts
152665
- var import_node_crypto16, fs15, path14, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileProjectDocumentStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryReadMarkerStore, FileReadMarkerStore;
152863
+ var import_node_crypto17, fs15, path14, NdjsonOplogStore, DirBlobStore, MUTATORS, FileTypeRegistryStore, FileRoleRegistryStore, FileRegistryStore, FileAssistantBindStore, FileHumanPrefsStore, FileProjectStateStore, FileProjectDocumentStore, FileArtifactStateStore, FileTraceStore, MemoryChatSessionStore, FileChatSessionStore, MemoryReadMarkerStore, FileReadMarkerStore;
152666
152864
  var init_dev_store = __esm({
152667
152865
  "../server/src/dev-store.ts"() {
152668
152866
  "use strict";
152669
- import_node_crypto16 = require("node:crypto");
152867
+ import_node_crypto17 = require("node:crypto");
152670
152868
  fs15 = __toESM(require("node:fs"), 1);
152671
152869
  path14 = __toESM(require("node:path"), 1);
152672
152870
  init_src();
@@ -152720,7 +152918,7 @@ var init_dev_store = __esm({
152720
152918
  return path14.join(this.dir, hash);
152721
152919
  }
152722
152920
  async put(bytes) {
152723
- const hash = (0, import_node_crypto16.createHash)("sha256").update(bytes).digest("hex");
152921
+ const hash = (0, import_node_crypto17.createHash)("sha256").update(bytes).digest("hex");
152724
152922
  const file = this.fileOf(hash);
152725
152923
  if (!fs15.existsSync(file)) fs15.writeFileSync(file, bytes);
152726
152924
  return hash;
@@ -153457,11 +153655,11 @@ function typeDefError(def, mode) {
153457
153655
  }
153458
153656
  return null;
153459
153657
  }
153460
- var import_node_crypto17, RESERVED_FIELD_NAMES, ARTIFACT_TYPE_ACCENTS, TYPE_DEF_SCHEMA, TypesAdminService;
153658
+ var import_node_crypto18, RESERVED_FIELD_NAMES, ARTIFACT_TYPE_ACCENTS, TYPE_DEF_SCHEMA, TypesAdminService;
153461
153659
  var init_types_admin = __esm({
153462
153660
  "../server/src/types-admin.ts"() {
153463
153661
  "use strict";
153464
- import_node_crypto17 = require("node:crypto");
153662
+ import_node_crypto18 = require("node:crypto");
153465
153663
  init_zod();
153466
153664
  init_src2();
153467
153665
  init_config_audit();
@@ -153578,7 +153776,7 @@ var init_types_admin = __esm({
153578
153776
  async trace(change, target, by, detail) {
153579
153777
  try {
153580
153778
  await this.audit?.({
153581
- id: `reg_${(0, import_node_crypto17.randomUUID)()}`,
153779
+ id: `reg_${(0, import_node_crypto18.randomUUID)()}`,
153582
153780
  actor: by ?? SYSTEM_CONFIG_ACTOR,
153583
153781
  kind: "registry_change",
153584
153782
  target,
@@ -153726,11 +153924,11 @@ function roleDefError(def, mode) {
153726
153924
  }
153727
153925
  return null;
153728
153926
  }
153729
- var import_node_crypto18, ACCENTS, ROLE_DEF_SCHEMA, RolesAdminService;
153927
+ var import_node_crypto19, ACCENTS, ROLE_DEF_SCHEMA, RolesAdminService;
153730
153928
  var init_roles_admin = __esm({
153731
153929
  "../server/src/roles-admin.ts"() {
153732
153930
  "use strict";
153733
- import_node_crypto18 = require("node:crypto");
153931
+ import_node_crypto19 = require("node:crypto");
153734
153932
  init_zod();
153735
153933
  init_src2();
153736
153934
  init_config_audit();
@@ -153755,7 +153953,7 @@ var init_roles_admin = __esm({
153755
153953
  async trace(change, target, by, detail) {
153756
153954
  try {
153757
153955
  await this.deps.audit?.({
153758
- id: `reg_${(0, import_node_crypto18.randomUUID)()}`,
153956
+ id: `reg_${(0, import_node_crypto19.randomUUID)()}`,
153759
153957
  actor: by ?? SYSTEM_CONFIG_ACTOR,
153760
153958
  kind: "registry_change",
153761
153959
  target,
@@ -155113,6 +155311,7 @@ async function planChatTurnRecovery(deps) {
155113
155311
  assistantMsgId: row.id,
155114
155312
  runId: run.id,
155115
155313
  artifactId: run.artifactId,
155314
+ actor: run.actorId,
155116
155315
  ...run.runtimeKind ? { runtimeKind: run.runtimeKind } : {},
155117
155316
  ...runtimeSessionId ? { runtimeSessionId } : {},
155118
155317
  startedAt: run.startedAt,
@@ -155210,7 +155409,7 @@ function wireRecoveredChatTurn(deps) {
155210
155409
  const segText = assistantText;
155211
155410
  const segParts = collectedParts();
155212
155411
  const closingId = currentMsgId;
155213
- const nextId = (0, import_node_crypto19.randomUUID)();
155412
+ const nextId = (0, import_node_crypto20.randomUUID)();
155214
155413
  assistantText = "";
155215
155414
  currentMsgId = nextId;
155216
155415
  segmentBaseSeq = live.bufferedParts().reduce((max, p2) => p2.seq > max ? p2.seq : max, 0);
@@ -155223,7 +155422,7 @@ function wireRecoveredChatTurn(deps) {
155223
155422
  ...segParts.length ? { parts: segParts } : {}
155224
155423
  }).catch(() => void 0);
155225
155424
  await store.appendMessage({
155226
- id: (0, import_node_crypto19.randomUUID)(),
155425
+ id: (0, import_node_crypto20.randomUUID)(),
155227
155426
  sessionId: plan.chatSessionId,
155228
155427
  role: "user",
155229
155428
  content: text2,
@@ -155403,11 +155602,11 @@ async function reconcileChatExitFrame(deps) {
155403
155602
  }
155404
155603
  return false;
155405
155604
  }
155406
- var import_node_crypto19, asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
155605
+ var import_node_crypto20, asObj3, partsOf, maxPartSeq, exitFailed, exitErrorText, runTerminalPatch;
155407
155606
  var init_chat_recovery = __esm({
155408
155607
  "../server/src/chat-recovery.ts"() {
155409
155608
  "use strict";
155410
- import_node_crypto19 = require("node:crypto");
155609
+ import_node_crypto20 = require("node:crypto");
155411
155610
  init_chat_parts();
155412
155611
  init_sink();
155413
155612
  asObj3 = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
@@ -155432,8 +155631,8 @@ var init_chat_recovery = __esm({
155432
155631
 
155433
155632
  // ../server/src/auth/crypto.ts
155434
155633
  function hashPassword(password) {
155435
- const salt = (0, import_node_crypto20.randomBytes)(16);
155436
- const dk = (0, import_node_crypto20.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
155634
+ const salt = (0, import_node_crypto21.randomBytes)(16);
155635
+ const dk = (0, import_node_crypto21.scryptSync)(password, salt, SCRYPT_KEYLEN, { N: SCRYPT_N, maxmem: 64 * 1024 * 1024 });
155437
155636
  return `scrypt$${SCRYPT_N}$${salt.toString("base64url")}$${dk.toString("base64url")}`;
155438
155637
  }
155439
155638
  function verifyPassword(password, stored) {
@@ -155450,8 +155649,8 @@ function verifyPassword(password, stored) {
155450
155649
  return false;
155451
155650
  }
155452
155651
  if (expected.length === 0) return false;
155453
- const dk = (0, import_node_crypto20.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
155454
- return dk.length === expected.length && (0, import_node_crypto20.timingSafeEqual)(dk, expected);
155652
+ const dk = (0, import_node_crypto21.scryptSync)(password, salt, expected.length, { N, maxmem: 64 * 1024 * 1024 });
155653
+ return dk.length === expected.length && (0, import_node_crypto21.timingSafeEqual)(dk, expected);
155455
155654
  }
155456
155655
  function b64urlJson(value2) {
155457
155656
  return Buffer.from(JSON.stringify(value2)).toString("base64url");
@@ -155459,17 +155658,17 @@ function b64urlJson(value2) {
155459
155658
  function signSession(claims, secret) {
155460
155659
  const head = b64urlJson({ alg: "HS256", typ: "JWT" });
155461
155660
  const body = b64urlJson(claims);
155462
- const sig = (0, import_node_crypto20.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155661
+ const sig = (0, import_node_crypto21.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155463
155662
  return `${head}.${body}.${sig}`;
155464
155663
  }
155465
155664
  function verifySession(token, secret, nowMs) {
155466
155665
  const parts = token.split(".");
155467
155666
  if (parts.length !== 3) return null;
155468
155667
  const [head, body, sig] = parts;
155469
- const expected = (0, import_node_crypto20.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155668
+ const expected = (0, import_node_crypto21.createHmac)("sha256", secret).update(`${head}.${body}`).digest("base64url");
155470
155669
  const got = Buffer.from(sig);
155471
155670
  const exp = Buffer.from(expected);
155472
- if (got.length !== exp.length || !(0, import_node_crypto20.timingSafeEqual)(got, exp)) return null;
155671
+ if (got.length !== exp.length || !(0, import_node_crypto21.timingSafeEqual)(got, exp)) return null;
155473
155672
  let claims;
155474
155673
  try {
155475
155674
  claims = JSON.parse(Buffer.from(body, "base64url").toString("utf8"));
@@ -155481,21 +155680,21 @@ function verifySession(token, secret, nowMs) {
155481
155680
  return claims;
155482
155681
  }
155483
155682
  function generateCode() {
155484
- return String((0, import_node_crypto20.randomInt)(0, 1e6)).padStart(6, "0");
155683
+ return String((0, import_node_crypto21.randomInt)(0, 1e6)).padStart(6, "0");
155485
155684
  }
155486
155685
  function hashCode(code, secret) {
155487
- return (0, import_node_crypto20.createHmac)("sha256", secret).update(`code:${code}`).digest("base64url");
155686
+ return (0, import_node_crypto21.createHmac)("sha256", secret).update(`code:${code}`).digest("base64url");
155488
155687
  }
155489
155688
  function safeEqualHash(a, b2) {
155490
155689
  const ba = Buffer.from(a);
155491
155690
  const bb = Buffer.from(b2);
155492
- return ba.length === bb.length && (0, import_node_crypto20.timingSafeEqual)(ba, bb);
155691
+ return ba.length === bb.length && (0, import_node_crypto21.timingSafeEqual)(ba, bb);
155493
155692
  }
155494
- var import_node_crypto20, SCRYPT_N, SCRYPT_KEYLEN;
155693
+ var import_node_crypto21, SCRYPT_N, SCRYPT_KEYLEN;
155495
155694
  var init_crypto2 = __esm({
155496
155695
  "../server/src/auth/crypto.ts"() {
155497
155696
  "use strict";
155498
- import_node_crypto20 = require("node:crypto");
155697
+ import_node_crypto21 = require("node:crypto");
155499
155698
  SCRYPT_N = 16384;
155500
155699
  SCRYPT_KEYLEN = 32;
155501
155700
  }
@@ -156024,13 +156223,13 @@ function variableKeyFromEnv(env = process.env) {
156024
156223
  return buf;
156025
156224
  }
156026
156225
  if (env.NODE_ENV === "production") throw new Error("OASIS_VAR_KEY is required in production");
156027
- return (0, import_node_crypto21.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
156226
+ return (0, import_node_crypto22.createHash)("sha256").update("oasis-dev-only-variable-key").digest();
156028
156227
  }
156029
- var import_node_crypto21, REDACTED_MARKER, ActorsService, mask, changedKeys;
156228
+ var import_node_crypto22, REDACTED_MARKER, ActorsService, mask, changedKeys;
156030
156229
  var init_service3 = __esm({
156031
156230
  "../server/src/domains/actors/service.ts"() {
156032
156231
  "use strict";
156033
- import_node_crypto21 = require("node:crypto");
156232
+ import_node_crypto22 = require("node:crypto");
156034
156233
  init_skill_fetcher();
156035
156234
  init_identity();
156036
156235
  init_src5();
@@ -156424,7 +156623,7 @@ ${input.description}
156424
156623
  */
156425
156624
  buildSkillFile(skillId, path30, content, now) {
156426
156625
  const bytes = new TextEncoder().encode(content);
156427
- const blobHash = (0, import_node_crypto21.createHash)("sha256").update(bytes).digest("hex");
156626
+ const blobHash = (0, import_node_crypto22.createHash)("sha256").update(bytes).digest("hex");
156428
156627
  return { skillId, path: path30, content, blobHash, size: bytes.length, updatedAt: now };
156429
156628
  }
156430
156629
  /**
@@ -156779,15 +156978,15 @@ ${input.description}
156779
156978
  return env;
156780
156979
  }
156781
156980
  encrypt(plain) {
156782
- const iv = (0, import_node_crypto21.randomBytes)(12);
156783
- const cipher = (0, import_node_crypto21.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
156981
+ const iv = (0, import_node_crypto22.randomBytes)(12);
156982
+ const cipher = (0, import_node_crypto22.createCipheriv)("aes-256-gcm", this.opts.variableKey, iv);
156784
156983
  const enc4 = Buffer.concat([cipher.update(plain, "utf8"), cipher.final()]);
156785
156984
  return [iv.toString("base64"), cipher.getAuthTag().toString("base64"), enc4.toString("base64")].join(".");
156786
156985
  }
156787
156986
  decrypt(packed) {
156788
156987
  const [iv, tag, data] = packed.split(".");
156789
156988
  if (!iv || !tag || typeof data !== "string") throw new Error("malformed ciphertext");
156790
- const decipher = (0, import_node_crypto21.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
156989
+ const decipher = (0, import_node_crypto22.createDecipheriv)("aes-256-gcm", this.opts.variableKey, Buffer.from(iv, "base64"));
156791
156990
  decipher.setAuthTag(Buffer.from(tag, "base64"));
156792
156991
  return Buffer.concat([decipher.update(Buffer.from(data, "base64")), decipher.final()]).toString("utf8");
156793
156992
  }
@@ -157628,7 +157827,7 @@ async function listSkillMetadataForActor(args) {
157628
157827
  usedDirs.add(dir);
157629
157828
  const sorted = [...metas].sort((a, b2) => a.path.localeCompare(b2.path));
157630
157829
  let latest = "1970-01-01T00:00:00.000Z";
157631
- const hasher = (0, import_node_crypto22.createHash)("sha256");
157830
+ const hasher = (0, import_node_crypto23.createHash)("sha256");
157632
157831
  for (const m2 of sorted) {
157633
157832
  if (m2.updatedAt > latest) latest = m2.updatedAt;
157634
157833
  hasher.update(m2.path);
@@ -157653,11 +157852,11 @@ async function listSkillMetadataForActor(args) {
157653
157852
  const dir = sanitizeSkillDir(c.name, c.slug);
157654
157853
  if (usedDirs.has(dir)) continue;
157655
157854
  usedDirs.add(dir);
157656
- const hasher = (0, import_node_crypto22.createHash)("sha256");
157855
+ const hasher = (0, import_node_crypto23.createHash)("sha256");
157657
157856
  for (const p2 of paths) {
157658
157857
  hasher.update(p2);
157659
157858
  hasher.update("\0");
157660
- hasher.update((0, import_node_crypto22.createHash)("sha256").update(c.files[p2]).digest("hex"));
157859
+ hasher.update((0, import_node_crypto23.createHash)("sha256").update(c.files[p2]).digest("hex"));
157661
157860
  hasher.update("\0");
157662
157861
  }
157663
157862
  out.push({
@@ -157678,11 +157877,11 @@ async function listSkillMetadataForActor(args) {
157678
157877
  const dir = sanitizeSkillDir(b2.name, b2.id);
157679
157878
  if (usedDirs.has(dir)) continue;
157680
157879
  usedDirs.add(dir);
157681
- const hasher = (0, import_node_crypto22.createHash)("sha256");
157880
+ const hasher = (0, import_node_crypto23.createHash)("sha256");
157682
157881
  for (const p2 of paths) {
157683
157882
  hasher.update(p2);
157684
157883
  hasher.update("\0");
157685
- hasher.update((0, import_node_crypto22.createHash)("sha256").update(b2.files[p2]).digest("hex"));
157884
+ hasher.update((0, import_node_crypto23.createHash)("sha256").update(b2.files[p2]).digest("hex"));
157686
157885
  hasher.update("\0");
157687
157886
  }
157688
157887
  out.push({
@@ -157702,7 +157901,7 @@ function builtinSkillToFiles(b2) {
157702
157901
  skillId: `builtin:${b2.id}`,
157703
157902
  path: path30,
157704
157903
  content,
157705
- blobHash: (0, import_node_crypto22.createHash)("sha256").update(content).digest("hex"),
157904
+ blobHash: (0, import_node_crypto23.createHash)("sha256").update(content).digest("hex"),
157706
157905
  size: Buffer.byteLength(content, "utf8"),
157707
157906
  updatedAt: "1970-01-01T00:00:00.000Z"
157708
157907
  }));
@@ -157726,7 +157925,7 @@ function sanitizeSkillDir(name, fallbackId) {
157726
157925
  if (byName) return byName;
157727
157926
  const byId = fallbackId ? fold2(fallbackId) : "";
157728
157927
  if (byId) return byId;
157729
- return `skill-${(0, import_node_crypto22.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
157928
+ return `skill-${(0, import_node_crypto23.createHash)("sha256").update(name).digest("hex").slice(0, 8)}`;
157730
157929
  }
157731
157930
  async function materializeSkillFiles(args) {
157732
157931
  const skills = await args.service.listInstalledSkillsForActor(args.actorId);
@@ -157759,7 +157958,7 @@ function connectorSkillToFiles(c) {
157759
157958
  skillId: c.id,
157760
157959
  path: path30,
157761
157960
  content,
157762
- blobHash: (0, import_node_crypto22.createHash)("sha256").update(content).digest("hex"),
157961
+ blobHash: (0, import_node_crypto23.createHash)("sha256").update(content).digest("hex"),
157763
157962
  size: Buffer.byteLength(content, "utf8"),
157764
157963
  updatedAt: "1970-01-01T00:00:00.000Z"
157765
157964
  }));
@@ -157776,11 +157975,11 @@ function connectorSkillDisplayRows(connectorSkills, enabledConnectors) {
157776
157975
  ...s2.version !== void 0 ? { version: s2.version } : {}
157777
157976
  }));
157778
157977
  }
157779
- var import_node_crypto22;
157978
+ var import_node_crypto23;
157780
157979
  var init_skill_materializer = __esm({
157781
157980
  "../server/src/domains/actors/skill-materializer.ts"() {
157782
157981
  "use strict";
157783
- import_node_crypto22 = require("node:crypto");
157982
+ import_node_crypto23 = require("node:crypto");
157784
157983
  }
157785
157984
  });
157786
157985
 
@@ -158719,7 +158918,7 @@ function createActorsDomain(opts) {
158719
158918
  ...kernel !== void 0 ? { onRolesChanged: (a, r) => kernel.setActorRoles(a, r) } : {},
158720
158919
  audit: async (entry) => {
158721
158920
  await opts.audit?.({
158722
- id: `reg_${(0, import_node_crypto23.randomUUID)()}`,
158921
+ id: `reg_${(0, import_node_crypto24.randomUUID)()}`,
158723
158922
  actor: entry.by,
158724
158923
  kind: "registry_change",
158725
158924
  target: entry.actorId,
@@ -158754,11 +158953,11 @@ function createActorsDomain(opts) {
158754
158953
  register: actorsDomain({ resolveCtx, ...opts.trace ? { trace: opts.trace } : {}, ...opts.listBuiltinSkills ? { listBuiltinSkills: opts.listBuiltinSkills } : {}, ...opts.getBuiltinSkills ? { getBuiltinSkills: opts.getBuiltinSkills } : {}, ...opts.getConnectorSkills ? { getConnectorSkills: opts.getConnectorSkills } : {}, ...opts.refreshConnectorSkills ? { refreshConnectorSkills: opts.refreshConnectorSkills } : {}, ...opts.memory ? { memory: opts.memory } : {} })
158755
158954
  };
158756
158955
  }
158757
- var import_node_crypto23;
158956
+ var import_node_crypto24;
158758
158957
  var init_actors = __esm({
158759
158958
  "../server/src/domains/actors/index.ts"() {
158760
158959
  "use strict";
158761
- import_node_crypto23 = require("node:crypto");
158960
+ import_node_crypto24 = require("node:crypto");
158762
158961
  init_service3();
158763
158962
  init_routes();
158764
158963
  init_service3();
@@ -159814,11 +160013,11 @@ var init_projects = __esm({
159814
160013
  });
159815
160014
 
159816
160015
  // ../server/src/domains/companies/service.ts
159817
- var import_node_crypto24, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, SLUG_RE, CompanyError, CompaniesService;
160016
+ var import_node_crypto25, ROLES, INVITABLE_ROLES, INVITATION_TTL_MS, SLUG_RE, CompanyError, CompaniesService;
159818
160017
  var init_service4 = __esm({
159819
160018
  "../server/src/domains/companies/service.ts"() {
159820
160019
  "use strict";
159821
- import_node_crypto24 = require("node:crypto");
160020
+ import_node_crypto25 = require("node:crypto");
159822
160021
  ROLES = ["owner", "admin", "member"];
159823
160022
  INVITABLE_ROLES = ["admin", "member"];
159824
160023
  INVITATION_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
@@ -159866,7 +160065,7 @@ var init_service4 = __esm({
159866
160065
  const existing = await this.store.getAccountByEmail(normalized);
159867
160066
  if (existing) return existing;
159868
160067
  const account = {
159869
- id: `actor:human:${(0, import_node_crypto24.randomUUID)()}`,
160068
+ id: `actor:human:${(0, import_node_crypto25.randomUUID)()}`,
159870
160069
  email: normalized,
159871
160070
  name: name ?? normalized,
159872
160071
  status: "active"
@@ -160026,7 +160225,7 @@ var init_service4 = __esm({
160026
160225
  }
160027
160226
  const nowMs = Date.parse(this.now());
160028
160227
  const invitation = {
160029
- id: `invitation:${(0, import_node_crypto24.randomUUID)()}`,
160228
+ id: `invitation:${(0, import_node_crypto25.randomUUID)()}`,
160030
160229
  companyId,
160031
160230
  email: mail,
160032
160231
  role,
@@ -161062,6 +161261,23 @@ function daemonVersionLess(a, b2) {
161062
161261
  function nodesDomain(deps) {
161063
161262
  const UPDATE_TIMEOUT_MS = 15e4;
161064
161263
  const nodeUpdates = /* @__PURE__ */ new Map();
161264
+ function runtimeInfoOf(r) {
161265
+ const activeRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161266
+ const activeRuns = deps.activeRunsOf?.(r.nodeId, r.kind);
161267
+ return {
161268
+ id: r.id,
161269
+ nodeId: r.nodeId,
161270
+ hostname: r.hostname,
161271
+ kind: r.kind,
161272
+ ...r.binary ? { binary: r.binary } : {},
161273
+ ...r.version ? { version: r.version } : {},
161274
+ status: r.status,
161275
+ busy: activeRunCount > 0,
161276
+ activeRunCount,
161277
+ ...activeRuns ? { activeRuns } : {},
161278
+ lastReportAt: r.lastSeenAt
161279
+ };
161280
+ }
161065
161281
  const publicUpdateStatus = (entry, activeRunCount) => ({
161066
161282
  state: entry.state,
161067
161283
  requestedAt: new Date(entry.requestedAtMs).toISOString(),
@@ -161211,21 +161427,7 @@ function nodesDomain(deps) {
161211
161427
  id: n.id,
161212
161428
  hostname: n.hostname,
161213
161429
  adapters: rts.map((r) => r.kind),
161214
- runtimes: rts.map((r) => {
161215
- const runtimeActiveRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161216
- return {
161217
- id: r.id,
161218
- nodeId: r.nodeId,
161219
- hostname: r.hostname,
161220
- kind: r.kind,
161221
- ...r.binary ? { binary: r.binary } : {},
161222
- ...r.version ? { version: r.version } : {},
161223
- status: r.status,
161224
- busy: runtimeActiveRunCount > 0,
161225
- activeRunCount: runtimeActiveRunCount,
161226
- lastReportAt: r.lastSeenAt
161227
- };
161228
- }),
161430
+ runtimes: rts.map(runtimeInfoOf),
161229
161431
  nodeVersion: n.nodeVersion,
161230
161432
  ...daemonVersion ? { daemonVersion } : {},
161231
161433
  ...n.name ? { name: n.name } : {},
@@ -161258,38 +161460,10 @@ function nodesDomain(deps) {
161258
161460
  const stale = [...new Set(rts.filter((r) => onlineIds.has(r.nodeId) && r.status !== "online").map((r) => r.nodeId))];
161259
161461
  if (stale.length > 0) {
161260
161462
  await Promise.all(stale.map((id) => syncConnectedDaemon(id, hub)));
161261
- return { status: 200, body: { items: (await deps.nodeStore.listRuntimes()).map((r) => {
161262
- const activeRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161263
- return {
161264
- id: r.id,
161265
- nodeId: r.nodeId,
161266
- hostname: r.hostname,
161267
- kind: r.kind,
161268
- ...r.binary ? { binary: r.binary } : {},
161269
- ...r.version ? { version: r.version } : {},
161270
- status: r.status,
161271
- busy: activeRunCount > 0,
161272
- activeRunCount,
161273
- lastReportAt: r.lastSeenAt
161274
- };
161275
- }) } };
161463
+ return { status: 200, body: { items: (await deps.nodeStore.listRuntimes()).map(runtimeInfoOf) } };
161276
161464
  }
161277
161465
  }
161278
- const items = rts.map((r) => {
161279
- const activeRunCount = deps.activeRunCountOf?.(r.nodeId, r.kind) ?? 0;
161280
- return {
161281
- id: r.id,
161282
- nodeId: r.nodeId,
161283
- hostname: r.hostname,
161284
- kind: r.kind,
161285
- ...r.binary ? { binary: r.binary } : {},
161286
- ...r.version ? { version: r.version } : {},
161287
- status: r.status,
161288
- busy: activeRunCount > 0,
161289
- activeRunCount,
161290
- lastReportAt: r.lastSeenAt
161291
- };
161292
- });
161466
+ const items = rts.map(runtimeInfoOf);
161293
161467
  return { status: 200, body: { items } };
161294
161468
  });
161295
161469
  router.post("/api/nodes/enroll", async (req) => {
@@ -161315,7 +161489,7 @@ function nodesDomain(deps) {
161315
161489
  nodeId = incomingNodeId;
161316
161490
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
161317
161491
  } else {
161318
- nodeId = `node-${(0, import_node_crypto25.randomUUID)().slice(0, 8)}`;
161492
+ nodeId = `node-${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`;
161319
161493
  deps.enrollTokens.setIssuedNodeId(enrollToken, nodeId);
161320
161494
  }
161321
161495
  const existingNode = await deps.nodeStore.getNode(nodeId);
@@ -161453,11 +161627,11 @@ function nodesDomain(deps) {
161453
161627
  });
161454
161628
  };
161455
161629
  }
161456
- var import_node_crypto25, import_node_fs11, import_node_url4, import_node_path13;
161630
+ var import_node_crypto26, import_node_fs11, import_node_url4, import_node_path13;
161457
161631
  var init_routes5 = __esm({
161458
161632
  "../server/src/domains/nodes/routes.ts"() {
161459
161633
  "use strict";
161460
- import_node_crypto25 = require("node:crypto");
161634
+ import_node_crypto26 = require("node:crypto");
161461
161635
  import_node_fs11 = require("node:fs");
161462
161636
  import_node_url4 = require("node:url");
161463
161637
  import_node_path13 = require("node:path");
@@ -162655,13 +162829,13 @@ function nameKey(name) {
162655
162829
  function cleanName(name) {
162656
162830
  return name.trim().replace(/\s+/g, " ");
162657
162831
  }
162658
- var import_node_fs12, import_node_path14, import_node_crypto26, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
162832
+ var import_node_fs12, import_node_path14, import_node_crypto27, SEP, keyOf, prefixOf, MemoryWorkorderTagStore, FileWorkorderTagStore;
162659
162833
  var init_tags = __esm({
162660
162834
  "../server/src/domains/collab/tags.ts"() {
162661
162835
  "use strict";
162662
162836
  import_node_fs12 = __toESM(require("node:fs"), 1);
162663
162837
  import_node_path14 = __toESM(require("node:path"), 1);
162664
- import_node_crypto26 = __toESM(require("node:crypto"), 1);
162838
+ import_node_crypto27 = __toESM(require("node:crypto"), 1);
162665
162839
  SEP = "::";
162666
162840
  keyOf = (companyId, id) => `${companyId}${SEP}${id}`;
162667
162841
  prefixOf = (companyId) => `${companyId}${SEP}`;
@@ -162679,7 +162853,7 @@ var init_tags = __esm({
162679
162853
  if (!name) return null;
162680
162854
  if (this.entries(companyId).some((t) => nameKey(t.name) === nameKey(name))) return null;
162681
162855
  const tag = {
162682
- id: `tag-${import_node_crypto26.default.randomBytes(6).toString("hex")}`,
162856
+ id: `tag-${import_node_crypto27.default.randomBytes(6).toString("hex")}`,
162683
162857
  name,
162684
162858
  ...input.color?.trim() ? { color: input.color.trim() } : {},
162685
162859
  ...input.description?.trim() ? { description: input.description.trim() } : {}
@@ -163274,7 +163448,7 @@ var init_collab = __esm({
163274
163448
 
163275
163449
  // ../server/src/domains/collab/create-seeded-workorder.ts
163276
163450
  function makeSeededWorkorderCreator(deps) {
163277
- const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto27.randomUUID)().slice(0, 8)}`);
163451
+ const genWorkspace = deps.genWorkspace ?? (() => `ws:wo-${(0, import_node_crypto28.randomUUID)().slice(0, 8)}`);
163278
163452
  return async (input) => {
163279
163453
  const workspace = genWorkspace();
163280
163454
  if (deps.artifactState && (input.projectId || deps.createProject)) {
@@ -163354,11 +163528,11 @@ function makeSeededWorkorderCreator(deps) {
163354
163528
  return { workspace, rootArtifactId: briefId, spawned: planned.spawned };
163355
163529
  };
163356
163530
  }
163357
- var import_node_crypto27, enc2;
163531
+ var import_node_crypto28, enc2;
163358
163532
  var init_create_seeded_workorder = __esm({
163359
163533
  "../server/src/domains/collab/create-seeded-workorder.ts"() {
163360
163534
  "use strict";
163361
- import_node_crypto27 = require("node:crypto");
163535
+ import_node_crypto28 = require("node:crypto");
163362
163536
  init_ephemeral_project();
163363
163537
  init_planner();
163364
163538
  enc2 = (s2) => new TextEncoder().encode(s2);
@@ -164212,7 +164386,7 @@ function createChatSessionsDomain(opts) {
164212
164386
  const runtimeId = await currentRuntimeId(body.aiActorId) ?? "unknown";
164213
164387
  const now = (/* @__PURE__ */ new Date()).toISOString();
164214
164388
  const session = {
164215
- id: (0, import_node_crypto28.randomUUID)(),
164389
+ id: (0, import_node_crypto29.randomUUID)(),
164216
164390
  humanActorId: req.auth.actor,
164217
164391
  aiActorId: body.aiActorId,
164218
164392
  runtimeId,
@@ -164285,7 +164459,7 @@ function createChatSessionsDomain(opts) {
164285
164459
  if (body.role !== "user" && body.role !== "assistant") throw new ApiError(400, "BAD_REQUEST", "role must be user or assistant");
164286
164460
  const role = body.role;
164287
164461
  const msg = await store.appendMessage({
164288
- id: (0, import_node_crypto28.randomUUID)(),
164462
+ id: (0, import_node_crypto29.randomUUID)(),
164289
164463
  sessionId: req.params.id,
164290
164464
  role,
164291
164465
  content: role === "user" ? stripInjectedChatContext(body.content) : body.content,
@@ -164377,11 +164551,11 @@ function createChatSessionsDomain(opts) {
164377
164551
  });
164378
164552
  };
164379
164553
  }
164380
- var import_node_crypto28, WORKDIR_READ_MAX_BYTES;
164554
+ var import_node_crypto29, WORKDIR_READ_MAX_BYTES;
164381
164555
  var init_chat_sessions = __esm({
164382
164556
  "../server/src/domains/chat-sessions/index.ts"() {
164383
164557
  "use strict";
164384
- import_node_crypto28 = require("node:crypto");
164558
+ import_node_crypto29 = require("node:crypto");
164385
164559
  init_chat_session();
164386
164560
  init_router();
164387
164561
  init_workorders();
@@ -165592,14 +165766,294 @@ var init_project_binding = __esm({
165592
165766
  }
165593
165767
  });
165594
165768
 
165769
+ // ../server/src/domains/evaluation/judge-prompt.ts
165770
+ function builtinRubricsForCase(evaluationCase) {
165771
+ const at = "1970-01-01T00:00:00.000Z";
165772
+ const base = {
165773
+ companyId: "",
165774
+ version: 0,
165775
+ status: "active",
165776
+ createdBy: "system",
165777
+ createdAt: at,
165778
+ updatedBy: "system",
165779
+ updatedAt: at
165780
+ };
165781
+ return [
165782
+ {
165783
+ ...base,
165784
+ rubricId: "builtin:common",
165785
+ name: "\u901A\u7528\u80FD\u529B\u6807\u51C6\uFF08Case \u81EA\u5E26\uFF09",
165786
+ kind: "common",
165787
+ promptSection: evaluationCase.commonRubric,
165788
+ outputSpec: BUILTIN_COMMON_OUTPUT_SPEC
165789
+ },
165790
+ {
165791
+ ...base,
165792
+ rubricId: "builtin:specialty",
165793
+ name: `S \u4E13\u9879\u6807\u51C6\uFF08${evaluationCase.scopeType}\uFF0CCase \u81EA\u5E26\uFF09`,
165794
+ kind: "specialty",
165795
+ // 「只看可读专业产物」这条约束原先写在硬编码提示词里、不在 bench 的专项标准正文里。
165796
+ // 搬到这里而不是丢掉——它同时还有代码侧的事后守卫(enforceSpecialtyArtifactBoundary),
165797
+ // 两边必须说同一件事,否则模型评了分又被守卫抹掉,白跑一轮还看不懂为什么。
165798
+ promptSection: [
165799
+ "S \u4E13\u9879\u53EA\u80FD\u4F9D\u636E artifacts \u4E2D\u53EF\u8BFB\u7684\u4E13\u4E1A\u4EA7\u7269\u6B63\u6587\u5224\u65AD\u3002Trace\u3001\u8282\u70B9\u6458\u8981\u548C Brief \u4E0D\u80FD\u66FF\u4EE3\u4E13\u4E1A\u4EA7\u7269\u3002",
165800
+ "\u6CA1\u6709\u53EF\u8BFB\u4E13\u4E1A\u4EA7\u7269\u65F6\uFF0C\u4E94\u9879 score\u3001specialty.score \u548C specialty.score100 \u5FC5\u987B\u5168\u90E8\u4E3A null\u3002",
165801
+ "",
165802
+ evaluationCase.specialtyRubric
165803
+ ].join("\n"),
165804
+ outputSpec: BUILTIN_SPECIALTY_OUTPUT_SPEC
165805
+ },
165806
+ {
165807
+ ...base,
165808
+ rubricId: "builtin:case_special",
165809
+ name: "Case \u4E13\u9879\u6807\u51C6\uFF08Case \u81EA\u5E26\uFF09",
165810
+ kind: "case_special",
165811
+ promptSection: [
165812
+ "\u53EA\u4F9D\u636E\u6700\u7EC8\u4EA7\u7269\u53CA evaluator \u7ED3\u679C\u7ED9\u5206\u3002",
165813
+ "evaluator.type=native \u7684\u9879\u76EE\u53EA\u80FD\u8BFB\u53D6\u771F\u5B9E native evaluator \u8F93\u51FA\uFF1B\u5F53\u524D\u8BC1\u636E\u6CA1\u6709\u8BE5\u8F93\u51FA\u65F6\u5FC5\u987B\u8FD4\u56DE",
165814
+ "status=evaluator_failed\uFF0C\u7981\u6B62\u7531 LLM \u4EE3\u6253\u5B98\u65B9\u5206\u6570\u3002"
165815
+ ].join("\n"),
165816
+ outputSpec: BUILTIN_CASE_SPECIAL_OUTPUT_SPEC
165817
+ }
165818
+ ];
165819
+ }
165820
+ function caseSpecialItemDefinitions(evaluationCase) {
165821
+ const items = Array.isArray(evaluationCase.caseSpecial["items"]) ? evaluationCase.caseSpecial["items"] : [];
165822
+ return items.flatMap((raw) => {
165823
+ const item = asRecord2(raw);
165824
+ if (!item || typeof item["id"] !== "string") return [];
165825
+ const evaluator = asRecord2(item["evaluator"]);
165826
+ return [{
165827
+ id: item["id"],
165828
+ label: typeof item["label"] === "string" ? item["label"] : typeof item["description"] === "string" ? item["description"] : item["id"],
165829
+ maxScore: typeof item["max_score"] === "number" ? item["max_score"] : null,
165830
+ evaluatorType: typeof evaluator?.["type"] === "string" ? evaluator["type"] : null
165831
+ }];
165832
+ });
165833
+ }
165834
+ function sectionSkeleton(spec, caseSpecialItems) {
165835
+ if (spec.dimensions.length) {
165836
+ const rows2 = spec.dimensions.map((dimension) => ` - ${dimension.id}\uFF08${dimension.label}\uFF09\uFF1A${dimension.min}-${dimension.max} \u5206${dimension.nullable ? "\uFF0C\u786E\u5B9E\u4E0D\u9002\u7528\u65F6\u53EF\u4E3A null" : "\uFF0C\u4E0D\u5F97\u4E3A null"}`);
165837
+ const aggregation = spec.aggregation === "mean" ? `
165838
+ \u6BB5\u5185\u8FD8\u9700\u7ED9\u51FA score\uFF08\u5404\u7EF4\u5EA6\u5747\u503C\uFF09\u4E0E score100\uFF08\u5747\u503C\u6362\u7B97\u767E\u5206\u5236\uFF09\uFF0C\u7EF4\u5EA6\u4E0D\u5168\u65F6\u4E24\u8005\u90FD\u4E3A null\u3002` : "";
165839
+ return ` "${spec.sectionKey}".dimensions \u5FC5\u987B\u6070\u597D ${spec.dimensions.length} \u9879\uFF1A
165840
+ ${rows2.join("\n")}${aggregation}`;
165841
+ }
165842
+ if (!caseSpecialItems.length) {
165843
+ return ` "${spec.sectionKey}".items \u4E3A\u6570\u7EC4\uFF1B\u672C Case \u6CA1\u6709\u5B9A\u4E49\u8BC4\u5206\u9879\u65F6\u7ED9\u7A7A\u6570\u7EC4 []\uFF0C\u4E0D\u8981\u7701\u7565\u8BE5\u5B57\u6BB5\u3002`;
165844
+ }
165845
+ const rows = caseSpecialItems.map((item) => ` - id="${item.id}"\uFF08${item.label}\uFF09${item.maxScore === null ? "" : `\uFF0C\u6EE1\u5206 ${item.maxScore}`}${item.evaluatorType ? `\uFF0Cevaluator=${item.evaluatorType}` : ""}`);
165846
+ return [
165847
+ ` "${spec.sectionKey}".items \u5FC5\u987B\u9010\u9879\u8986\u76D6\u4E0B\u9762 ${caseSpecialItems.length} \u4E2A id\uFF0C\u4E00\u4E2A\u90FD\u4E0D\u80FD\u5C11\uFF1A`,
165848
+ ...rows,
165849
+ ` \u6BCF\u9879\u542B id / label / score / maxScore / status / reasoning\uFF1B`,
165850
+ ` status \u2208 scored | not_applicable | evaluator_failed\uFF1B\u62FF\u4E0D\u5230 evaluator \u8F93\u51FA\u5C31\u586B evaluator_failed \u4E14 score=null\u3002`
165851
+ ].join("\n");
165852
+ }
165853
+ function caseContextForPrompt(evaluationCase) {
165854
+ const {
165855
+ commonRubric: _commonRubric,
165856
+ specialtyRubric: _specialtyRubric,
165857
+ caseSpecial: _caseSpecial,
165858
+ ...rest
165859
+ } = evaluationCase;
165860
+ return rest;
165861
+ }
165862
+ function buildJudgePrompt(input) {
165863
+ const items = caseSpecialItemDefinitions(input.evaluationCase);
165864
+ const specs = input.rubrics.map((rubric) => rubric.outputSpec);
165865
+ const sections = input.rubrics.map((rubric, index) => [
165866
+ `### \u6807\u51C6 ${index + 1}\uFF0F${input.rubrics.length}\uFF1A${rubric.name}`,
165867
+ `- \u7C7B\u578B\uFF1A${rubric.kind}\uFF1B\u8F93\u51FA\u5230\u7ED3\u679C JSON \u7684 "${rubric.outputSpec.sectionKey}" \u6BB5` + (rubric.version ? `\uFF1B\u7248\u672C ${rubric.rubricId}@${rubric.version}` : ""),
165868
+ ...rubric.description ? [`- \u8BF4\u660E\uFF1A${rubric.description}`] : [],
165869
+ "",
165870
+ rubric.promptSection.trim()
165871
+ ].join("\n"));
165872
+ return [
165873
+ "\u4F60\u662F Oasis Benchmark \u7684\u8BC4\u5206\u5458\u5DE5\u3002\u672C\u6B21\u4EFB\u52A1\u53EA\u505A\u8BC4\u6D4B\uFF0C\u4E0D\u4FEE\u6539\u88AB\u6D4B\u5DE5\u5355\u3002",
165874
+ `evaluation_id: ${input.evaluationId}`,
165875
+ "",
165876
+ "## \u8BC4\u5206\u6807\u51C6\uFF08\u9010\u6761\u9002\u7528\uFF0C\u7F3A\u4E00\u4E0D\u53EF\uFF09",
165877
+ "",
165878
+ sections.join("\n\n"),
165879
+ "",
165880
+ "## \u8F93\u51FA\u8981\u6C42",
165881
+ "",
165882
+ "\u53EA\u8FD4\u56DE\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8FD4\u56DE Markdown \u89E3\u91CA\u3001\u4E0D\u8981\u52A0\u4EE3\u7801\u5757\u4EE5\u5916\u7684\u6B63\u6587\u3002\u5BF9\u8C61\u5FC5\u987B\u540C\u65F6\u5305\u542B\u4E0B\u5217\u5404\u6BB5\uFF1A",
165883
+ specs.map((spec) => sectionSkeleton(spec, items)).join("\n"),
165884
+ ' "runtimeMetrics"\uFF1A\u539F\u6837\u4FDD\u7559\u8BC1\u636E\u4E2D\u7684\u8FD0\u884C\u6307\u6807\uFF0C\u4E0D\u8FDB\u5165\u8D28\u91CF\u5206\u3002',
165885
+ "",
165886
+ "\u7981\u6B62\u751F\u6210\u8DE8\u6BB5\u7684\u603B\u4F53\u603B\u5206\u3002\u6BCF\u4E2A\u7EF4\u5EA6\u90FD\u8981\u7ED9 reasoning\uFF0C\u5E76\u5C3D\u91CF\u5E26 evidenceRefs\u3002",
165887
+ "",
165888
+ "## CASE",
165889
+ JSON.stringify(caseContextForPrompt(input.evaluationCase)),
165890
+ "",
165891
+ "## EVIDENCE SNAPSHOT",
165892
+ input.evidenceJson
165893
+ ].join("\n");
165894
+ }
165895
+ var asRecord2;
165896
+ var init_judge_prompt = __esm({
165897
+ "../server/src/domains/evaluation/judge-prompt.ts"() {
165898
+ "use strict";
165899
+ init_src();
165900
+ asRecord2 = (value2) => value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
165901
+ }
165902
+ });
165903
+
165904
+ // ../server/src/domains/evaluation/scoring.ts
165905
+ var ScoringConfigError, EvaluationScoringService;
165906
+ var init_scoring = __esm({
165907
+ "../server/src/domains/evaluation/scoring.ts"() {
165908
+ "use strict";
165909
+ init_src();
165910
+ init_judge_prompt();
165911
+ ScoringConfigError = class extends Error {
165912
+ constructor(statusCode, code, message) {
165913
+ super(message);
165914
+ this.statusCode = statusCode;
165915
+ this.code = code;
165916
+ this.name = "ScoringConfigError";
165917
+ }
165918
+ };
165919
+ EvaluationScoringService = class {
165920
+ constructor(options) {
165921
+ this.options = options;
165922
+ }
165923
+ at() {
165924
+ return (this.options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
165925
+ }
165926
+ listRubrics(companyId) {
165927
+ return this.options.store.listRubrics(companyId);
165928
+ }
165929
+ async upsertRubric(body, companyId, actor) {
165930
+ const raw = body ?? {};
165931
+ const rubricId = typeof raw["rubricId"] === "string" && raw["rubricId"] ? raw["rubricId"] : void 0;
165932
+ let existing = null;
165933
+ if (rubricId) {
165934
+ existing = await this.options.store.getRubric(rubricId);
165935
+ if (existing && existing.companyId !== companyId) {
165936
+ throw new ScoringConfigError(404, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
165937
+ }
165938
+ }
165939
+ const merged = existing ? {
165940
+ rubricId,
165941
+ name: raw["name"] ?? existing.name,
165942
+ kind: raw["kind"] ?? existing.kind,
165943
+ description: raw["description"] ?? existing.description,
165944
+ promptSection: raw["promptSection"] ?? existing.promptSection,
165945
+ outputSpec: raw["outputSpec"] ?? existing.outputSpec,
165946
+ status: raw["status"] ?? existing.status
165947
+ } : raw;
165948
+ let input;
165949
+ try {
165950
+ input = validateUpsertEvaluationRubricInput(merged);
165951
+ } catch (error2) {
165952
+ throw new ScoringConfigError(400, "BAD_REQUEST", error2 instanceof Error ? error2.message : String(error2));
165953
+ }
165954
+ return this.options.store.upsertRubric({ ...input, companyId, actor }, this.at());
165955
+ }
165956
+ async deleteRubric(rubricId, companyId) {
165957
+ const existing = await this.options.store.getRubric(rubricId);
165958
+ if (!existing || existing.companyId !== companyId) {
165959
+ throw new ScoringConfigError(404, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
165960
+ }
165961
+ await this.options.store.deleteRubric(rubricId, companyId);
165962
+ }
165963
+ listBindings(companyId) {
165964
+ return this.options.store.listBindings(companyId);
165965
+ }
165966
+ async putBinding(caseId, body, companyId, actor) {
165967
+ const input = body ?? {};
165968
+ const rubricIds = Array.isArray(input.rubricIds) ? input.rubricIds.filter((id) => typeof id === "string" && id.length > 0) : [];
165969
+ if (new Set(rubricIds).size !== rubricIds.length) {
165970
+ throw new ScoringConfigError(400, "BAD_REQUEST", "\u540C\u4E00\u6761\u8BC4\u5206\u6807\u51C6\u4E0D\u80FD\u91CD\u590D\u6302\u8F7D");
165971
+ }
165972
+ const rubrics = [];
165973
+ for (const rubricId of rubricIds) {
165974
+ const rubric = await this.options.store.getRubric(rubricId);
165975
+ if (!rubric || rubric.companyId !== companyId) {
165976
+ throw new ScoringConfigError(400, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
165977
+ }
165978
+ if (rubric.status !== "active") {
165979
+ throw new ScoringConfigError(400, "RUBRIC_ARCHIVED", `\u8BC4\u5206\u6807\u51C6\u300C${rubric.name}\u300D\u5DF2\u5F52\u6863\uFF0C\u4E0D\u80FD\u6302\u8F7D`);
165980
+ }
165981
+ rubrics.push(rubric);
165982
+ }
165983
+ const sections = rubrics.map((rubric) => rubric.outputSpec.sectionKey);
165984
+ if (new Set(sections).size !== sections.length) {
165985
+ throw new ScoringConfigError(
165986
+ 400,
165987
+ "RUBRIC_SECTION_CONFLICT",
165988
+ `\u6302\u8F7D\u7684\u6807\u51C6\u8F93\u51FA\u5230\u4E86\u540C\u4E00\u4E2A\u7ED3\u679C\u6BB5\uFF08${sections.join("\u3001")}\uFF09\uFF0C\u8BF7\u6539\u5176\u4E2D\u4E00\u6761\u7684 sectionKey`
165989
+ );
165990
+ }
165991
+ const judgeActorId = typeof input.judgeActorId === "string" && input.judgeActorId.trim() ? input.judgeActorId.trim() : null;
165992
+ if (judgeActorId && this.options.verifyJudgeActor && !await this.options.verifyJudgeActor(judgeActorId, companyId)) {
165993
+ throw new ScoringConfigError(400, "JUDGE_ACTOR_INVALID", `${judgeActorId} \u4E0D\u662F\u53EF\u7528\u7684\u5224\u5206\u5458\u5DE5`);
165994
+ }
165995
+ const binding = await this.options.store.putBinding(
165996
+ { companyId, caseId, rubricIds, judgeActorId, actor },
165997
+ this.at()
165998
+ );
165999
+ return {
166000
+ caseId,
166001
+ rubrics,
166002
+ judgeActorId: binding.judgeActorId,
166003
+ usesBuiltinFallback: rubrics.length === 0
166004
+ };
166005
+ }
166006
+ /** Case 当前装配的对外投影(挂载展开 + 是否还在吃回落)。 */
166007
+ async getCaseScoring(caseId, companyId) {
166008
+ const binding = await this.options.store.getBinding(companyId, caseId);
166009
+ const rubrics = await this.mountedRubrics(binding, companyId);
166010
+ return {
166011
+ caseId,
166012
+ rubrics,
166013
+ judgeActorId: binding?.judgeActorId ?? null,
166014
+ usesBuiltinFallback: rubrics.length === 0
166015
+ };
166016
+ }
166017
+ /** 判分前的最终解析:拿到本次真正要用的标准与判分员工。 */
166018
+ async resolveForRun(evaluationCase, companyId, requestedJudgeActorId) {
166019
+ const binding = await this.options.store.getBinding(companyId, evaluationCase.id);
166020
+ const mounted = await this.mountedRubrics(binding, companyId);
166021
+ const judgeActorId = requestedJudgeActorId?.trim() || binding?.judgeActorId || this.options.defaultJudgeActorId;
166022
+ if (!judgeActorId) {
166023
+ throw new ScoringConfigError(
166024
+ 409,
166025
+ "JUDGE_ACTOR_NOT_CONFIGURED",
166026
+ "\u6CA1\u6709\u53EF\u7528\u7684\u5224\u5206\u5458\u5DE5\uFF1A\u8BF7\u5728 Case \u8BC4\u5206\u88C5\u914D\u91CC\u6307\u5B9A\uFF0C\u6216\u914D\u7F6E OASIS_EVALUATION_SCORING_ACTOR_ID"
166027
+ );
166028
+ }
166029
+ return {
166030
+ rubrics: mounted.length ? mounted : builtinRubricsForCase(evaluationCase),
166031
+ judgeActorId,
166032
+ usesBuiltinFallback: mounted.length === 0
166033
+ };
166034
+ }
166035
+ async mountedRubrics(binding, companyId) {
166036
+ if (!binding?.rubricIds.length) return [];
166037
+ const rubrics = [];
166038
+ for (const rubricId of binding.rubricIds) {
166039
+ const rubric = await this.options.store.getRubric(rubricId);
166040
+ if (rubric && rubric.companyId === companyId && rubric.status === "active") rubrics.push(rubric);
166041
+ }
166042
+ return rubrics;
166043
+ }
166044
+ };
166045
+ }
166046
+ });
166047
+
165595
166048
  // ../server/src/domains/evaluation/service.ts
165596
- var import_node_crypto29, EvaluationError, EvaluationService;
166049
+ var import_node_crypto30, EvaluationError, EvaluationService;
165597
166050
  var init_service7 = __esm({
165598
166051
  "../server/src/domains/evaluation/service.ts"() {
165599
166052
  "use strict";
165600
- import_node_crypto29 = require("node:crypto");
166053
+ import_node_crypto30 = require("node:crypto");
165601
166054
  init_src();
165602
166055
  init_project_binding();
166056
+ init_scoring();
165603
166057
  EvaluationError = class extends Error {
165604
166058
  constructor(statusCode, code, message) {
165605
166059
  super(message);
@@ -165612,7 +166066,7 @@ var init_service7 = __esm({
165612
166066
  constructor(options) {
165613
166067
  this.options = options;
165614
166068
  this.now = options.now ?? (() => /* @__PURE__ */ new Date());
165615
- this.id = options.id ?? import_node_crypto29.randomUUID;
166069
+ this.id = options.id ?? import_node_crypto30.randomUUID;
165616
166070
  }
165617
166071
  now;
165618
166072
  id;
@@ -165715,10 +166169,17 @@ var init_service7 = __esm({
165715
166169
  createdBy: actor,
165716
166170
  createdAt: now
165717
166171
  });
165718
- const evaluation = await this.createEvaluation(run.runId, evaluationCase, actor, true);
166172
+ const evaluation = await this.createEvaluation(
166173
+ run.runId,
166174
+ evaluationCase,
166175
+ actor,
166176
+ companyId,
166177
+ input.judgeActorId,
166178
+ true
166179
+ );
165719
166180
  return { run, evaluation };
165720
166181
  }
165721
- async createRescore(runId, actor, companyId = "default") {
166182
+ async createRescore(runId, actor, companyId = "default", judgeActorId) {
165722
166183
  const run = await this.options.store.getRun(runId);
165723
166184
  if (!run || run.companyId !== companyId) {
165724
166185
  throw new EvaluationError(404, "RUN_NOT_FOUND", `Run ${runId} \u4E0D\u5B58\u5728`);
@@ -165728,7 +166189,7 @@ var init_service7 = __esm({
165728
166189
  if (!evaluationCase) {
165729
166190
  throw new EvaluationError(409, "CASE_VERSION_MISSING", `Case ${run.caseId}@${run.caseVersion} \u4E0D\u5B58\u5728`);
165730
166191
  }
165731
- return this.createEvaluation(runId, evaluationCase, actor);
166192
+ return this.createEvaluation(runId, evaluationCase, actor, companyId, judgeActorId);
165732
166193
  }
165733
166194
  async runEvaluation(evaluationId, companyId) {
165734
166195
  const current = await this.options.store.getEvaluation(evaluationId);
@@ -165752,11 +166213,18 @@ var init_service7 = __esm({
165752
166213
  };
165753
166214
  await this.options.store.updateEvaluation(started);
165754
166215
  try {
166216
+ const resolved = await this.options.scoring.resolveForRun(
166217
+ evaluationCase,
166218
+ run.companyId,
166219
+ current.judgeActorId
166220
+ );
165755
166221
  const judged = await this.options.judge.evaluate({
165756
166222
  ...companyId ? { companyId } : {},
165757
166223
  evaluationId,
165758
166224
  evaluationCase,
165759
- evidenceSnapshot: run.evidenceSnapshot
166225
+ evidenceSnapshot: run.evidenceSnapshot,
166226
+ rubrics: resolved.rubrics,
166227
+ judgeActorId: resolved.judgeActorId
165760
166228
  });
165761
166229
  const snapshotMetrics = run.evidenceSnapshot["runtimeMetrics"];
165762
166230
  const result = {
@@ -165828,15 +166296,20 @@ var init_service7 = __esm({
165828
166296
  benchmarkProjects
165829
166297
  };
165830
166298
  }
165831
- createEvaluation(runId, evaluationCase, actor, ifRunHasNone = false) {
166299
+ /**
166300
+ * 判分员工与 rubricVersion 在**建 Evaluation 时**定下并落库,不在跑的时候再算:
166301
+ * 队列里排到再解析的话,中途改了装配就说不清「这条分是按哪套标准、谁打的」。
166302
+ */
166303
+ async createEvaluation(runId, evaluationCase, actor, companyId, judgeActorId, ifRunHasNone = false) {
165832
166304
  const now = this.now().toISOString();
166305
+ const resolved = await this.options.scoring.resolveForRun(evaluationCase, companyId, judgeActorId);
165833
166306
  return this.options.store.createEvaluation({
165834
166307
  evaluationId: this.id(),
165835
166308
  runId,
165836
166309
  status: "queued",
165837
- judgeActorId: this.options.judgeActorId,
166310
+ judgeActorId: resolved.judgeActorId,
165838
166311
  judgeVersion: this.options.judgeVersion,
165839
- rubricVersion: evaluationCase.rubricVersion,
166312
+ rubricVersion: rubricVersionOf(resolved.rubrics, evaluationCase.rubricVersion),
165840
166313
  evaluatorVersion: evaluationCase.evaluatorVersion,
165841
166314
  createdBy: actor,
165842
166315
  createdAt: now
@@ -165850,6 +166323,7 @@ var init_service7 = __esm({
165850
166323
  function evaluationDomain(options) {
165851
166324
  const schedule = options.schedule ?? ((task2) => queueMicrotask(task2));
165852
166325
  const service = options.service;
166326
+ const scoring = options.scoring;
165853
166327
  return (router) => {
165854
166328
  router.get("/api/evaluations/workorders", async (req) => ({
165855
166329
  status: 200,
@@ -165877,7 +166351,8 @@ function evaluationDomain(options) {
165877
166351
  const created = await service.createRun({
165878
166352
  workOrderId: body.workOrderId,
165879
166353
  caseId: body.caseId,
165880
- ...body.caseVersion ? { caseVersion: body.caseVersion } : {}
166354
+ ...body.caseVersion ? { caseVersion: body.caseVersion } : {},
166355
+ judgeActorId: optionalActorId(body.judgeActorId)
165881
166356
  }, req.auth.actor, req.auth.companyId ?? "default");
165882
166357
  schedule(() => {
165883
166358
  void service.runEvaluation(created.evaluation.evaluationId, req.auth.companyId);
@@ -165892,7 +166367,8 @@ function evaluationDomain(options) {
165892
166367
  const evaluation = await service.createRescore(
165893
166368
  req.params.runId,
165894
166369
  req.auth.actor,
165895
- req.auth.companyId ?? "default"
166370
+ req.auth.companyId ?? "default",
166371
+ optionalActorId(req.body?.judgeActorId)
165896
166372
  );
165897
166373
  schedule(() => {
165898
166374
  void service.runEvaluation(evaluation.evaluationId, req.auth.companyId);
@@ -165902,20 +166378,87 @@ function evaluationDomain(options) {
165902
166378
  return mapError(error2);
165903
166379
  }
165904
166380
  });
166381
+ router.get("/api/evaluations/rubrics", async (req) => ({
166382
+ status: 200,
166383
+ body: { items: await scoring.listRubrics(req.auth.companyId ?? "default") }
166384
+ }));
166385
+ router.post("/api/evaluations/rubrics", async (req) => {
166386
+ try {
166387
+ return {
166388
+ status: 201,
166389
+ body: await scoring.upsertRubric(req.body, req.auth.companyId ?? "default", req.auth.actor)
166390
+ };
166391
+ } catch (error2) {
166392
+ return mapError(error2);
166393
+ }
166394
+ });
166395
+ router.put("/api/evaluations/rubrics/:rubricId", async (req) => {
166396
+ try {
166397
+ return {
166398
+ status: 200,
166399
+ body: await scoring.upsertRubric(
166400
+ { ...req.body, rubricId: req.params.rubricId },
166401
+ req.auth.companyId ?? "default",
166402
+ req.auth.actor
166403
+ )
166404
+ };
166405
+ } catch (error2) {
166406
+ return mapError(error2);
166407
+ }
166408
+ });
166409
+ router.delete("/api/evaluations/rubrics/:rubricId", async (req) => {
166410
+ try {
166411
+ await scoring.deleteRubric(req.params.rubricId, req.auth.companyId ?? "default");
166412
+ return { status: 200, body: { ok: true } };
166413
+ } catch (error2) {
166414
+ return mapError(error2);
166415
+ }
166416
+ });
166417
+ router.get("/api/evaluations/case-scoring", async (req) => ({
166418
+ status: 200,
166419
+ body: { items: await scoring.listBindings(req.auth.companyId ?? "default") }
166420
+ }));
166421
+ router.get("/api/evaluations/cases/:caseId/scoring", async (req) => ({
166422
+ status: 200,
166423
+ body: await scoring.getCaseScoring(req.params.caseId, req.auth.companyId ?? "default")
166424
+ }));
166425
+ router.put("/api/evaluations/cases/:caseId/scoring", async (req) => {
166426
+ try {
166427
+ return {
166428
+ status: 200,
166429
+ body: await scoring.putBinding(
166430
+ req.params.caseId,
166431
+ req.body,
166432
+ req.auth.companyId ?? "default",
166433
+ req.auth.actor
166434
+ )
166435
+ };
166436
+ } catch (error2) {
166437
+ return mapError(error2);
166438
+ }
166439
+ });
166440
+ router.get("/api/evaluations/judge-candidates", async (req) => ({
166441
+ status: 200,
166442
+ body: {
166443
+ items: options.listJudgeCandidates ? await options.listJudgeCandidates(req.auth.companyId ?? "default") : []
166444
+ }
166445
+ }));
165905
166446
  };
165906
166447
  }
165907
- var mapError;
166448
+ var mapError, optionalActorId;
165908
166449
  var init_routes8 = __esm({
165909
166450
  "../server/src/domains/evaluation/routes.ts"() {
165910
166451
  "use strict";
165911
166452
  init_router();
165912
166453
  init_service7();
166454
+ init_scoring();
165913
166455
  mapError = (error2) => {
165914
- if (error2 instanceof EvaluationError) {
166456
+ if (error2 instanceof EvaluationError || error2 instanceof ScoringConfigError) {
165915
166457
  throw new ApiError(error2.statusCode, error2.code, error2.message);
165916
166458
  }
165917
166459
  throw error2;
165918
166460
  };
166461
+ optionalActorId = (value2) => typeof value2 === "string" && value2.trim() ? value2.trim() : null;
165919
166462
  }
165920
166463
  });
165921
166464
 
@@ -173614,27 +174157,12 @@ function evidenceForJudge(snapshot) {
173614
174157
  };
173615
174158
  }
173616
174159
  function judgePrompt(input) {
173617
- return [
173618
- "\u4F60\u662F Oasis Benchmark \u7684\u8BC4\u5206\u5458\u5DE5\u3002\u672C\u6B21\u4EFB\u52A1\u53EA\u505A\u8BC4\u6D4B\uFF0C\u4E0D\u4FEE\u6539\u88AB\u6D4B\u5DE5\u5355\u3002",
173619
- `evaluation_id: ${input.evaluationId}`,
173620
- "",
173621
- "\u5FC5\u987B\u5206\u522B\u8F93\u51FA\u56DB\u7EC4\u7ED3\u679C\uFF0C\u7981\u6B62\u751F\u6210\u603B\u4F53\u603B\u5206\uFF1A",
173622
- "1. common.dimensions\uFF1AG1-G7 \u4E03\u9879\uFF0C1-5 \u5206\uFF1B\u53EA\u6709 G6 \u53EF\u5728\u786E\u5B9E\u4E0D\u9002\u7528\u65F6\u4E3A null\u3002",
173623
- "2. specialty.dimensions\uFF1A\u4E25\u683C\u4E94\u9879\u3001\u6BCF\u9879 1-5 \u5206\uFF1Bscore \u4E3A\u4E94\u9879\u5E73\u5747\uFF0Cscore100=score*20\u3002",
173624
- " S \u4E13\u9879\u53EA\u80FD\u4F9D\u636E artifacts \u4E2D\u53EF\u8BFB\u7684\u4E13\u4E1A\u4EA7\u7269\u6B63\u6587\u5224\u65AD\u3002Trace\u3001\u8282\u70B9\u6458\u8981\u548C Brief \u4E0D\u80FD\u66FF\u4EE3\u4E13\u4E1A\u4EA7\u7269\u3002",
173625
- " \u6CA1\u6709\u53EF\u8BFB\u4E13\u4E1A\u4EA7\u7269\u65F6\uFF0C\u4E94\u9879 score\u3001specialty.score \u548C specialty.score100 \u5FC5\u987B\u5168\u90E8\u4E3A null\u3002",
173626
- "3. caseSpecial\uFF1A\u53EA\u4F9D\u636E\u6700\u7EC8\u4EA7\u7269\u53CA evaluator \u7ED3\u679C\u3002",
173627
- " evaluator.type=native \u7684\u9879\u76EE\u53EA\u80FD\u8BFB\u53D6\u771F\u5B9E native evaluator \u8F93\u51FA\uFF1B\u5F53\u524D\u8BC1\u636E\u6CA1\u6709\u8BE5\u8F93\u51FA\u65F6\u5FC5\u987B\u8FD4\u56DE evaluator_failed\uFF0C\u7981\u6B62\u7531 LLM \u4EE3\u6253\u5B98\u65B9\u5206\u6570\u3002",
173628
- "4. runtimeMetrics\uFF1A\u539F\u6837\u4FDD\u7559\u8BC1\u636E\u4E2D\u7684\u8FD0\u884C\u6307\u6807\uFF0C\u4E0D\u8FDB\u5165\u8D28\u91CF\u5206\u3002",
173629
- "",
173630
- "\u53EA\u8FD4\u56DE\u4E00\u4E2A JSON \u5BF9\u8C61\uFF0C\u4E0D\u8981\u8FD4\u56DE Markdown \u89E3\u91CA\u3002",
173631
- "",
173632
- "CASE:",
173633
- JSON.stringify(input.evaluationCase),
173634
- "",
173635
- "EVIDENCE SNAPSHOT:",
173636
- JSON.stringify(evidenceForJudge(input.evidenceSnapshot))
173637
- ].join("\n");
174160
+ return buildJudgePrompt({
174161
+ evaluationId: input.evaluationId,
174162
+ evaluationCase: input.evaluationCase,
174163
+ rubrics: input.rubrics,
174164
+ evidenceJson: JSON.stringify(evidenceForJudge(input.evidenceSnapshot))
174165
+ });
173638
174166
  }
173639
174167
  function record7(value2) {
173640
174168
  return value2 && typeof value2 === "object" && !Array.isArray(value2) ? value2 : null;
@@ -173673,19 +174201,20 @@ function normalizeDimensions(value2, expectedIds) {
173673
174201
  if (!dimensions) return value2;
173674
174202
  return Object.entries(dimensions).map(([id, raw]) => normalizeDimensionItem(raw, id, expectedIds));
173675
174203
  }
173676
- function normalizeJudgeOutput(value2, evaluationCase) {
174204
+ function normalizeJudgeOutput(value2, evaluationCase, rubrics) {
173677
174205
  const source = record7(value2);
173678
174206
  if (!source) return value2;
173679
174207
  const result = structuredClone(source);
173680
- const common = record7(result["common"]);
173681
- if (common) {
173682
- common["dimensions"] = normalizeDimensions(
173683
- common["dimensions"],
173684
- ["G1", "G2", "G3", "G4", "G5", "G6", "G7"]
174208
+ for (const rubric of rubrics) {
174209
+ const spec = rubric.outputSpec;
174210
+ if (!spec.dimensions.length) continue;
174211
+ const section = record7(result[spec.sectionKey]);
174212
+ if (!section) continue;
174213
+ section["dimensions"] = normalizeDimensions(
174214
+ section["dimensions"],
174215
+ spec.dimensions.map((dimension) => dimension.id)
173685
174216
  );
173686
174217
  }
173687
- const specialty = record7(result["specialty"]);
173688
- if (specialty) specialty["dimensions"] = normalizeDimensions(specialty["dimensions"]);
173689
174218
  const caseSpecial = record7(result["caseSpecial"]);
173690
174219
  if (caseSpecial && Array.isArray(caseSpecial["items"])) {
173691
174220
  const definitions = Array.isArray(evaluationCase.caseSpecial["items"]) ? evaluationCase.caseSpecial["items"] : [];
@@ -173711,6 +174240,30 @@ function normalizeJudgeOutput(value2, evaluationCase) {
173711
174240
  }
173712
174241
  return result;
173713
174242
  }
174243
+ function fillMissingItemSections(value2, evaluationCase, rubrics) {
174244
+ const result = record7(value2);
174245
+ if (!result) return value2;
174246
+ const filled = structuredClone(result);
174247
+ const definitions = caseSpecialItemDefinitions(evaluationCase);
174248
+ for (const rubric of rubrics) {
174249
+ const spec = rubric.outputSpec;
174250
+ if (spec.dimensions.length) continue;
174251
+ const section = record7(filled[spec.sectionKey]);
174252
+ if (section && Array.isArray(section["items"])) continue;
174253
+ filled[spec.sectionKey] = {
174254
+ score100: null,
174255
+ items: definitions.map((definition) => ({
174256
+ id: definition.id,
174257
+ label: definition.label,
174258
+ score: null,
174259
+ maxScore: definition.maxScore,
174260
+ status: "evaluator_failed",
174261
+ reasoning: `\u8BC4\u5206\u5458\u5DE5\u672A\u8FD4\u56DE ${spec.sectionKey} \u6BB5\uFF0C\u672C\u9879\u6309\u672A\u8BC4\u5206\u8BB0\u5F55\uFF08\u6807\u51C6\uFF1A${rubric.name}\uFF09\u3002`
174262
+ }))
174263
+ };
174264
+ }
174265
+ return filled;
174266
+ }
173714
174267
  function enforceEvaluatorBoundaries(value2, evaluationCase) {
173715
174268
  if (!value2 || typeof value2 !== "object") return value2;
173716
174269
  const result = structuredClone(value2);
@@ -173776,17 +174329,22 @@ var init_judge = __esm({
173776
174329
  "../server/src/domains/evaluation/judge.ts"() {
173777
174330
  "use strict";
173778
174331
  init_src();
174332
+ init_judge_prompt();
173779
174333
  TRACE_STRING_LIMIT = 200;
173780
174334
  TRACE_ARRAY_LIMIT = 20;
173781
174335
  ChatEvaluationJudge = class {
173782
174336
  constructor(options) {
173783
174337
  this.options = options;
174338
+ this.attempts = Math.max(1, options.attempts ?? 2);
173784
174339
  }
174340
+ attempts;
173785
174341
  async evaluate(input) {
173786
- const message = judgePrompt(input);
173787
- for (let attempt = 0; attempt < 2; attempt += 1) {
174342
+ if (!input.judgeActorId) throw new Error("\u672A\u6307\u5B9A\u5224\u5206\u5458\u5DE5");
174343
+ const rubrics = input.rubrics?.length ? input.rubrics : builtinRubricsForCase(input.evaluationCase);
174344
+ const message = judgePrompt({ ...input, rubrics });
174345
+ for (let attempt = 0; attempt < this.attempts; attempt += 1) {
173788
174346
  const session = await this.options.dispatchChat({
173789
- actorId: this.options.actorId,
174347
+ actorId: input.judgeActorId,
173790
174348
  message,
173791
174349
  ...input.companyId ? { companyId: input.companyId } : {}
173792
174350
  });
@@ -173797,7 +174355,7 @@ var init_judge = __esm({
173797
174355
  try {
173798
174356
  await session.done;
173799
174357
  } catch (error2) {
173800
- if (attempt === 0 && isRetryableRuntimeExit(error2, output)) continue;
174358
+ if (attempt + 1 < this.attempts && isRetryableRuntimeExit(error2, output)) continue;
173801
174359
  if (error2 instanceof Error && session.runId) {
173802
174360
  Object.assign(error2, { judgeRunId: session.runId });
173803
174361
  }
@@ -173806,13 +174364,20 @@ var init_judge = __esm({
173806
174364
  return {
173807
174365
  judgeRunId: session.runId ?? null,
173808
174366
  judgeVersion: this.options.judgeVersion,
173809
- result: validateEvaluationResult(enforceEvaluatorBoundaries(
173810
- enforceSpecialtyArtifactBoundary(
173811
- normalizeJudgeOutput(extractJson2(output), input.evaluationCase),
173812
- input.evidenceSnapshot
174367
+ result: validateEvaluationResult(
174368
+ enforceEvaluatorBoundaries(
174369
+ enforceSpecialtyArtifactBoundary(
174370
+ fillMissingItemSections(
174371
+ normalizeJudgeOutput(extractJson2(output), input.evaluationCase, rubrics),
174372
+ input.evaluationCase,
174373
+ rubrics
174374
+ ),
174375
+ input.evidenceSnapshot
174376
+ ),
174377
+ input.evaluationCase
173813
174378
  ),
173814
- input.evaluationCase
173815
- ))
174379
+ rubrics.map((rubric) => rubric.outputSpec)
174380
+ )
173816
174381
  };
173817
174382
  }
173818
174383
  throw new Error("\u8BC4\u5206\u5458\u5DE5\u91CD\u8BD5\u6D41\u7A0B\u5F02\u5E38\u7ED3\u675F");
@@ -173880,6 +174445,8 @@ var init_evaluation3 = __esm({
173880
174445
  init_evidence();
173881
174446
  init_filesystem_catalog();
173882
174447
  init_judge();
174448
+ init_judge_prompt();
174449
+ init_scoring();
173883
174450
  init_project_binding();
173884
174451
  init_runtime_metrics();
173885
174452
  init_routes8();
@@ -174479,7 +175046,7 @@ function playbooksDomain(opts) {
174479
175046
  opts.overrides.set(companyOf(req), ref2, nodeKey, nextOverride);
174480
175047
  try {
174481
175048
  await opts.audit?.({
174482
- id: `reg_${(0, import_node_crypto30.randomUUID)()}`,
175049
+ id: `reg_${(0, import_node_crypto31.randomUUID)()}`,
174483
175050
  actor: req.auth.actor,
174484
175051
  kind: "registry_change",
174485
175052
  target: `playbook:${ref2}#${nodeKey}`,
@@ -174496,11 +175063,11 @@ function playbooksDomain(opts) {
174496
175063
  });
174497
175064
  };
174498
175065
  }
174499
- var import_node_crypto30;
175066
+ var import_node_crypto31;
174500
175067
  var init_routes9 = __esm({
174501
175068
  "../server/src/domains/playbooks/routes.ts"() {
174502
175069
  "use strict";
174503
- import_node_crypto30 = require("node:crypto");
175070
+ import_node_crypto31 = require("node:crypto");
174504
175071
  init_router();
174505
175072
  init_registry3();
174506
175073
  init_planner();
@@ -174633,11 +175200,11 @@ function remoteAppendInput(hub, nodeId, dispatchId, entry, input, timeoutMs) {
174633
175200
  entry.appendWaiters.push({ resolve: resolve9, timer });
174634
175201
  });
174635
175202
  }
174636
- var import_node_crypto31, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
175203
+ var import_node_crypto32, STASH_TTL_MS, STASH_MAX_FRAMES_PER_ID, STASH_MAX_IDS, DaemonHubAdapter, BindingRouterAdapter, WorkdirBridge;
174637
175204
  var init_daemon_adapter = __esm({
174638
175205
  "../server/src/daemon-adapter.ts"() {
174639
175206
  "use strict";
174640
- import_node_crypto31 = require("node:crypto");
175207
+ import_node_crypto32 = require("node:crypto");
174641
175208
  STASH_TTL_MS = 5 * 6e4;
174642
175209
  STASH_MAX_FRAMES_PER_ID = 500;
174643
175210
  STASH_MAX_IDS = 50;
@@ -174723,6 +175290,21 @@ var init_daemon_adapter = __esm({
174723
175290
  }
174724
175291
  return n;
174725
175292
  }
175293
+ /**
175294
+ * 当前在途会话的**按员工分布**:`activeRunCount` 的同源摊开(同一张 pending 表、同一组过滤条件),
175295
+ * 故 `sum(count) === activeRunCount(nodeId, runtimeKind)` 恒成立。
175296
+ * 重挂路没带 actor 的会话归到 `actorId: ""`——不丢计数、也不猜身份。
175297
+ */
175298
+ activeRunsByActor(nodeId, runtimeKind) {
175299
+ const byActor = /* @__PURE__ */ new Map();
175300
+ for (const e of this.pending.values()) {
175301
+ if (e.nodeId !== nodeId || e.exited) continue;
175302
+ if (runtimeKind !== void 0 && e.runtimeKind !== runtimeKind) continue;
175303
+ const key = e.actorId ?? "";
175304
+ byActor.set(key, (byActor.get(key) ?? 0) + 1);
175305
+ }
175306
+ return byActor;
175307
+ }
174726
175308
  /** 收到任何回帧(started/event/output/exited)即视为派发已达,取消 ack 超时。 */
174727
175309
  cancelAck(dispatchId) {
174728
175310
  const entry = this.pending.get(dispatchId);
@@ -174793,10 +175375,11 @@ var init_daemon_adapter = __esm({
174793
175375
  async spawn(job) {
174794
175376
  const nodeId = job.binding?.nodeId;
174795
175377
  if (!nodeId) throw new Error("DaemonHubAdapter \u9700\u8981 job.binding.nodeId\uFF08\u8DEF\u7531\u9519\u8BEF\uFF09");
174796
- const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto31.randomUUID)()}`;
175378
+ const dispatchId = job.dispatchId ?? `dispatch:${(0, import_node_crypto32.randomUUID)()}`;
174797
175379
  const entry = {
174798
175380
  nodeId,
174799
175381
  ...job.binding?.runtimeKind ? { runtimeKind: job.binding.runtimeKind } : {},
175382
+ ...job.actor ? { actorId: job.actor } : {},
174800
175383
  exitCbs: [],
174801
175384
  telemetryCbs: [],
174802
175385
  outputCbs: [],
@@ -174840,13 +175423,14 @@ var init_daemon_adapter = __esm({
174840
175423
  appendInput: (input) => remoteAppendInput(hub, nodeId, dispatchId, entry, input, appendTimeoutMs)
174841
175424
  };
174842
175425
  }
174843
- recover(dispatchId, nodeId, runtimeKind) {
175426
+ recover(dispatchId, nodeId, runtimeKind, actorId) {
174844
175427
  const stashed = this.drainStash(dispatchId);
174845
175428
  let entry = this.pending.get(dispatchId);
174846
175429
  if (!entry) {
174847
175430
  entry = {
174848
175431
  nodeId,
174849
175432
  ...runtimeKind ? { runtimeKind } : {},
175433
+ ...actorId ? { actorId } : {},
174850
175434
  exitCbs: [],
174851
175435
  telemetryCbs: [],
174852
175436
  outputCbs: [],
@@ -174954,7 +175538,7 @@ var init_daemon_adapter = __esm({
174954
175538
  }));
174955
175539
  }
174956
175540
  request(nodeId, buildFrame) {
174957
- const requestId = (0, import_node_crypto31.randomUUID)();
175541
+ const requestId = (0, import_node_crypto32.randomUUID)();
174958
175542
  const sent = this.hub.dispatch(nodeId, buildFrame(requestId));
174959
175543
  if (!sent) return Promise.resolve({ ok: false, code: "NODE_OFFLINE" });
174960
175544
  return new Promise((resolve9) => {
@@ -175037,13 +175621,13 @@ function classifyPage(page, lastPushedHash, serviceAccount) {
175037
175621
  if (sha(body) === lastPushedHash) return { kind: "echo" };
175038
175622
  return { kind: "human-edit", content: body, updatedBy: page.updatedBy };
175039
175623
  }
175040
- var import_node_crypto32, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
175624
+ var import_node_crypto33, sha, enc3, dec, MirrorEngine, MapMirrorIdentities;
175041
175625
  var init_engine = __esm({
175042
175626
  "../server/src/mirror/engine.ts"() {
175043
175627
  "use strict";
175044
- import_node_crypto32 = require("node:crypto");
175628
+ import_node_crypto33 = require("node:crypto");
175045
175629
  init_src();
175046
- sha = (s2) => (0, import_node_crypto32.createHash)("sha256").update(s2, "utf8").digest("hex");
175630
+ sha = (s2) => (0, import_node_crypto33.createHash)("sha256").update(s2, "utf8").digest("hex");
175047
175631
  enc3 = (s2) => new TextEncoder().encode(s2);
175048
175632
  dec = (b2) => new TextDecoder().decode(b2);
175049
175633
  MirrorEngine = class {
@@ -175795,11 +176379,11 @@ function humanExitCause(exit) {
175795
176379
  const base = (exit.reason ? label[exit.reason] : void 0) ?? `\u4F1A\u8BDD\u5F02\u5E38\u7ED3\u675F\uFF08${exit.reason ?? "\u65E0\u9000\u51FA\u4FE1\u606F"}\uFF09`;
175796
176380
  return exit.errorMessage ? `${base}\uFF1A${exit.errorMessage.slice(0, 200)}` : base;
175797
176381
  }
175798
- var import_node_crypto33, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
176382
+ var import_node_crypto34, AUTONOMOUS_ETHOS, CONVERSATIONAL_ETHOS, SHARED_GRAPH_BODY, AUTONOMOUS_RECOVERY_TOOLS, HIGH_RISK_COMMANDS, COORDINATOR_SYSTEM_PROMPT, CONVERSATIONAL_RECOVERY_TOOLS, CONVERSATIONAL_MANAGER_BODY, MACHINE_EXIT_CODES, CoordinatorWorker;
175799
176383
  var init_worker = __esm({
175800
176384
  "../server/src/coordinator/worker.ts"() {
175801
176385
  "use strict";
175802
- import_node_crypto33 = require("node:crypto");
176386
+ import_node_crypto34 = require("node:crypto");
175803
176387
  init_src2();
175804
176388
  init_identity();
175805
176389
  AUTONOMOUS_ETHOS = `\u4F60\u662F\u8FD9\u4E2A\u5DE5\u5355\u7684**\u7BA1\u7406\u8005**\u2014\u2014\u804C\u8D23\u662F\u8BA9\u5B83\u987A\u7545\u8DD1\u5B8C\u3002\u7CFB\u7EDF\u5728\u67D0\u4E2A\u8282\u70B9\u5361\u4F4F\u3001\u673A\u68B0\u5206\u8BCA\u786E\u8BA4"\u9700\u8981\u4F60"\u65F6\u5524\u8D77\u4F60\uFF08\u65E0\u4EBA\u5728\u573A\uFF0C\u4F60\u8FD9\u4E00\u8F6E\u628A\u80FD\u505A\u7684\u505A\u6389\uFF09\u3002\u4F60\u7684\u624B\u6BB5\u5F88\u5BBD\uFF1A
@@ -176038,7 +176622,7 @@ ${HIGH_RISK_COMMANDS}`;
176038
176622
  return this.deps.kernel.model.lastSeq.get(artifactId) ?? 0;
176039
176623
  }
176040
176624
  evaluationKey(kind, artifactId, evidence) {
176041
- const fingerprint = (0, import_node_crypto33.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
176625
+ const fingerprint = (0, import_node_crypto34.createHash)("sha256").update(JSON.stringify(evidence)).digest("hex");
176042
176626
  return `${kind}:${artifactId}:${fingerprint}`;
176043
176627
  }
176044
176628
  artifactEvidence(id) {
@@ -176403,7 +176987,7 @@ ${ctx.nodeFault}
176403
176987
  const token = this.deps.tokenFor(actorId, ctx);
176404
176988
  const serverUrl = this.deps.serverUrlFor ? await this.deps.serverUrlFor(ctx) : this.deps.serverUrl;
176405
176989
  const workspace = this.deps.kernel.model.artifacts.get(artifactId)?.workspace;
176406
- const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto33.randomUUID)();
176990
+ const runtimeSessionId = opts?.resumeSessionId ?? (0, import_node_crypto34.randomUUID)();
176407
176991
  const job = {
176408
176992
  actor: actorId,
176409
176993
  actorToken: token,
@@ -181812,11 +182396,11 @@ var init_esm2 = __esm({
181812
182396
  });
181813
182397
 
181814
182398
  // ../storage/src/postgres.ts
181815
- var import_node_crypto34, ident3, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
182399
+ var import_node_crypto35, ident3, isUniqueViolation, PostgresOplogStore, PostgresBlobStore;
181816
182400
  var init_postgres = __esm({
181817
182401
  "../storage/src/postgres.ts"() {
181818
182402
  "use strict";
181819
- import_node_crypto34 = require("node:crypto");
182403
+ import_node_crypto35 = require("node:crypto");
181820
182404
  init_esm2();
181821
182405
  init_src();
181822
182406
  ident3 = (s2) => {
@@ -181969,7 +182553,7 @@ var init_postgres = __esm({
181969
182553
  return new _PostgresBlobStore(pool, schema);
181970
182554
  }
181971
182555
  async put(bytes) {
181972
- const hash = (0, import_node_crypto34.createHash)("sha256").update(bytes).digest("hex");
182556
+ const hash = (0, import_node_crypto35.createHash)("sha256").update(bytes).digest("hex");
181973
182557
  await this.pool.query(
181974
182558
  `INSERT INTO ${this.t} (hash, bytes, size, content_type) VALUES ($1, $2, $3, $4) ON CONFLICT (hash) DO NOTHING`,
181975
182559
  [hash, Buffer.from(bytes), bytes.byteLength, sniffContentType(bytes) ?? null]
@@ -185849,11 +186433,11 @@ var init_postgres_chat_sessions = __esm({
185849
186433
  });
185850
186434
 
185851
186435
  // ../storage/src/postgres-nodes.ts
185852
- var import_node_crypto35, ident12, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
186436
+ var import_node_crypto36, ident12, PostgresNodeStore, PostgresNodeTokenStore, rowToNode, rowToRuntime;
185853
186437
  var init_postgres_nodes = __esm({
185854
186438
  "../storage/src/postgres-nodes.ts"() {
185855
186439
  "use strict";
185856
- import_node_crypto35 = require("node:crypto");
186440
+ import_node_crypto36 = require("node:crypto");
185857
186441
  init_esm2();
185858
186442
  ident12 = (s2) => {
185859
186443
  if (!/^[a-z_][a-z0-9_]*$/.test(s2)) throw new Error(`invalid schema name: ${s2}`);
@@ -185992,7 +186576,7 @@ var init_postgres_nodes = __esm({
185992
186576
  return store;
185993
186577
  }
185994
186578
  issue(nodeId) {
185995
- const token = `ont_${(0, import_node_crypto35.randomBytes)(24).toString("base64url")}`;
186579
+ const token = `ont_${(0, import_node_crypto36.randomBytes)(24).toString("base64url")}`;
185996
186580
  this.cache.set(token, nodeId);
185997
186581
  void this.pool.query(`INSERT INTO ${this.s}.node_tokens (token,node_id) VALUES ($1,$2)`, [token, nodeId]);
185998
186582
  return token;
@@ -186203,11 +186787,11 @@ var init_postgres_type_registry = __esm({
186203
186787
  });
186204
186788
 
186205
186789
  // ../storage/src/postgres-actor-memory.ts
186206
- var import_node_crypto36, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
186790
+ var import_node_crypto37, matchClause, ident15, PostgresActorMemoryStore, rowToIndexEntry, rowToRecord;
186207
186791
  var init_postgres_actor_memory = __esm({
186208
186792
  "../storage/src/postgres-actor-memory.ts"() {
186209
186793
  "use strict";
186210
- import_node_crypto36 = require("node:crypto");
186794
+ import_node_crypto37 = require("node:crypto");
186211
186795
  init_src();
186212
186796
  matchClause = (q) => q.requireMatch && q.keywords.length > 0 ? " WHERE m > 0" : "";
186213
186797
  ident15 = (s2) => {
@@ -186412,7 +186996,7 @@ var init_postgres_actor_memory = __esm({
186412
186996
  }
186413
186997
  async write(input, now) {
186414
186998
  if (input.memId === void 0) {
186415
- const memId = `mem:${(0, import_node_crypto36.randomUUID)()}`;
186999
+ const memId = `mem:${(0, import_node_crypto37.randomUUID)()}`;
186416
187000
  const r2 = await this.pool.query(
186417
187001
  `INSERT INTO ${this.s}.actor_memories
186418
187002
  (mem_id, actor_id, project_id, keywords, content, version, created_at, updated_at, accessed_at, source_artifact_id, source_session_id)
@@ -186605,6 +187189,20 @@ function benchmarkSchemaSql(schema) {
186605
187189
  ON ${s2}.benchmark_runs (case_id, attempt_no DESC);
186606
187190
  CREATE INDEX IF NOT EXISTS benchmark_evaluations_run_idx
186607
187191
  ON ${s2}.benchmark_evaluations (run_id, evaluation_no DESC);
187192
+ CREATE TABLE IF NOT EXISTS ${s2}.benchmark_rubrics (
187193
+ rubric_id text PRIMARY KEY, company_id text NOT NULL, name text NOT NULL, kind text NOT NULL,
187194
+ description text, prompt_section text NOT NULL, output_spec jsonb NOT NULL,
187195
+ version integer NOT NULL, status text NOT NULL,
187196
+ created_by text NOT NULL, created_at timestamptz NOT NULL,
187197
+ updated_by text NOT NULL, updated_at timestamptz NOT NULL
187198
+ );
187199
+ CREATE TABLE IF NOT EXISTS ${s2}.benchmark_case_scoring (
187200
+ company_id text NOT NULL, case_id text NOT NULL, rubric_ids jsonb NOT NULL,
187201
+ judge_actor_id text, updated_by text NOT NULL, updated_at timestamptz NOT NULL,
187202
+ PRIMARY KEY (company_id, case_id)
187203
+ );
187204
+ CREATE INDEX IF NOT EXISTS benchmark_rubrics_company_idx
187205
+ ON ${s2}.benchmark_rubrics (company_id, name);
186608
187206
  `;
186609
187207
  }
186610
187208
  function benchmarkAttemptLockKey(companyId, caseId) {
@@ -186648,10 +187246,38 @@ function toEvaluation(row) {
186648
187246
  completedAt: nullableIso(row.completed_at)
186649
187247
  };
186650
187248
  }
186651
- var ident17, iso2, nullableIso, nullableText, PostgresEvaluationStore;
187249
+ function toRubric(row) {
187250
+ return {
187251
+ rubricId: String(row.rubric_id),
187252
+ companyId: String(row.company_id),
187253
+ name: String(row.name),
187254
+ kind: String(row.kind),
187255
+ ...row.description == null ? {} : { description: String(row.description) },
187256
+ promptSection: String(row.prompt_section),
187257
+ outputSpec: structuredClone(row.output_spec),
187258
+ version: Number(row.version),
187259
+ status: String(row.status),
187260
+ createdBy: String(row.created_by),
187261
+ createdAt: iso2(row.created_at),
187262
+ updatedBy: String(row.updated_by),
187263
+ updatedAt: iso2(row.updated_at)
187264
+ };
187265
+ }
187266
+ function toBinding(row) {
187267
+ return {
187268
+ companyId: String(row.company_id),
187269
+ caseId: String(row.case_id),
187270
+ rubricIds: Array.isArray(row.rubric_ids) ? row.rubric_ids.map(String) : [],
187271
+ judgeActorId: nullableText(row.judge_actor_id),
187272
+ updatedBy: String(row.updated_by),
187273
+ updatedAt: iso2(row.updated_at)
187274
+ };
187275
+ }
187276
+ var import_node_crypto38, ident17, iso2, nullableIso, nullableText, PostgresEvaluationStore, PostgresEvaluationRubricStore;
186652
187277
  var init_postgres_evaluation = __esm({
186653
187278
  "../storage/src/postgres-evaluation.ts"() {
186654
187279
  "use strict";
187280
+ import_node_crypto38 = require("node:crypto");
186655
187281
  init_esm2();
186656
187282
  ident17 = (value2) => {
186657
187283
  if (!/^[a-z_][a-z0-9_]*$/.test(value2)) throw new Error(`invalid schema name: ${value2}`);
@@ -186838,6 +187464,147 @@ var init_postgres_evaluation = __esm({
186838
187464
  if (result.rowCount !== 1) throw new Error(`Evaluation ${evaluation.evaluationId} \u4E0D\u5B58\u5728`);
186839
187465
  }
186840
187466
  };
187467
+ PostgresEvaluationRubricStore = class _PostgresEvaluationRubricStore {
187468
+ constructor(pool, schema) {
187469
+ this.pool = pool;
187470
+ this.s = `"${ident17(schema)}"`;
187471
+ }
187472
+ s;
187473
+ static async open(pool, schema = "public") {
187474
+ const safe = ident17(schema);
187475
+ await pool.query(`CREATE SCHEMA IF NOT EXISTS "${safe}"`);
187476
+ await pool.query(benchmarkSchemaSql(safe));
187477
+ return new _PostgresEvaluationRubricStore(pool, safe);
187478
+ }
187479
+ async listRubrics(companyId) {
187480
+ const result = await this.pool.query(
187481
+ `SELECT * FROM ${this.s}.benchmark_rubrics WHERE company_id=$1 ORDER BY name ASC`,
187482
+ [companyId]
187483
+ );
187484
+ return result.rows.map((row) => toRubric(row));
187485
+ }
187486
+ async getRubric(rubricId) {
187487
+ const result = await this.pool.query(
187488
+ `SELECT * FROM ${this.s}.benchmark_rubrics WHERE rubric_id=$1`,
187489
+ [rubricId]
187490
+ );
187491
+ return result.rows[0] ? toRubric(result.rows[0]) : null;
187492
+ }
187493
+ async upsertRubric(input, at) {
187494
+ const client = await this.pool.connect();
187495
+ try {
187496
+ await client.query("BEGIN");
187497
+ const existing = input.rubricId ? (await client.query(
187498
+ `SELECT * FROM ${this.s}.benchmark_rubrics WHERE rubric_id=$1 FOR UPDATE`,
187499
+ [input.rubricId]
187500
+ )).rows[0] : void 0;
187501
+ if (existing && String(existing.company_id) !== input.companyId) {
187502
+ throw new Error(`\u8BC4\u5206\u6807\u51C6 ${input.rubricId} \u4E0D\u5C5E\u4E8E\u5F53\u524D\u516C\u53F8`);
187503
+ }
187504
+ const rubricId = existing ? String(existing.rubric_id) : input.rubricId ?? (0, import_node_crypto38.randomUUID)();
187505
+ const version2 = existing ? Number(existing.version) + 1 : 1;
187506
+ const status = input.status ?? (existing ? String(existing.status) : "active");
187507
+ const createdBy = existing ? String(existing.created_by) : input.actor;
187508
+ const createdAt = existing ? iso2(existing.created_at) : at;
187509
+ await client.query(
187510
+ `INSERT INTO ${this.s}.benchmark_rubrics
187511
+ (rubric_id,company_id,name,kind,description,prompt_section,output_spec,version,status,
187512
+ created_by,created_at,updated_by,updated_at)
187513
+ VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9,$10,$11,$12,$13)
187514
+ ON CONFLICT (rubric_id) DO UPDATE SET name=EXCLUDED.name,kind=EXCLUDED.kind,
187515
+ description=EXCLUDED.description,prompt_section=EXCLUDED.prompt_section,
187516
+ output_spec=EXCLUDED.output_spec,version=EXCLUDED.version,status=EXCLUDED.status,
187517
+ updated_by=EXCLUDED.updated_by,updated_at=EXCLUDED.updated_at`,
187518
+ [
187519
+ rubricId,
187520
+ input.companyId,
187521
+ input.name,
187522
+ input.kind,
187523
+ input.description ?? null,
187524
+ input.promptSection,
187525
+ JSON.stringify(input.outputSpec),
187526
+ version2,
187527
+ status,
187528
+ createdBy,
187529
+ createdAt,
187530
+ input.actor,
187531
+ at
187532
+ ]
187533
+ );
187534
+ await client.query("COMMIT");
187535
+ const saved = await this.getRubric(rubricId);
187536
+ if (!saved) throw new Error(`\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4FDD\u5B58\u540E\u8BFB\u4E0D\u56DE`);
187537
+ return saved;
187538
+ } catch (error2) {
187539
+ await client.query("ROLLBACK").catch(() => {
187540
+ });
187541
+ throw error2;
187542
+ } finally {
187543
+ client.release();
187544
+ }
187545
+ }
187546
+ async deleteRubric(rubricId, companyId) {
187547
+ const client = await this.pool.connect();
187548
+ try {
187549
+ await client.query("BEGIN");
187550
+ await client.query(
187551
+ `DELETE FROM ${this.s}.benchmark_rubrics WHERE rubric_id=$1 AND company_id=$2`,
187552
+ [rubricId, companyId]
187553
+ );
187554
+ await client.query(
187555
+ `UPDATE ${this.s}.benchmark_case_scoring
187556
+ SET rubric_ids = COALESCE((
187557
+ SELECT jsonb_agg(value) FROM jsonb_array_elements_text(rubric_ids) AS value
187558
+ WHERE value <> $2
187559
+ ), '[]'::jsonb)
187560
+ WHERE company_id=$1 AND rubric_ids @> to_jsonb($2::text)`,
187561
+ [companyId, rubricId]
187562
+ );
187563
+ await client.query("COMMIT");
187564
+ } catch (error2) {
187565
+ await client.query("ROLLBACK").catch(() => {
187566
+ });
187567
+ throw error2;
187568
+ } finally {
187569
+ client.release();
187570
+ }
187571
+ }
187572
+ async listBindings(companyId) {
187573
+ const result = await this.pool.query(
187574
+ `SELECT * FROM ${this.s}.benchmark_case_scoring WHERE company_id=$1 ORDER BY case_id ASC`,
187575
+ [companyId]
187576
+ );
187577
+ return result.rows.map((row) => toBinding(row));
187578
+ }
187579
+ async getBinding(companyId, caseId) {
187580
+ const result = await this.pool.query(
187581
+ `SELECT * FROM ${this.s}.benchmark_case_scoring WHERE company_id=$1 AND case_id=$2`,
187582
+ [companyId, caseId]
187583
+ );
187584
+ return result.rows[0] ? toBinding(result.rows[0]) : null;
187585
+ }
187586
+ async putBinding(input, at) {
187587
+ await this.pool.query(
187588
+ `INSERT INTO ${this.s}.benchmark_case_scoring
187589
+ (company_id,case_id,rubric_ids,judge_actor_id,updated_by,updated_at)
187590
+ VALUES ($1,$2,$3::jsonb,$4,$5,$6)
187591
+ ON CONFLICT (company_id,case_id) DO UPDATE SET rubric_ids=EXCLUDED.rubric_ids,
187592
+ judge_actor_id=EXCLUDED.judge_actor_id,updated_by=EXCLUDED.updated_by,
187593
+ updated_at=EXCLUDED.updated_at`,
187594
+ [
187595
+ input.companyId,
187596
+ input.caseId,
187597
+ JSON.stringify(input.rubricIds),
187598
+ input.judgeActorId,
187599
+ input.actor,
187600
+ at
187601
+ ]
187602
+ );
187603
+ const saved = await this.getBinding(input.companyId, input.caseId);
187604
+ if (!saved) throw new Error(`Case ${input.caseId} \u88C5\u914D\u4FDD\u5B58\u540E\u8BFB\u4E0D\u56DE`);
187605
+ return saved;
187606
+ }
187607
+ };
186841
187608
  }
186842
187609
  });
186843
187610
 
@@ -186852,6 +187619,7 @@ __export(src_exports, {
186852
187619
  PostgresChannelStore: () => PostgresChannelStore,
186853
187620
  PostgresChatSessionStore: () => PostgresChatSessionStore,
186854
187621
  PostgresControlPlaneStore: () => PostgresControlPlaneStore,
187622
+ PostgresEvaluationRubricStore: () => PostgresEvaluationRubricStore,
186855
187623
  PostgresEvaluationStore: () => PostgresEvaluationStore,
186856
187624
  PostgresHumanPrefsStore: () => PostgresHumanPrefsStore,
186857
187625
  PostgresModelPriceStore: () => PostgresModelPriceStore,
@@ -187027,13 +187795,13 @@ var import_node_child_process17 = require("node:child_process");
187027
187795
  var fs33 = __toESM(require("node:fs"), 1);
187028
187796
  var os8 = __toESM(require("node:os"), 1);
187029
187797
  var path27 = __toESM(require("node:path"), 1);
187030
- var import_node_crypto40 = require("node:crypto");
187798
+ var import_node_crypto42 = require("node:crypto");
187031
187799
 
187032
187800
  // ../cli/src/serve.ts
187033
187801
  var fs29 = __toESM(require("node:fs"), 1);
187034
187802
  var os5 = __toESM(require("node:os"), 1);
187035
187803
  var path23 = __toESM(require("node:path"), 1);
187036
- var import_node_crypto37 = require("node:crypto");
187804
+ var import_node_crypto39 = require("node:crypto");
187037
187805
  var import_node_url5 = require("node:url");
187038
187806
  init_src2();
187039
187807
  init_src7();
@@ -187923,6 +188691,16 @@ async function startServe(opts) {
187923
188691
  let workdirBridge = null;
187924
188692
  const nodeHealth = new NodeHealthTracker();
187925
188693
  const activeRunCountOf = (nodeId, runtimeKind) => (chatRemoteAdapter?.activeRunCount(nodeId, runtimeKind) ?? 0) + (dispatchRemoteAdapter?.activeRunCount(nodeId, runtimeKind) ?? 0);
188694
+ const activeRunsOf = (nodeId, runtimeKind) => {
188695
+ const byActor = /* @__PURE__ */ new Map();
188696
+ for (const adapter of [chatRemoteAdapter, dispatchRemoteAdapter]) {
188697
+ if (!adapter) continue;
188698
+ for (const [actorId, count2] of adapter.activeRunsByActor(nodeId, runtimeKind)) {
188699
+ byActor.set(actorId, (byActor.get(actorId) ?? 0) + count2);
188700
+ }
188701
+ }
188702
+ return [...byActor].map(([actorId, count2]) => ({ actorId, count: count2 })).sort((a, b2) => b2.count - a.count || a.actorId.localeCompare(b2.actorId));
188703
+ };
187926
188704
  let localUrl = "";
187927
188705
  const chatLiveSessions = /* @__PURE__ */ new Map();
187928
188706
  const remoteApiUrl = opts.publicUrl ? normalizeHttpBaseUrl(opts.publicUrl) : apiUrlFromGatewayUrl(opts.gatewayUrl);
@@ -187980,6 +188758,7 @@ async function startServe(opts) {
187980
188758
  const structuralBaselines = /* @__PURE__ */ new Map();
187981
188759
  const deployTargets = DeployTargetStore.open(path23.join(opts.dir, "deploy-targets.json"));
187982
188760
  const evaluationStore = pgPool ? await PostgresEvaluationStore.open(pgPool, pgSchema) : new MemoryEvaluationStore();
188761
+ const evaluationRubricStore = pgPool ? await PostgresEvaluationRubricStore.open(pgPool, pgSchema) : new MemoryEvaluationRubricStore();
187983
188762
  const evaluationBenchRoot = process.env["OASIS_EVALUATION_BENCH_ROOT"]?.trim() ?? "";
187984
188763
  const evaluationCatalog = evaluationBenchRoot ? await FilesystemEvaluationCaseCatalog.open(evaluationBenchRoot) : new StaticEvaluationCaseCatalog([]);
187985
188764
  console.log(`[serve] evaluation benchmark catalog=${evaluationBenchRoot || "empty (OASIS_EVALUATION_BENCH_ROOT unset)"}`);
@@ -188029,19 +188808,34 @@ async function startServe(opts) {
188029
188808
  return collector.freeze(workOrderId);
188030
188809
  };
188031
188810
  const evaluationJudge = new ChatEvaluationJudge({
188032
- actorId: evaluationScoringActorId,
188033
188811
  judgeVersion: evaluationJudgeVersion,
188034
188812
  dispatchChat: async (request) => {
188035
- if (!evaluationScoringActorId) {
188036
- throw new Error("OASIS_EVALUATION_SCORING_ACTOR_ID \u672A\u914D\u7F6E\uFF0C\u65E0\u6CD5\u8C03\u7528\u8BC4\u5206\u5458\u5DE5");
188037
- }
188038
188813
  if (!evaluationDispatchChat) {
188039
188814
  throw new Error("\u8BC4\u5206\u5458\u5DE5\u6D3E\u53D1\u94FE\u8DEF\u5C1A\u672A\u521D\u59CB\u5316");
188040
188815
  }
188041
188816
  return evaluationDispatchChat(request);
188042
188817
  }
188043
188818
  });
188819
+ const listJudgeCandidates = async (companyId) => {
188820
+ const actorCtx = await actors.resolveCtx(companyId);
188821
+ const [agents, resolveBinding] = await Promise.all([
188822
+ actorCtx.service.listActors({ kind: "agent", status: "active" }),
188823
+ actorCtx.service.resolveBinding()
188824
+ ]);
188825
+ const candidates = await Promise.all(agents.map(async (agent) => {
188826
+ const binding = await resolveBinding(agent.id).catch(() => null);
188827
+ return binding ? { actorId: agent.id, name: agent.name } : null;
188828
+ }));
188829
+ return candidates.filter((candidate) => candidate !== null);
188830
+ };
188831
+ const evaluationScoring = new EvaluationScoringService({
188832
+ store: evaluationRubricStore,
188833
+ defaultJudgeActorId: evaluationScoringActorId,
188834
+ verifyJudgeActor: async (actorId, companyId) => (await listJudgeCandidates(companyId)).some((candidate) => candidate.actorId === actorId)
188835
+ });
188044
188836
  const evaluations = createEvaluationDomain({
188837
+ scoring: evaluationScoring,
188838
+ listJudgeCandidates,
188045
188839
  service: new EvaluationService({
188046
188840
  store: evaluationStore,
188047
188841
  catalog: evaluationCatalog,
@@ -188051,7 +188845,7 @@ async function startServe(opts) {
188051
188845
  },
188052
188846
  freezeEvidence: async (runId, companyId) => structuredClone(await collectEvaluationEvidence(runId, companyId)),
188053
188847
  judge: evaluationJudge,
188054
- judgeActorId: evaluationScoringActorId,
188848
+ scoring: evaluationScoring,
188055
188849
  judgeVersion: evaluationJudgeVersion,
188056
188850
  resolveBenchmarkProjects: (evaluationCase) => resolveEvaluationBenchmarkProjects(evaluationCase, projectStateStore)
188057
188851
  })
@@ -188117,7 +188911,7 @@ async function startServe(opts) {
188117
188911
  }));
188118
188912
  }
188119
188913
  const limits = { wallClockMs: SESSION_WALL_CLOCK_MS.planner };
188120
- const artifactId = `artifact:planner:${(0, import_node_crypto37.randomUUID)()}`;
188914
+ const artifactId = `artifact:planner:${(0, import_node_crypto39.randomUUID)()}`;
188121
188915
  const handle = await chatRemoteAdapter.spawn({
188122
188916
  actor: planner.id,
188123
188917
  actorToken: issueSessionToken(planner.id, { artifactId, action: "plan-workorder", limits, binding }),
@@ -188164,6 +188958,7 @@ async function startServe(opts) {
188164
188958
  repoRemote: opts.nodeRepoRemote ?? "git@github.com:open-friday/oasis-core.git",
188165
188959
  nodeHealth,
188166
188960
  activeRunCountOf,
188961
+ activeRunsOf,
188167
188962
  fetchLatestNpmDaemonVersion
188168
188963
  }),
188169
188964
  evaluations.register,
@@ -188308,10 +189103,10 @@ async function startServe(opts) {
188308
189103
  { nodeId: priorChatSession?.runtimeId, runtimeKind: priorChatSession?.runtimeKind },
188309
189104
  { nodeId: binding.nodeId, runtimeKind: binding.runtimeKind }
188310
189105
  ) : false;
188311
- const runtimeSessionId = sessionId ?? (0, import_node_crypto37.randomUUID)();
189106
+ const runtimeSessionId = sessionId ?? (0, import_node_crypto39.randomUUID)();
188312
189107
  const resumeRuntimeSession = Boolean(sessionId);
188313
- const traceRunId = `chat-run:${(0, import_node_crypto37.randomUUID)()}`;
188314
- const artifactId = `artifact:chat:${(0, import_node_crypto37.randomUUID)()}`;
189108
+ const traceRunId = `chat-run:${(0, import_node_crypto39.randomUUID)()}`;
189109
+ const artifactId = `artifact:chat:${(0, import_node_crypto39.randomUUID)()}`;
188315
189110
  const traceStartedAt = (/* @__PURE__ */ new Date()).toISOString();
188316
189111
  let traceSeq = 0;
188317
189112
  let lastProgressTouchMs = 0;
@@ -188645,7 +189440,7 @@ async function startServe(opts) {
188645
189440
  isWired: (artifactId) => chatLiveSessions.has(`chat::${artifactId}`)
188646
189441
  });
188647
189442
  for (const plan of plans) {
188648
- const handle = chatRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind);
189443
+ const handle = chatRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind, plan.actor);
188649
189444
  const jobKey = `chat::${plan.artifactId}`;
188650
189445
  wireRecoveredChatTurn({
188651
189446
  plan,
@@ -189078,7 +189873,7 @@ async function startServe(opts) {
189078
189873
  ensureDispatcherForEngine?.(companyId, engine2);
189079
189874
  const slot = dispatchers.get(companyId);
189080
189875
  if (!slot) continue;
189081
- const session = dispatchRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind);
189876
+ const session = dispatchRemoteAdapter.recover(plan.dispatchId, daemonId, plan.runtimeKind, plan.actor);
189082
189877
  const recoveredAt = (/* @__PURE__ */ new Date()).toISOString();
189083
189878
  const interruptedAt = previousServerHeartbeatAt ?? serverStartedAt;
189084
189879
  const restored = slot.dispatcher.recoverInFlightSession({
@@ -189708,7 +190503,7 @@ var SessionManager = class {
189708
190503
  // ../cli/src/daemon/ws-client.ts
189709
190504
  init_wrapper();
189710
190505
  var import_node_os7 = require("node:os");
189711
- var import_node_crypto38 = require("node:crypto");
190506
+ var import_node_crypto40 = require("node:crypto");
189712
190507
  init_src5();
189713
190508
 
189714
190509
  // ../cli/src/daemon/detect-adapters.ts
@@ -190264,7 +191059,7 @@ var DaemonWsClient = class {
190264
191059
  */
190265
191060
  async queryArtifactStates(artifactIds, timeoutMs = 15e3) {
190266
191061
  if (artifactIds.length === 0) return {};
190267
- const requestId = (0, import_node_crypto38.randomUUID)();
191062
+ const requestId = (0, import_node_crypto40.randomUUID)();
190268
191063
  return new Promise((resolve9, reject) => {
190269
191064
  const timer = setTimeout(() => {
190270
191065
  this.gcPending.delete(requestId);
@@ -190483,7 +191278,7 @@ async function startNode(opts) {
190483
191278
  // ../cli/src/daemon/machine-id.ts
190484
191279
  var import_node_child_process16 = require("node:child_process");
190485
191280
  var import_node_fs18 = require("node:fs");
190486
- var import_node_crypto39 = require("node:crypto");
191281
+ var import_node_crypto41 = require("node:crypto");
190487
191282
  var import_node_os10 = require("node:os");
190488
191283
  function linuxMachineId() {
190489
191284
  for (const p2 of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
@@ -190549,7 +191344,7 @@ var defaultSources = {
190549
191344
  function resolveNodeId(sources = {}) {
190550
191345
  const s2 = { ...defaultSources, ...sources };
190551
191346
  const material = `${s2.machineFingerprint()}:${s2.osUser()}`;
190552
- const digest = (0, import_node_crypto39.createHash)("sha256").update(material).digest("hex").slice(0, 12);
191347
+ const digest = (0, import_node_crypto41.createHash)("sha256").update(material).digest("hex").slice(0, 12);
190553
191348
  return `node-${digest}`;
190554
191349
  }
190555
191350
 
@@ -190720,6 +191515,24 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
190720
191515
  legacy-assistants list # \u5217\u5B58\u91CF\u53EF\u8BA4\u9886\u7684\u79C1\u4EBA agent\uFF08\u5019\u9009\u9762\uFF0C\u9644\u731C\u6D4B\u5F52\u5C5E\u4EBA\uFF0C\u4E0D\u9884\u586B\uFF09
190721
191516
  legacy-assistants claim <agentId> --human <humanId> [--keep-position] [--name <\u65B0\u540D>] # \u8BA4\u9886\u5E76\u6C38\u4E45\u9501\u5B9A\u7ED9\u8BE5\u771F\u4EBA
190722
191517
 
191518
+ \u6D4B\u8BC4\u4E0E\u8BC4\u5206\u88C5\u914D\uFF08\u4EBA\u548C agent \u540C\u4E00\u5957\u547D\u4EE4\uFF1B\u524D\u7AEF\u300C\u8BC4\u6D4B \u2192 \u8BC4\u5206\u88C5\u914D\u300D\u9875\u8D70\u540C\u4E00\u6279\u63A5\u53E3\uFF09
191519
+ cases # Benchmark Case \u6E05\u5355
191520
+ evaluations [--case <caseId>] # Run \u4E00\u89C8\uFF1A\u6700\u65B0\u8BC4\u5206\u72B6\u6001 / \u5224\u5206\u5458\u5DE5 / \u6807\u51C6\u7248\u672C
191521
+ evaluate <workOrderId> --case <caseId> [--judge <actorId>] [--case-version <v>] # \u5EFA Run \u5E76\u6392\u961F\u9996\u6B21\u8BC4\u5206
191522
+ rescore <runId> [--judge <actorId>] # \u53EA\u65B0\u589E\u4E00\u6B21\u8BC4\u5206\uFF0C\u4E0D\u52A8 Run \u5E8F\u53F7
191523
+ judges # \u53EF\u5F53\u5224\u5206\u5458\u5DE5\u7684 agent\uFF08\u53EA\u5217\u6709 active runtime \u7ED1\u5B9A\u7684\uFF09
191524
+ rubrics [--kind common|specialty|case_special] # \u8BC4\u5206\u6807\u51C6\u6E05\u5355\uFF08\u4E09\u79CD\u6807\u51C6\u662F\u540C\u4E00\u79CD\u5B9E\u4F53\uFF09
191525
+ rubric <rubricId> # \u770B\u4E00\u6761\u6807\u51C6\uFF1A\u8BF4\u660E + \u8F93\u51FA\u5951\u7EA6 + \u6CE8\u5165 prompt \u7684\u6B63\u6587\u5168\u6587
191526
+ rubric-save [--rubric-id <id>] --name <\u540D> --kind <k> (--prompt <\u6587\u672C>|--prompt-file <\u8DEF\u5F84>) [--spec-file <json>|--spec <json>] [--description \u2026] [--status active|archived]
191527
+ # \u4E0D\u5E26 --rubric-id \u662F\u65B0\u5EFA\uFF0C\u5E26\u4E0A\u662F\u6539\uFF08\u7248\u672C\u53F7\u81EA\u589E\uFF09\u3002--spec \u662F\u8F93\u51FA\u5951\u7EA6\uFF1A
191528
+ # { "sectionKey": "common", "aggregation": "none"|"mean", "strictIds": true, "dimensions": [{"id":"G1","label":"\u2026","min":1,"max":5,"nullable":false}] }
191529
+ # \u5B83\u540C\u65F6\u51B3\u5B9A\u300C\u5224\u5206\u5458\u5DE5\u8981\u8F93\u51FA\u4EC0\u4E48\u5F62\u72B6\u300D\u548C\u300C\u7ED3\u679C\u600E\u4E48\u6821\u9A8C\u300D\u2014\u2014\u4E0D\u518D\u5199\u6B7B G1-G7/\u4E94\u9879\u3002
191530
+ rubric-delete <rubricId> # \u5220\u6807\u51C6\uFF08\u6302\u8F7D\u4E86\u5B83\u7684 Case \u540C\u6B65\u6458\u5F15\u7528\uFF09
191531
+ case-scoring <caseId> # \u770B\u67D0 Case \u6302\u4E86\u54EA\u51E0\u5957\u6807\u51C6\u3001\u7531\u8C01\u6253\u5206\u3001\u662F\u5426\u8FD8\u5728\u5403\u56DE\u843D
191532
+ case-scoring-set <caseId> [--rubrics id1,id2] [--judge <actorId>|none]
191533
+ # \u53EA\u7ED9\u5176\u4E2D\u4E00\u4E2A flag \u5C31\u53EA\u6539\u90A3\u4E00\u9879\uFF08\u53E6\u4E00\u9879\u6CBF\u7528\u73B0\u503C\uFF0C\u4E0D\u4F1A\u88AB\u6E05\u7A7A\uFF09\u3002--judge none = \u56DE\u5230\u90E8\u7F72\u9ED8\u8BA4\u3002
191534
+ # \u4E00\u6761\u6807\u51C6\u90FD\u4E0D\u6302 = \u56DE\u843D\u5230 oasis-bench \u81EA\u5E26\u7684\u901A\u7528/\u4E13\u9879/Case \u4E13\u9879\u4E09\u4EFD\u6750\u6599\uFF0C\u884C\u4E3A\u4E0E\u914D\u7F6E\u5316\u4E4B\u524D\u4E00\u81F4\u3002
191535
+
190723
191536
  \u6CBB\u7406\uFF08\xA711\uFF09
190724
191537
  reopen <artifactId> [--note t] # \u89E3\u5C01\uFF08lifecycle \u2192 active\uFF09
190725
191538
  force-conclude <artifactId> --reason <t> # \u8C41\u514D gate\uFF1B\u673A\u68B0\u68C0\u67E5\u7167\u8DD1\u3001\u91CC\u7A0B\u7891\u5E26 forced \u6807\u8BB0
@@ -191069,7 +191882,7 @@ async function runCli(argv, println = console.log) {
191069
191882
  const store = createNodeTokenStore(path27.join(dir, "node-tokens.json"));
191070
191883
  const sub = positional[0];
191071
191884
  if (sub === "issue") {
191072
- const id = flags.get("id") ?? `node-${(0, import_node_crypto40.randomUUID)()}`;
191885
+ const id = flags.get("id") ?? `node-${(0, import_node_crypto42.randomUUID)()}`;
191073
191886
  const token2 = store.issue(id);
191074
191887
  println(token2);
191075
191888
  process.stderr.write(
@@ -192687,6 +193500,151 @@ ${res.warning}`);
192687
193500
  else if (!wsFilter && rows.length > 30) println(`\u2014\u2014 \u5171 ${rows.length} \u4E2A\u4EA7\u7269\uFF08\u5168\u5E93\u62C9\u5E73\uFF09\u3002\u6309\u5DE5\u5355\u770B\u7528 \`oasis ls --workspace <ws:id>\`\uFF0C\u5DE5\u5355\u6E05\u5355\u7528 \`oasis workorders\`\u3002`);
192688
193501
  break;
192689
193502
  }
193503
+ /**
193504
+ * 评测评分装配(人和 agent 同一套命令)。
193505
+ *
193506
+ * 三种评分标准(通用 / S 专项 / Case 专项)在系统里是**同一种实体**,统一经 prompt 注入判分员工;
193507
+ * 一条标准可挂到多个 Case,一个 Case 可挂多条;判分员工按「本次指定 → Case 装配 → 部署默认」解析。
193508
+ * 前端「评测 → 评分装配」页走的是同一批接口,两边不会各算各的。
193509
+ */
193510
+ case "rubrics": {
193511
+ const kind = flags.get("kind");
193512
+ const res = await api.request("GET", "/api/evaluations/rubrics");
193513
+ const items = kind ? res.items.filter((r) => r.kind === kind) : res.items;
193514
+ println(`\u8BC4\u5206\u6807\u51C6(${items.length}${kind ? ` / kind=${kind}` : ""})\u2014\u2014\u6302\u5230 Case \u7528 \`oasis case-scoring-set\`:`);
193515
+ for (const r of items) {
193516
+ println(`- ${r.rubricId} ${r.name} [${r.kind}] v${r.version}${r.status === "archived" ? " [\u5DF2\u5F52\u6863]" : ""}`);
193517
+ println(` \u8F93\u51FA\u6BB5=${r.outputSpec.sectionKey} \u7EF4\u5EA6=${r.outputSpec.dimensions.length || "\u7531 Case \u5B9A\u4E49"}${r.description ? ` ${r.description}` : ""}`);
193518
+ }
193519
+ if (items.length === 0) println("\uFF08\u65E0\u3002\u4E00\u6761\u90FD\u6CA1\u6709\u65F6 Case \u4F1A\u56DE\u843D\u5230 oasis-bench \u81EA\u5E26\u7684\u4E09\u4EFD\u6750\u6599\uFF09");
193520
+ break;
193521
+ }
193522
+ case "rubric": {
193523
+ const rubricId = needPos(positional, 0, "oasis rubric <rubricId>");
193524
+ const res = await api.request("GET", "/api/evaluations/rubrics");
193525
+ const rubric = res.items.find((r) => r.rubricId === rubricId);
193526
+ if (!rubric) throw new Error(`\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
193527
+ println(`${rubric.name} [${rubric.kind}] v${rubric.version} ${rubric.status}`);
193528
+ if (rubric.description) println(`\u8BF4\u660E: ${rubric.description}`);
193529
+ println(`\u8F93\u51FA\u5951\u7EA6: ${JSON.stringify(rubric.outputSpec, null, 2)}`);
193530
+ println("--- \u6CE8\u5165\u5224\u5206 prompt \u7684\u6B63\u6587 ---");
193531
+ println(rubric.promptSection);
193532
+ break;
193533
+ }
193534
+ case "rubric-save": {
193535
+ const rubricId = flags.get("rubric-id");
193536
+ const promptSection = flags.get("prompt-file") !== void 0 ? readFileArg(flags.get("prompt-file")) : flags.get("prompt");
193537
+ if (!promptSection) {
193538
+ throw new Error("\u7F3A\u5C11\u6807\u51C6\u6B63\u6587\uFF1A\u7ED9 --prompt <\u6587\u672C> \u6216 --prompt-file <\u8DEF\u5F84>");
193539
+ }
193540
+ const outputSpec = flags.get("spec-file") !== void 0 ? JSON.parse(readFileArg(flags.get("spec-file"))) : flags.get("spec") !== void 0 ? JSON.parse(flags.get("spec")) : void 0;
193541
+ const body = { promptSection };
193542
+ if (flags.get("name") !== void 0) body["name"] = flags.get("name");
193543
+ if (flags.get("kind") !== void 0) body["kind"] = flags.get("kind");
193544
+ if (flags.get("description") !== void 0) body["description"] = flags.get("description");
193545
+ if (flags.get("status") !== void 0) body["status"] = flags.get("status");
193546
+ if (outputSpec !== void 0) body["outputSpec"] = outputSpec;
193547
+ const saved = rubricId ? await api.request("PUT", `/api/evaluations/rubrics/${encodeURIComponent(rubricId)}`, body) : await api.request("POST", "/api/evaluations/rubrics", body);
193548
+ println(`\u5DF2\u4FDD\u5B58 ${saved.rubricId} ${saved.name} [${saved.kind}] v${saved.version}`);
193549
+ println(`\u6302\u5230 Case: oasis case-scoring-set <caseId> --rubrics ${saved.rubricId}`);
193550
+ break;
193551
+ }
193552
+ case "rubric-delete": {
193553
+ const rubricId = needPos(positional, 0, "oasis rubric-delete <rubricId>");
193554
+ await api.request("DELETE", `/api/evaluations/rubrics/${encodeURIComponent(rubricId)}`);
193555
+ println(`\u5DF2\u5220\u9664 ${rubricId}\uFF08\u6302\u8F7D\u4E86\u5B83\u7684 Case \u4F1A\u540C\u6B65\u6458\u6389\u5F15\u7528\uFF09`);
193556
+ break;
193557
+ }
193558
+ case "case-scoring": {
193559
+ const caseId = needPos(positional, 0, "oasis case-scoring <caseId>");
193560
+ const res = await api.request(
193561
+ "GET",
193562
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`
193563
+ );
193564
+ println(`Case ${res.caseId} \u8BC4\u5206\u88C5\u914D:`);
193565
+ println(` \u5224\u5206\u5458\u5DE5: ${res.judgeActorId ?? "\uFF08\u7528\u90E8\u7F72\u9ED8\u8BA4\uFF09"}`);
193566
+ if (res.usesBuiltinFallback) {
193567
+ println(" \u8BC4\u5206\u6807\u51C6: \uFF08\u672A\u6302\u8F7D\uFF0C\u56DE\u843D\u5230 oasis-bench \u81EA\u5E26\u7684\u901A\u7528 / \u4E13\u9879 / Case \u4E13\u9879\u4E09\u4EFD\u6750\u6599\uFF09");
193568
+ } else {
193569
+ for (const r of res.rubrics) {
193570
+ println(` - ${r.rubricId} ${r.name} [${r.kind}] v${r.version} \u2192 \u8F93\u51FA\u6BB5 ${r.outputSpec.sectionKey}`);
193571
+ }
193572
+ }
193573
+ break;
193574
+ }
193575
+ case "case-scoring-set": {
193576
+ const caseId = needPos(positional, 0, "oasis case-scoring-set <caseId> [--rubrics id1,id2] [--judge <actorId>|none]");
193577
+ const current = await api.request(
193578
+ "GET",
193579
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`
193580
+ );
193581
+ const rubricIds = flags.get("rubrics") !== void 0 ? flags.get("rubrics").split(",").map((v2) => v2.trim()).filter(Boolean) : current.rubrics.map((r) => r.rubricId);
193582
+ const judgeFlag = flags.get("judge");
193583
+ const judgeActorId = judgeFlag === void 0 ? current.judgeActorId : judgeFlag === "none" || judgeFlag === "" ? null : judgeFlag;
193584
+ const saved = await api.request(
193585
+ "PUT",
193586
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`,
193587
+ { rubricIds, judgeActorId }
193588
+ );
193589
+ println(`\u5DF2\u66F4\u65B0 Case ${saved.caseId} \u7684\u8BC4\u5206\u88C5\u914D\uFF1A\u6807\u51C6 ${saved.rubrics.length} \u5957\uFF0C\u5224\u5206\u5458\u5DE5 ${saved.judgeActorId ?? "\u90E8\u7F72\u9ED8\u8BA4"}`);
193590
+ if (saved.usesBuiltinFallback) println("\uFF08\u4E00\u6761\u90FD\u6CA1\u6302 = \u4ECD\u8D70 oasis-bench \u56DE\u843D\uFF09");
193591
+ break;
193592
+ }
193593
+ case "judges": {
193594
+ const res = await api.request(
193595
+ "GET",
193596
+ "/api/evaluations/judge-candidates"
193597
+ );
193598
+ println(`\u53EF\u9009\u5224\u5206\u5458\u5DE5(${res.items.length}):`);
193599
+ for (const j of res.items) println(`- ${j.actorId} ${j.name}`);
193600
+ if (res.items.length === 0) println("\uFF08\u65E0\uFF1A\u6CA1\u6709 agent \u914D\u4E86 active runtime \u7ED1\u5B9A\uFF09");
193601
+ break;
193602
+ }
193603
+ case "evaluations": {
193604
+ const res = await api.request("GET", "/api/evaluations/runs");
193605
+ const caseId = flags.get("case");
193606
+ const items = caseId ? res.items.filter((i) => i.run.caseId === caseId) : res.items;
193607
+ println(`Benchmark Runs(${items.length}):`);
193608
+ for (const item of items) {
193609
+ const e = item.latestEvaluation;
193610
+ println(`- ${item.run.runId} ${item.run.workOrderName} case=${item.run.caseId}#${item.run.attemptNo}`);
193611
+ println(` \u8BC4\u5206=${e ? `${e.status}${e.errorMessage ? ` (${e.errorMessage})` : ""}` : "\u5C1A\u672A\u8BC4\u5206"} \u5224\u5206\u5458\u5DE5=${e?.judgeActorId ?? "-"} \u6807\u51C6\u7248\u672C=${e?.rubricVersion ?? "-"}`);
193612
+ }
193613
+ break;
193614
+ }
193615
+ case "evaluate": {
193616
+ const workOrderId = needPos(positional, 0, "oasis evaluate <workOrderId> --case <caseId> [--judge <actorId>]");
193617
+ const caseId = flags.get("case");
193618
+ if (!caseId) throw new Error("\u7F3A\u5C11 --case <caseId>\uFF08\u53EF\u7528 oasis cases \u770B\u6E05\u5355\uFF09");
193619
+ const r = await api.request(
193620
+ "POST",
193621
+ "/api/evaluations/runs",
193622
+ { workOrderId, caseId, ...flags.get("case-version") ? { caseVersion: flags.get("case-version") } : {}, ...flags.get("judge") ? { judgeActorId: flags.get("judge") } : {} }
193623
+ );
193624
+ println(`\u5DF2\u5EFA Run ${r.run.runId}\uFF0C\u8BC4\u5206 ${r.evaluation.evaluationId} \u5DF2\u6392\u961F\uFF08\u5224\u5206\u5458\u5DE5 ${r.evaluation.judgeActorId}\uFF09`);
193625
+ break;
193626
+ }
193627
+ case "rescore": {
193628
+ const runId = needPos(positional, 0, "oasis rescore <runId> [--judge <actorId>]");
193629
+ const r = await api.request(
193630
+ "POST",
193631
+ `/api/evaluations/runs/${encodeURIComponent(runId)}/rescore`,
193632
+ flags.get("judge") ? { judgeActorId: flags.get("judge") } : {}
193633
+ );
193634
+ println(`\u5DF2\u6392\u961F\u7B2C ${r.evaluationNo} \u6B21\u8BC4\u5206 ${r.evaluationId}\uFF08\u5224\u5206\u5458\u5DE5 ${r.judgeActorId}\uFF09`);
193635
+ break;
193636
+ }
193637
+ case "cases": {
193638
+ const res = await api.request(
193639
+ "GET",
193640
+ "/api/evaluations/cases"
193641
+ );
193642
+ println(`Benchmark Cases(${res.items.length}):`);
193643
+ for (const c of res.items) {
193644
+ println(`- ${c.id} ${c.title} [${c.scopeType}/${c.difficultyLevel}] ${c.status}`);
193645
+ }
193646
+ break;
193647
+ }
192690
193648
  case "artifact-types": {
192691
193649
  const sub = positional[0] ?? "list";
192692
193650
  const typeBodyFromFlags = () => {
@@ -192889,7 +193847,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
192889
193847
  }
192890
193848
 
192891
193849
  // src/index.ts
192892
- var PKG_VERSION = true ? "0.1.81" : "dev";
193850
+ var PKG_VERSION = true ? "0.1.82" : "dev";
192893
193851
  var OASIS_DIR = path29.join(os9.homedir(), ".oasis");
192894
193852
  var CONFIG_FILE = path29.join(OASIS_DIR, "node-config.json");
192895
193853
  var PID_FILE = path29.join(OASIS_DIR, "node.pid");