oasis_test 0.1.83 → 0.1.84

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 +384 -60
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2399,6 +2399,15 @@ function validateUpsertEvaluationRubricInput(value2) {
2399
2399
  if (input.status !== void 0 && input.status !== "active" && input.status !== "archived") {
2400
2400
  throw new Error("status \u53EA\u80FD\u662F active \u6216 archived");
2401
2401
  }
2402
+ if (input.scope !== void 0 && input.scope !== "shared" && input.scope !== "case") {
2403
+ throw new Error("scope \u53EA\u80FD\u662F shared \u6216 case");
2404
+ }
2405
+ if (input.scope === "case" && !input.ownerCaseId?.trim()) {
2406
+ throw new Error("Case \u7EA7\u6807\u51C6\u5FC5\u987B\u6307\u660E\u5F52\u5C5E\u7684 caseId");
2407
+ }
2408
+ if (input.scope !== "case" && input.ownerCaseId) {
2409
+ throw new Error("\u5171\u4EAB\u6807\u51C6\u4E0D\u80FD\u6307\u5B9A ownerCaseId");
2410
+ }
2402
2411
  return {
2403
2412
  ...typeof input.rubricId === "string" && input.rubricId ? { rubricId: input.rubricId } : {},
2404
2413
  name: input.name.trim(),
@@ -2406,13 +2415,25 @@ function validateUpsertEvaluationRubricInput(value2) {
2406
2415
  ...typeof input.description === "string" && input.description.trim() ? { description: input.description.trim() } : {},
2407
2416
  promptSection: input.promptSection,
2408
2417
  outputSpec: validateEvaluationRubricOutputSpec(input.outputSpec),
2409
- ...input.status ? { status: input.status } : {}
2418
+ ...input.status ? { status: input.status } : {},
2419
+ ...input.scope ? { scope: input.scope } : {},
2420
+ ...input.ownerCaseId?.trim() ? { ownerCaseId: input.ownerCaseId.trim() } : {}
2410
2421
  };
2411
2422
  }
2412
2423
  function rubricVersionOf(rubrics, fallback) {
2413
2424
  if (!rubrics.length) return fallback;
2414
2425
  return rubrics.map((rubric) => `${rubric.rubricId}@${rubric.version}`).join("+");
2415
2426
  }
2427
+ function rubricRefsOf(rubrics) {
2428
+ return rubrics.map((rubric) => ({
2429
+ rubricId: rubric.rubricId,
2430
+ version: rubric.version,
2431
+ name: rubric.name,
2432
+ kind: rubric.kind,
2433
+ scope: rubric.scope,
2434
+ sectionKey: rubric.outputSpec.sectionKey
2435
+ }));
2436
+ }
2416
2437
  var DIMENSION_ID;
2417
2438
  var init_evaluation_rubric = __esm({
2418
2439
  "../contract/src/evaluation-rubric.ts"() {
@@ -4828,7 +4849,9 @@ function memoryHowToLines() {
4828
4849
  `- **\u7528\u6237\u660E\u663E\u4E0D\u6EE1 / \u5931\u671B / \u53CD\u590D\u50AC**\u2192 \u6211\u54EA\u91CC\u6CA1\u8FBE\u5230\u9884\u671F\u3001\u4E0B\u6B21\u600E\u4E48\u907F\u5F00\uFF1F`,
4829
4850
  `- **\u88AB\u8981\u6C42\u8FD4\u5DE5 / \u6253\u56DE**\u2192 \u8FD9\u662F\u300C\u9879\u76EE\u7279\u6709\u7684\u5751\u300D\uFF0C\u8FD8\u662F\u300C\u6211\u8FD9\u7C7B\u6D3B\u513F\u53CD\u590D\u72AF\u7684\u6BDB\u75C5\u300D\uFF1F`,
4830
4851
  `\u5224\u636E\u4E00\u81F4\uFF1A\u628A\u9879\u76EE\u540D\u53BB\u6389\u8FD9\u53E5\u8BDD\u8FD8\u6210\u7ACB\u5417\u2014\u2014\u6210\u7ACB \`--scope actor\`\uFF0C\u53EA\u5728\u672C\u9879\u76EE\u6210\u7ACB \`--scope project\`\u3002`,
4831
- `\u5199**\u7ED3\u8BBA**\uFF08"\u4E0B\u6B21\u8BE5\u600E\u4E48\u505A\uFF0C\u4E00\u53E5\u8BDD"\uFF09\uFF0C\u4E0D\u5199\u7ECF\u8FC7\u3002`
4852
+ `\u5199**\u7ED3\u8BBA**\uFF08"\u4E0B\u6B21\u8BE5\u600E\u4E48\u505A\uFF0C\u4E00\u53E5\u8BDD"\uFF09\uFF0C\u4E0D\u5199\u7ECF\u8FC7\u3002`,
4853
+ `**\u987A\u5E8F**\uFF1A"\u6536\u5DE5\u524D"\uFF1D**\u7ED9\u51FA\u6700\u7EC8\u7B54\u590D\u4E4B\u524D**\uFF0C\u4E0D\u662F\u4E4B\u540E\u3002\`mem-write\` \u505A\u5B8C\u518D\u5199\u6B63\u6587\uFF0C`,
4854
+ `\u522B\u628A\u300C\u8BB0\u5FC6\u5DF2\u4FDD\u5B58\u300D\u8FD9\u7C7B\u786E\u8BA4\u7559\u6210\u4F60\u7684\u6700\u540E\u4E00\u53E5\u2014\u2014\u5C55\u793A\u9762\u53EA\u628A\u6700\u540E\u4E00\u6BB5\u6B63\u6587\u5F53\u56DE\u590D\uFF0C\u6536\u5C3E\u786E\u8BA4\u4F1A\u9876\u6389\u771F\u6B63\u7684\u7B54\u590D\u3002`
4832
4855
  ];
4833
4856
  }
4834
4857
  function memoryReflectionEscalation(opts) {
@@ -4951,7 +4974,7 @@ function commandReference(opts) {
4951
4974
  `**\u5199**`,
4952
4975
  opts.handler.submitInstruction({ artifactId: id, isPart: true, action: "produce" }),
4953
4976
  `- \`oasis gap ${id} --desc "<\u7F3A\u4EC0\u4E48>"\` \u2014\u2014 **\u505A\u4E0D\u4E0B\u53BB\u65F6\u62A5**\uFF1A\u7F3A\u8F93\u5165 / \u7F3A\u4FE1\u606F / \u8981\u4EBA\u51B3\u7B56 / \u7F3A\u80FD\u529B\uFF08\u5DE5\u5177\u88C5\u4E0D\u4E0A\u7B49\uFF09\u90FD\u7B97\u3002\`--desc\` \u8BF4\u6E05\u7F3A\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\u5361\u4F4F\uFF08**\u4F60\u5728\u54EA\u4E2A\u90E8\u4EF6\u7CFB\u7EDF\u5DF2\u77E5\u9053\uFF0C\u4E0D\u7528\u4F60\u586B**\uFF09\u3002\u62A5\u5B8C**\u6536\u5DE5**\uFF1A\u8FD9\u6761\u90E8\u4EF6\u4F1A\u6682\u505C\uFF0C\u7BA1\u7406\u8005\u5206\u8BCA\uFF08\u56FE\u4E0A\u8865 / \u627E\u4EBA\uFF09\uFF1B\u9700\u6C42\u6EE1\u8DB3\u540E\u7CFB\u7EDF\u4F1A\u5E26\u7740\u89E3\u6CD5\u8BF4\u660E\u91CD\u65B0\u5524\u8D77\u4F60\uFF1B\u671F\u95F4\u522B propose\u3002`,
4954
- `- \`oasis annotate <\u4E0A\u6E38id> --from ${id} --part <\u4F60\u7684\u90E8\u4EF6> --body "<\u7591\u95EE>"\` \u2014\u2014 \u5BF9\u4E0A\u6E38\u63D0\u7591\u95EE/\u5F02\u8BAE\uFF08\u56DE\u538B\uFF09\u3002\`<\u4E0A\u6E38id>\`=\u88AB\u95EE\u7684\u4E0A\u6E38\uFF1B\`--from\`=\u672C\u4EA7\u7269\uFF1B\`--part\`=\u4F60\u8FD9\u4E2A\u90E8\u4EF6\uFF1B\`--body\`=\u5177\u4F53\u95EE\u9898\u3002\u63D0\u5B8C**\u6536\u5DE5**\u7B49\u7B54\u590D\uFF1B\u63D0\u95EE\u4E4B\u540E\u522B propose\uFF08\u591A\u4EFB\u52A1\u65F6\u540C\u6837**\u5148\u4EA4\u4ED8\u540E\u62A5\u969C**\uFF09\u3002`,
4977
+ `- \`oasis annotate <\u76EE\u6807\u4EA7\u7269id> --body "<\u4F60\u8981\u8BF4\u7684>"\` \u2014\u2014 **\u5728\u522B\u4EBA\u7684\u4EA7\u7269\u4E0A\u5199\u4E00\u6761\u8BC4\u8BBA**\u3002\u8BF4\u4EC0\u4E48\u7531\u4F60\u5B9A\uFF1A\u7591\u95EE\u3001\u5F02\u8BAE\u3001\u4FEE\u6539\u610F\u89C1\u3001\u8981\u6C42\u8FD4\u5DE5\u3001\u5224\u5B9A\u672A\u8FBE\u6807\u3001\u6216\u53EA\u662F\u63D0\u9192\u2014\u2014\u4F5C\u7528\u53D6\u51B3\u4E8E\u4F60\u5199\u7684\u5185\u5BB9\uFF0C\u547D\u4EE4\u672C\u8EAB\u4E0D\u533A\u5206\u3002\u5199\u7ED9**\u4F60\u7684\u4E0A\u6E38**\u65F6\uFF0C\u8FD9\u6761\u8BC4\u8BBA\u81EA\u52A8\u5E26\u4E0A\u963B\u585E\u529B\uFF1A**\u4E0A\u6E38\u7B54\u590D\u5B83\u4E4B\u524D\u4E0D\u80FD\u6536\u5C3E**\uFF0C\u4E14\u5B83\u7B54\u590D\u540E\u7CFB\u7EDF\u4F1A\u91CD\u65B0\u5524\u8D77\u4F60\uFF08\u4F60\u5728\u54EA\u4E2A\u90E8\u4EF6\u3001\u4EE3\u8868\u54EA\u4E2A\u4EA7\u7269\uFF0C\u7CFB\u7EDF\u90FD\u5DF2\u77E5\u9053\uFF0C\u4E0D\u7528\u4F60\u586B\uFF09\u3002`,
4955
4978
  ``,
4956
4979
  `**\u8BFB**\uFF08\u4F60\u662F\u53F6\u5B50\u5DE5\u4EBA\uFF0C\u53EA\u770B\u4F60\u4F9D\u8D56\u7684\u4E1C\u897F\uFF0C\u4E0D\u770B\u5168\u5C40\uFF09`,
4957
4980
  `- \`oasis status <id>\` / \`oasis content <id|revisionId> [path]\` \u2014\u2014 \u770B\u4F60\u4F9D\u8D56\u7684\u5144\u5F1F\u90E8\u4EF6 / \u4E0A\u6E38\u8F93\u5165\u7684\u72B6\u6001\u7D22\u5F15\u4E0E\u5B9E\u9645\u5185\u5BB9\uFF08\`status\` \u7ED9\u5168\u90E8\u7248\u672C\u7684\u5B8C\u6574 id + \u8BC4\u5BA1\u7968 + \u6279\u6CE8 id\uFF1B\`content\` \u4F20 \`revision:\u2026\` \u53D6\u6307\u5B9A\u7248\u672C\u6B63\u6587\u3001\u4F20 \`annotation:\u2026\`/\`review:\u2026\` \u53D6\u6279\u6CE8\u6216\u8BC4\u5BA1\u7968\u5168\u6587\uFF09\u3002`
@@ -4971,8 +4994,8 @@ function commandReference(opts) {
4971
4994
  write.push(
4972
4995
  `- \`oasis conclude ${id}\` \u2014\u2014 \u5BA3\u5E03\u4EA7\u7269**\u5B8C\u6574\u3001\u53EF\u88AB\u4E0B\u6E38\u6D88\u8D39**\uFF0C\u76D6\u4E00\u4E2A\u91CC\u7A0B\u7891\u3002\u524D\u63D0\uFF1A\u961F\u5217\u5DF2\u6E05\u7A7A\u3001\u4E14\u65E0\u672A\u89E3\u6790 gap / \u672A\u7B54\u590D\u56DE\u538B\uFF08\u5426\u5219\u88AB\u62D2\uFF09\uFF1B\u6709\u672A\u5904\u7F6E\u6765\u4FE1\u5148\u5904\u7F6E\u5B8C\uFF08\u56DE\u590D\u6216\u6539\u540E\u56DE\u590D\uFF09\u2014\u2014\u7CFB\u7EDF\u4E0D\u4F1A\u5728\u6709\u6765\u4FE1\u65F6\u66FF\u4F60\u81EA\u52A8\u6536\u5C3E\u3002\u76D6\u5B8C\u4E0B\u6E38\u6536\u5230\u901A\u77E5\u3002`,
4973
4996
  `- \`oasis add-revision ${id} --desc "<\u8FD9\u90E8\u4EF6\u505A\u4EC0\u4E48>" [--name <\u90E8\u4EF6\u540D>] [--role <\u89D2\u8272>]\` \u2014\u2014 \u628A\u672C\u4EA7\u7269\u62C6\u51FA\u4E00\u4E2A**\u53EF\u5E76\u884C\u4EA7\u51FA\u7684\u5B50\u90E8\u4EF6**\u6D3E\u51FA\u53BB\u3002\`--desc\`\uFF08**\u5FC5\u586B**\uFF09= \u8FD9\u4E2A\u5B50\u90E8\u4EF6\u8981\u5B8C\u6210\u4EC0\u4E48\uFF1B\`--name\` = \u7ED9\u5B83\u8D77\u7684\u90E8\u4EF6\u540D\uFF08\u53EF\u9009\uFF0C\u7F3A\u7701\u81EA\u52A8\u751F\u6210\uFF09\uFF1B\`--role\` = \u8C01\u6765\u505A\uFF08\u53EF\u9009\uFF0C\u7F3A\u7701=\u4F60\u81EA\u5DF1\uFF09\u3002${opts.handler.mergeMode === "external-ff" ? "\u5404\u90E8\u4EF6\u628A\u6539\u52A8\u5E76\u5165\u5DE5\u5355\u5206\u652F\u540E\uFF0C\u4F60 `oasis propose` \u6536\u5168 feat \u6536\u53E3\uFF08git-native\uFF0C\u522B\u7528 integrate\uFF09\u3002" : "\u5404\u90E8\u4EF6\u4EA7\u5B8C\u7531\u4F60 `oasis integrate` \u6536\u53E3\u3002"}`,
4974
- `- \`oasis gap ${id} --desc "<\u7F3A\u4EC0\u4E48>"\` \u2014\u2014 **\u505A\u4E0D\u4E0B\u53BB\u65F6\u62A5**\uFF1A\u7F3A\u8F93\u5165 / \u7F3A\u4FE1\u606F / \u8981\u4EBA\u51B3\u7B56 / \u7F3A\u80FD\u529B\uFF08\u5DE5\u5177\u88C5\u4E0D\u4E0A\u7B49\uFF09\u90FD\u7B97\u3002\`--desc\` \u8BF4\u6E05\u7F3A\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\u5361\u4F4F\uFF08\u7BA1\u7406\u8005\u636E\u5B83\u5206\u8BCA\uFF1A\u56FE\u4E0A\u8865 / \u627E\u4EBA\uFF09\u3002\u62A5\u5B8C**\u6536\u5DE5**\uFF1A\u8FD9\u6761\u4F1A\u6682\u505C\uFF0C\u9700\u6C42\u6EE1\u8DB3\u540E\u7CFB\u7EDF\u4F1A\u5E26\u7740\u89E3\u6CD5\u8BF4\u660E\u91CD\u65B0\u5524\u8D77\u4F60\uFF1B\u62A5\u969C\u4E4B\u540E\u522B propose\uFF08**\u5148\u4EA4\u4ED8\u540E\u62A5\u969C**\uFF1A\u672C\u8F6E\u82E5\u8FD8\u6709\u5DF2\u5B8C\u6210\u7684\u4EFB\u52A1\uFF0C\u5148 propose \u518D\u62A5\u2014\u2014\u62A5\u4E86\u8FD9\u6761\u7EBF\u5C31\u4EA4\u4E0D\u51FA\u7A3F\u4E86\uFF09\u3002`,
4975
- `- \`oasis annotate <\u4E0A\u6E38id> --from ${id} --body "<\u7591\u95EE>"\` \u2014\u2014 \u5BF9\u67D0\u4E0A\u6E38\u63D0\u7591\u95EE/\u5F02\u8BAE\uFF08\u56DE\u538B\uFF09\u3002\`<\u4E0A\u6E38id>\`=\u88AB\u95EE\u7684\u4E0A\u6E38\uFF1B\`--from\`=\u672C\u4EA7\u7269\uFF08\u7CFB\u7EDF\u636E\u6B64\u5728\u4E0A\u6E38\u7B54\u590D\u540E\u91CD\u6D3E\u4F60\uFF09\uFF1B\`--body\`=\u5177\u4F53\u95EE\u9898\u3002\u63D0\u5B8C**\u6536\u5DE5**\u7B49\u7B54\u590D\uFF1B\u63D0\u95EE\u4E4B\u540E\u522B propose\uFF08\u591A\u4EFB\u52A1\u65F6\u540C\u6837**\u5148\u4EA4\u4ED8\u540E\u62A5\u969C**\uFF09\u3002`,
4997
+ `- \`oasis gap ${id} --desc "<\u7F3A\u4EC0\u4E48>"\` \u2014\u2014 **\u505A\u4E0D\u4E0B\u53BB\u65F6\u62A5**\uFF1A\u7F3A\u8F93\u5165 / \u7F3A\u4FE1\u606F / \u8981\u4EBA\u51B3\u7B56 / \u7F3A\u80FD\u529B\uFF08\u5DE5\u5177\u88C5\u4E0D\u4E0A\u7B49\uFF09\u90FD\u7B97\u3002\`--desc\` \u8BF4\u6E05\u7F3A\u4EC0\u4E48\u3001\u4E3A\u4EC0\u4E48\u5361\u4F4F\uFF08\u7BA1\u7406\u8005\u636E\u5B83\u5206\u8BCA\uFF1A\u56FE\u4E0A\u8865 / \u627E\u4EBA\uFF09\u3002\u62A5\u5B8C**\u6536\u5DE5**\uFF1A\u8FD9\u6761\u4F1A\u6682\u505C\uFF0C\u9700\u6C42\u6EE1\u8DB3\u540E\u7CFB\u7EDF\u4F1A\u5E26\u7740\u89E3\u6CD5\u8BF4\u660E\u91CD\u65B0\u5524\u8D77\u4F60\u3002`,
4998
+ `- \`oasis annotate <\u76EE\u6807\u4EA7\u7269id> --body "<\u4F60\u8981\u8BF4\u7684>"\` \u2014\u2014 **\u5728\u522B\u4EBA\u7684\u4EA7\u7269\u4E0A\u5199\u4E00\u6761\u8BC4\u8BBA**\u3002\u8BF4\u4EC0\u4E48\u7531\u4F60\u5B9A\uFF1A\u7591\u95EE\u3001\u5F02\u8BAE\u3001\u4FEE\u6539\u610F\u89C1\u3001\u8981\u6C42\u8FD4\u5DE5\u3001\u5224\u5B9A\u672A\u8FBE\u6807\u3001\u6216\u53EA\u662F\u63D0\u9192\u2014\u2014\u4F5C\u7528\u53D6\u51B3\u4E8E\u4F60\u5199\u7684\u5185\u5BB9\uFF0C\u547D\u4EE4\u672C\u8EAB\u4E0D\u533A\u5206\u3002\u5199\u7ED9**\u4F60\u7684\u4E0A\u6E38**\u65F6\uFF0C\u8FD9\u6761\u8BC4\u8BBA\u81EA\u52A8\u5E26\u4E0A\u963B\u585E\u529B\uFF1A**\u4E0A\u6E38\u7B54\u590D\u5B83\u4E4B\u524D\u4E0D\u80FD\u6536\u5C3E**\uFF0C\u4E14\u5B83\u7B54\u590D\u540E\u7CFB\u7EDF\u4F1A\u91CD\u65B0\u5524\u8D77\u4F60\uFF08\u4EE3\u8868\u54EA\u4E2A\u4EA7\u7269\u63D0\u7684\uFF0C\u7CFB\u7EDF\u5DF2\u77E5\u9053\uFF0C\u4E0D\u7528\u4F60\u586B\uFF09\u3002`,
4976
4999
  `- \`oasis project content-location add <projectId> (--system <s> --config '<json>' | --file <path>)\` \u2014\u2014 \u7ED9\u9879\u76EE\u767B\u8BB0\u4E00\u5904\u5185\u5BB9\u4F4D\u7F6E\uFF1A\u5916\u90E8 home\uFF08\u5982\u4F60\u5EFA\u597D\u7684 git \u4ED3\uFF0C\`--system\`+\`--config\`\uFF1B**\u53EA\u767B\u8BB0\u6307\u9488\u3001\u4E0D\u521B\u5EFA\u8D44\u6E90\u672C\u8EAB**\u2014\u2014\u5EFA\u4ED3\u7528 gh \u7B49\u6258\u7BA1\u65B9 CLI\uFF09\u6216\u5185\u90E8\u53C2\u8003\u6587\u4EF6\uFF08\`--file\`\uFF09\u3002config \u5F62\u72B6\u968F system\uFF0C\u7528\`content-location systems <s>\` \u67E5\u5B57\u6BB5\u3002`
4977
5000
  );
4978
5001
  if (opts.hasOpenAnnotations) {
@@ -5298,7 +5321,7 @@ ${manifestDiff(baseC, newC)}
5298
5321
  whyLines.push(``, `\uFF08\u5DF2\u5173\u95ED\u7684\u5386\u53F2\u8BC4\u8BBA\u4E0D\u5217\u5165\u6E05\u5355\u2014\u2014\u9700\u8981\u65F6\u7528 \`oasis show ${artifactId}\` \u67E5\u3002\uFF09`);
5299
5322
  }
5300
5323
  whatLines.push(
5301
- queueTaskDue ? `**\u987A\u5E8F**\uFF1A\u2460 \u7EAF\u56DE\u590D\u7C7B\u7684\u4FE1\u5148\u56DE\u6389\uFF08\`oasis resolve\`/\`oasis reply\`\u2014\u2014**\u56DE\u590D\u6C38\u4E0D\u963B\u585E**\uFF09\u2192 \u2461 \u628A\u961F\u5217\u91CC\u90A3\u4E9B\u7248\u672C\u7684\u610F\u56FE**\u8FDE\u540C\u672C\u8F6E\u5176\u5B83\u4EFB\u52A1\u7684\u6539\u52A8\u5408\u6210\u4E00\u7248**\uFF0C\u7528 \`oasis integrate\` \u4EA4\uFF08**\u522B\u7528 \`oasis propose\`**\u2014\u2014\u90A3\u53EA\u4F1A\u518D\u52A0\u4E00\u6761\u6392\u961F\u7248\u672C\uFF0C\u961F\u5217\u66F4\u957F\uFF09\u2192 \u2462 \u5361\u4F4F\u7684\u4EFB\u52A1\u6B64\u65F6\u624D \`oasis gap\` / \u5411\u4E0A\u6E38 \`oasis annotate --from\`\uFF08**\u5148\u4EA4\u4ED8\u540E\u62A5\u969C**\uFF09\u2192 \u2463 \u6536\u5DE5\u3002**\u5168\u90E8\u4EFB\u52A1\u5904\u7406\u5B8C\u624D\u6536\u5DE5\u3002**` : `**\u987A\u5E8F**\uFF1A\u2460 \u7EAF\u56DE\u590D\u7C7B\u7684\u4FE1\u5148\u56DE\u6389\uFF08\`oasis resolve\`/\`oasis reply\`\u2014\u2014**\u56DE\u590D\u6C38\u4E0D\u963B\u585E**\uFF0C\u5148\u56DE\u514D\u5F97\u63D0\u4EA4\u88AB\u65E0\u5173\u7684\u4FE1\u62BC\u7740\uFF09\u2192 \u2461 \u9700\u8981\u6539\u5185\u5BB9\u7684\u4EFB\u52A1\u6539\u52A8**\u5408\u6210\u4E00\u7248** propose\uFF08\`--reason\` **\u6309\u4EFB\u52A1\u9010\u6761**\u5199\u6E05\uFF1A"\u4EFB\u52A11\uFF1A\u2026\uFF1B\u4EFB\u52A12\uFF1A\u2026"\uFF09\u2192 \u2462 \u5361\u4F4F\u7684\u4EFB\u52A1\u6B64\u65F6\u624D \`oasis gap\` / \u5411\u4E0A\u6E38 \`oasis annotate --from\`\uFF08**\u5148\u4EA4\u4ED8\u540E\u62A5\u969C**\u2014\u2014\u53CD\u8FC7\u6765\u8FD9\u6761\u7EBF\u5C31\u4E0D\u80FD propose \u4E86\uFF0C\u4F60\u5DF2\u5B8C\u6210\u7684\u5DE5\u4F5C\u4EA4\u4E0D\u51FA\u53BB\uFF09\u2192 \u2463 \u6536\u5DE5\u3002**\u5168\u90E8\u4EFB\u52A1\u5904\u7406\u5B8C\u624D\u6536\u5DE5\u3002**`
5324
+ queueTaskDue ? `**\u987A\u5E8F**\uFF1A\u2460 \u7EAF\u56DE\u590D\u7C7B\u7684\u4FE1\u5148\u56DE\u6389\uFF08\`oasis resolve\`/\`oasis reply\`\u2014\u2014**\u56DE\u590D\u6C38\u4E0D\u963B\u585E**\uFF09\u2192 \u2461 \u628A\u961F\u5217\u91CC\u90A3\u4E9B\u7248\u672C\u7684\u610F\u56FE**\u8FDE\u540C\u672C\u8F6E\u5176\u5B83\u4EFB\u52A1\u7684\u6539\u52A8\u5408\u6210\u4E00\u7248**\uFF0C\u7528 \`oasis integrate\` \u4EA4\uFF08**\u522B\u7528 \`oasis propose\`**\u2014\u2014\u90A3\u53EA\u4F1A\u518D\u52A0\u4E00\u6761\u6392\u961F\u7248\u672C\uFF0C\u961F\u5217\u66F4\u957F\uFF09\u2192 \u2462 \u9700\u8981\u4E0A\u6E38\u8FD4\u5DE5\u7684\u5411\u4E0A\u6E38 \`oasis annotate\`\u3001\u9700\u8981\u4EBA\u4ECB\u5165\u7684 \`oasis gap\` \u2192 \u2463 \u6536\u5DE5\u3002**\u5168\u90E8\u4EFB\u52A1\u5904\u7406\u5B8C\u624D\u6536\u5DE5\u3002**` : `**\u987A\u5E8F**\uFF1A\u2460 \u7EAF\u56DE\u590D\u7C7B\u7684\u4FE1\u5148\u56DE\u6389\uFF08\`oasis resolve\`/\`oasis reply\`\u2014\u2014**\u56DE\u590D\u6C38\u4E0D\u963B\u585E**\uFF0C\u5148\u56DE\u514D\u5F97\u63D0\u4EA4\u88AB\u65E0\u5173\u7684\u4FE1\u62BC\u7740\uFF09\u2192 \u2461 \u9700\u8981\u6539\u5185\u5BB9\u7684\u4EFB\u52A1\u6539\u52A8**\u5408\u6210\u4E00\u7248** propose\uFF08\`--reason\` **\u6309\u4EFB\u52A1\u9010\u6761**\u5199\u6E05\uFF1A"\u4EFB\u52A11\uFF1A\u2026\uFF1B\u4EFB\u52A12\uFF1A\u2026"\uFF09\u2192 \u2462 \u9700\u8981\u4E0A\u6E38\u8FD4\u5DE5\u7684\u5411\u4E0A\u6E38 \`oasis annotate\`\u3001\u9700\u8981\u4EBA\u4ECB\u5165\u7684 \`oasis gap\` \u2192 \u2463 \u6536\u5DE5\u3002**\u5168\u90E8\u4EFB\u52A1\u5904\u7406\u5B8C\u624D\u6536\u5DE5\u3002**`
5302
5325
  );
5303
5326
  } else if (integrating) {
5304
5327
  whyLines.push(`**\u5404\u90E8\u4EF6\u5DF2\u4EA7\u9F50\uFF0C\u5F85\u4F60\u96C6\u6210**\uFF1A\u4F60\u5148\u524D\u6D3E\u51FA\u53BB\u7684\u5B50\u90E8\u4EF6\u90FD\u4EA7\u51FA\u4E86\uFF0C\u73B0\u5728\u7531\u4F60 owner \u6536\u53E3\u6210\u4E00\u7248\u5B8C\u6574\u3001\u81EA\u6D3D\u7684 R\\*\u3002`);
@@ -5662,8 +5685,11 @@ ${m2.spec.split("\n").map((l) => ` > ${l}`).join("\n")}`);
5662
5685
  ``,
5663
5686
  `## \u751F\u4EA7\u8005\u5B88\u5219\uFF08\u56FA\u5B9A\uFF0C\u6BCF\u4E2A\u751F\u4EA7\u8005\u90FD\u4E00\u6837\uFF09`,
5664
5687
  `- \u4F60\u53EA\u4EA7**\u8FD9\u4E00\u4E2A**\u4EA7\u7269\uFF0C\u522B\u66FF\u522B\u7684\u4EA7\u7269\u62CD\u677F\u3001\u522B\u8D8A\u754C\u6539\u522B\u4EBA\u7684\u4E1C\u897F\uFF1B**\u4E0D\u5F52\u4F60\u5B9A\u7684\u51B3\u7B56\u522B\u5728\u5047\u8BBE\u4E0A\u786C\u7F16**\uFF08\u4F1A\u88AB\u6253\u56DE\uFF09\u3002`,
5665
- `- \u7F3A\u4E00\u4E2A**\u8FD8\u4E0D\u5B58\u5728\u7684\u524D\u7F6E**\u505A\u4E0D\u4E0B\u53BB \u2192 \`oasis gap\` \u62A5\u7F3A\u53E3\u540E**\u6536\u5DE5**\uFF0C\u522B\u786C\u7F16\uFF1B\u63D0\u4E86 gap \u5C31\u522B\u518D propose\uFF08\u8FD9\u6761\u4F1A\u6682\u505C\uFF0C\u524D\u7F6E\u5C31\u7EEA\u540E\u7CFB\u7EDF\u91CD\u65B0\u5524\u8D77\u4F60\uFF09\u3002`,
5666
- `- \u5BF9**\u4E0A\u6E38**\u6709\u7591\u95EE/\u5F02\u8BAE \u2192 \`oasis annotate\` \u63D0\u56DE\u538B\u540E**\u6536\u5DE5**\uFF0C\u540C\u6837\u522B propose\uFF1B\u4E0A\u6E38\u7B54\u590D\u540E\u7CFB\u7EDF\u91CD\u6D3E\u4F60\u3002`,
5688
+ // 这两条**不再预告"提了就别 propose"**:那条闸只对并行部件会话成立(kernel.ts:532/541
5689
+ // `proposingPart !== null` 为前提),整体版 propose 不设防。部件会话仍在自己的命令清单里看到真话
5690
+ // (本文件 :273)。失败条件一律交给内核报错讲——它自带理由与出路,且永不与实现漂移。
5691
+ `- \u7F3A\u4E00\u4E2A**\u8FD8\u4E0D\u5B58\u5728\u7684\u524D\u7F6E**\u505A\u4E0D\u4E0B\u53BB \u2192 \`oasis gap\` \u62A5\u7F3A\u53E3\u540E**\u6536\u5DE5**\uFF0C\u522B\u786C\u7F16\uFF08\u8FD9\u6761\u4F1A\u6682\u505C\uFF0C\u524D\u7F6E\u5C31\u7EEA\u540E\u7CFB\u7EDF\u91CD\u65B0\u5524\u8D77\u4F60\uFF09\u3002`,
5692
+ `- \u5BF9**\u4E0A\u6E38**\u6709\u610F\u89C1\u2014\u2014\u6709\u7591\u95EE\u3001\u8981\u5B83\u6539\u3001\u5224\u5B83\u6CA1\u8FBE\u6807 \u2192 \`oasis annotate <\u4E0A\u6E38id> --body "<\u8BF4\u6E05\u695A>"\` \u540E**\u6536\u5DE5**\u3002\u5199\u7ED9\u4E0A\u6E38\u7684\u8BC4\u8BBA\u81EA\u52A8\u5E26\u963B\u585E\u529B\uFF1A**\u5B83\u7B54\u590D\u524D\u4E0D\u80FD\u6536\u5C3E**\uFF0C\u7B54\u590D\u540E\u7CFB\u7EDF\u91CD\u6D3E\u4F60\u3002`,
5667
5693
  ...args.part === void 0 ? [`- \u6D3B\u592A\u5927 / \u53EF\u5E76\u884C \u2192 \`oasis add-revision\` \u62C6\u6210\u5B50\u90E8\u4EF6\u6D3E\u51FA\u53BB\uFF0C\u522B\u4E00\u4EBA\u4E00\u4F1A\u8BDD\u786C\u625B\u3002`] : [],
5668
5694
  ...batchedContinuation && args.part === void 0 ? [`- \u957F\u4EFB\u52A1\u5DF2\u5141\u8BB8\u5206\u6279\u7EED\u8DD1\uFF1A\u4E00\u6279\u6709\u8FDB\u5C55\u4F46\u6574\u4F53\u672A\u5B8C\u6210\u65F6\uFF0C\u6309\u300C\u600E\u4E48\u63D0\u4EA4\u300D\u91CC\u7684 propose \u547D\u4EE4\u8FFD\u52A0 \`--checkpoint --continue\`\uFF0Creason \u5199\u6E05\u672C\u6279\u5B8C\u6210\u4E86\u4EC0\u4E48\u3001\u5269\u4EC0\u4E48\u3001\u4E0B\u6279\u4ECE\u54EA\u7EE7\u7EED\uFF0C\u7136\u540E\u6536\u5DE5\uFF1B\u7CFB\u7EDF\u4F1A\u6D3E\u53D1\u4E0B\u4E00\u8F6E\u6B63\u5F0F session\u3002\u5168\u90E8\u5B8C\u6210\u65F6\u7167\u5E38 propose \u540E \`oasis conclude ${artifactId}\`\u3002`] : [],
5669
5695
  `- \u5199\u5165\u53EA\u8D70 \`oasis propose\`\uFF0C\u771F\u6B63\u5B8C\u6574\u4E86\u624D \`oasis conclude\`\uFF1B\u5361\u6CA1\u5361\u4F4F\u3001\u8FDB\u5EA6\u90FD\u662F\u7CFB\u7EDF\u7B97\u7684\uFF0C\u522B\u81EA\u5DF1\u7EF4\u62A4\u3002`,
@@ -7663,36 +7689,57 @@ var init_store = __esm({
7663
7689
  });
7664
7690
 
7665
7691
  // ../core/src/evaluation/rubric-store.ts
7666
- var import_node_crypto4, bindingKey, MemoryEvaluationRubricStore;
7692
+ var import_node_crypto4, bindingKey, versionKey, snapshotOf, MemoryEvaluationRubricStore;
7667
7693
  var init_rubric_store = __esm({
7668
7694
  "../core/src/evaluation/rubric-store.ts"() {
7669
7695
  "use strict";
7670
7696
  import_node_crypto4 = require("node:crypto");
7671
7697
  bindingKey = (companyId, caseId) => JSON.stringify([companyId, caseId]);
7698
+ versionKey = (rubricId, version2) => JSON.stringify([rubricId, version2]);
7699
+ snapshotOf = (rubric) => ({
7700
+ rubricId: rubric.rubricId,
7701
+ version: rubric.version,
7702
+ name: rubric.name,
7703
+ kind: rubric.kind,
7704
+ scope: rubric.scope,
7705
+ ...rubric.ownerCaseId ? { ownerCaseId: rubric.ownerCaseId } : {},
7706
+ ...rubric.description ? { description: rubric.description } : {},
7707
+ promptSection: rubric.promptSection,
7708
+ outputSpec: structuredClone(rubric.outputSpec),
7709
+ createdBy: rubric.updatedBy,
7710
+ createdAt: rubric.updatedAt
7711
+ });
7672
7712
  MemoryEvaluationRubricStore = class {
7673
7713
  rubrics = /* @__PURE__ */ new Map();
7714
+ versions = /* @__PURE__ */ new Map();
7674
7715
  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));
7716
+ async listRubrics(companyId, scope = "shared") {
7717
+ return [...this.rubrics.values()].filter((rubric) => rubric.companyId === companyId && rubric.scope === scope).sort((left, right) => left.name.localeCompare(right.name)).map((rubric) => structuredClone(rubric));
7677
7718
  }
7678
7719
  async getRubric(rubricId) {
7679
7720
  const rubric = this.rubrics.get(rubricId);
7680
7721
  return rubric ? structuredClone(rubric) : null;
7681
7722
  }
7723
+ async getCaseRubric(companyId, caseId) {
7724
+ const found = [...this.rubrics.values()].find((rubric) => rubric.companyId === companyId && rubric.scope === "case" && rubric.ownerCaseId === caseId);
7725
+ return found ? structuredClone(found) : null;
7726
+ }
7682
7727
  async upsertRubric(input, at) {
7683
7728
  const existing = input.rubricId ? this.rubrics.get(input.rubricId) : void 0;
7684
7729
  if (existing && existing.companyId !== input.companyId) {
7685
7730
  throw new Error(`\u8BC4\u5206\u6807\u51C6 ${input.rubricId} \u4E0D\u5C5E\u4E8E\u5F53\u524D\u516C\u53F8`);
7686
7731
  }
7732
+ const scope = input.scope ?? existing?.scope ?? "shared";
7687
7733
  const rubric = {
7688
7734
  rubricId: existing?.rubricId ?? input.rubricId ?? (0, import_node_crypto4.randomUUID)(),
7689
7735
  companyId: input.companyId,
7690
7736
  name: input.name,
7691
7737
  kind: input.kind,
7692
7738
  ...input.description ? { description: input.description } : {},
7739
+ scope,
7740
+ ...scope === "case" && (input.ownerCaseId ?? existing?.ownerCaseId) ? { ownerCaseId: input.ownerCaseId ?? existing?.ownerCaseId } : {},
7693
7741
  promptSection: input.promptSection,
7694
7742
  outputSpec: structuredClone(input.outputSpec),
7695
- // 版本随每次保存自增:判分记录靠 rubricId@version 复现「当时用的是哪一版标准」。
7696
7743
  version: (existing?.version ?? 0) + 1,
7697
7744
  status: input.status ?? existing?.status ?? "active",
7698
7745
  createdBy: existing?.createdBy ?? input.actor,
@@ -7701,6 +7748,7 @@ var init_rubric_store = __esm({
7701
7748
  updatedAt: at
7702
7749
  };
7703
7750
  this.rubrics.set(rubric.rubricId, rubric);
7751
+ this.versions.set(versionKey(rubric.rubricId, rubric.version), snapshotOf(rubric));
7704
7752
  return structuredClone(rubric);
7705
7753
  }
7706
7754
  async deleteRubric(rubricId, companyId) {
@@ -7715,6 +7763,13 @@ var init_rubric_store = __esm({
7715
7763
  });
7716
7764
  }
7717
7765
  }
7766
+ async listRubricVersions(rubricId) {
7767
+ return [...this.versions.values()].filter((version2) => version2.rubricId === rubricId).sort((left, right) => right.version - left.version).map((version2) => structuredClone(version2));
7768
+ }
7769
+ async getRubricVersion(rubricId, version2) {
7770
+ const found = this.versions.get(versionKey(rubricId, version2));
7771
+ return found ? structuredClone(found) : null;
7772
+ }
7718
7773
  async listBindings(companyId) {
7719
7774
  return [...this.bindings.values()].filter((binding) => binding.companyId === companyId).map((binding) => structuredClone(binding));
7720
7775
  }
@@ -147331,14 +147386,17 @@ ${acceptanceCriteria.map((c) => `- ${c}`).join("\n")}`] : []
147331
147386
  return { message: revisionArg !== void 0 ? `\u9A8C\u6536\u7968\u5DF2\u8BB0\u5F55\uFF08${status === "pending" ? "\u7B49\u5176\u4F59\u4F5C\u8005/\u5408\u5165" : status}\uFF09` : `review \u5DF2\u8BB0\u5F55\uFF1Bgate \u2192 ${status}` };
147332
147387
  }
147333
147388
  case "annotate": {
147334
- const raisedFrom = optStr(args, "raisedFrom");
147389
+ const targetId = str(args, "artifactId");
147390
+ const sessionNode = ctx.sessionArtifactId;
147391
+ const autoRaisedFrom = optStr(args, "raisedFrom") === void 0 && sessionNode !== void 0 && sessionNode !== targetId && (kernel.model.artifacts.get(sessionNode)?.inputs ?? []).some((e) => e.to === targetId) ? sessionNode : void 0;
147392
+ const raisedFrom = optStr(args, "raisedFrom") ?? autoRaisedFrom;
147335
147393
  const attachments = attachmentArgs(args);
147336
147394
  const mentions = Array.isArray(args["mentions"]) ? args["mentions"].filter((x2) => typeof x2 === "string" && x2.startsWith("actor:")) : void 0;
147337
147395
  if (mentions !== void 0 && mentions.length > 0 && isAgent(actor)) {
147338
147396
  throw new Error("@ \u6743\u53EA\u5C5E\u4E8E\u4EBA\uFF1Aagent \u627E agent \u7528\u56DE\u538B\uFF08annotate --from\uFF09\u6216\u5199\u4FE1\u5230\u5B83\u7684\u4EA7\u7269\uFF1B\u66FF\u4EBA @ \u9700\u5728 1:1 \u4F1A\u8BDD\u4E2D\uFF08\u7F72\u540D\u4EE3\u7F72\uFF09\u3002");
147339
147397
  }
147340
147398
  const annotation = await kernel.annotate({
147341
- artifactId: str(args, "artifactId"),
147399
+ artifactId: targetId,
147342
147400
  actor,
147343
147401
  body: str(args, "body"),
147344
147402
  ...hand !== void 0 ? { hand } : {},
@@ -148133,6 +148191,8 @@ async function startOasisServer(opts) {
148133
148191
  }
148134
148192
  const result = await runCommand(engine.kernel, engine.blobs, engine.oplog, actor, body.command, body.args ?? {}, {
148135
148193
  ...tokenClaims?.dispatchSeq !== void 0 ? { dispatchSeq: tokenClaims.dispatchSeq } : {},
148194
+ // annotate 自动补 raisedFrom 的依据:本会话在做哪个节点(同源同解析器,见 ctx.sessionArtifactId)
148195
+ ...tokenClaims?.artifactId !== void 0 ? { sessionArtifactId: tokenClaims.artifactId } : {},
148136
148196
  ...actingForHuman !== void 0 ? { actingForHuman } : {},
148137
148197
  ...chatOrigin !== void 0 ? { chatOrigin } : {},
148138
148198
  ...opts.projectState ? { projectState: opts.projectState } : {},
@@ -165799,6 +165859,9 @@ function builtinRubricsForCase(evaluationCase) {
165799
165859
  const base = {
165800
165860
  companyId: "",
165801
165861
  version: 0,
165862
+ // 回落标准不是登记表里的记录,标成 shared 只是为了满足类型;它们的 rubricId 是 builtin:*,
165863
+ // 不会被写进挂载,也不会出现在「评分标准」页。
165864
+ scope: "shared",
165802
165865
  status: "active",
165803
165866
  createdBy: "system",
165804
165867
  createdAt: at,
@@ -165950,11 +166013,36 @@ var init_scoring = __esm({
165950
166013
  at() {
165951
166014
  return (this.options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
165952
166015
  }
166016
+ /** 「评分标准」登记表——只列共享标准。Case 级的走 getCaseScoring。 */
165953
166017
  listRubrics(companyId) {
165954
- return this.options.store.listRubrics(companyId);
166018
+ return this.options.store.listRubrics(companyId, "shared");
166019
+ }
166020
+ listRubricVersions(rubricId) {
166021
+ return this.options.store.listRubricVersions(rubricId);
166022
+ }
166023
+ async getRubricVersion(rubricId, version2) {
166024
+ const found = await this.options.store.getRubricVersion(rubricId, version2);
166025
+ if (!found) {
166026
+ throw new ScoringConfigError(404, "RUBRIC_VERSION_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId}@${version2} \u4E0D\u5B58\u5728`);
166027
+ }
166028
+ return found;
165955
166029
  }
165956
- async upsertRubric(body, companyId, actor) {
165957
- const raw = body ?? {};
166030
+ /** 保存共享标准(登记表)。每次保存版本号 +1 并落一条不可变快照。 */
166031
+ upsertRubric(body, companyId, actor) {
166032
+ return this.save({ ...body, scope: "shared" }, companyId, actor);
166033
+ }
166034
+ /** 保存某个 Case 自己的标准。同一个 Case 只有一条,重复保存就是出新版本。 */
166035
+ async saveCaseRubric(caseId, body, companyId, actor) {
166036
+ const existing = await this.options.store.getCaseRubric(companyId, caseId);
166037
+ return this.save({
166038
+ ...body,
166039
+ scope: "case",
166040
+ ownerCaseId: caseId,
166041
+ // 认已有那条的 id:Case 级标准一对一,不带 id 再存一次会变成两条抢同一个 Case。
166042
+ ...existing ? { rubricId: existing.rubricId } : {}
166043
+ }, companyId, actor);
166044
+ }
166045
+ async save(raw, companyId, actor) {
165958
166046
  const rubricId = typeof raw["rubricId"] === "string" && raw["rubricId"] ? raw["rubricId"] : void 0;
165959
166047
  let existing = null;
165960
166048
  if (rubricId) {
@@ -165962,6 +166050,13 @@ var init_scoring = __esm({
165962
166050
  if (existing && existing.companyId !== companyId) {
165963
166051
  throw new ScoringConfigError(404, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
165964
166052
  }
166053
+ if (existing && raw["scope"] && existing.scope !== raw["scope"]) {
166054
+ throw new ScoringConfigError(
166055
+ 409,
166056
+ "RUBRIC_SCOPE_IMMUTABLE",
166057
+ `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u5DF2\u662F ${existing.scope === "shared" ? "\u5171\u4EAB" : "Case \u7EA7"}\u6807\u51C6\uFF0C\u4E0D\u80FD\u6539\u4F5C\u7528\u57DF`
166058
+ );
166059
+ }
165965
166060
  }
165966
166061
  const merged = existing ? {
165967
166062
  rubricId,
@@ -165970,7 +166065,9 @@ var init_scoring = __esm({
165970
166065
  description: raw["description"] ?? existing.description,
165971
166066
  promptSection: raw["promptSection"] ?? existing.promptSection,
165972
166067
  outputSpec: raw["outputSpec"] ?? existing.outputSpec,
165973
- status: raw["status"] ?? existing.status
166068
+ status: raw["status"] ?? existing.status,
166069
+ scope: existing.scope,
166070
+ ...existing.ownerCaseId ? { ownerCaseId: existing.ownerCaseId } : {}
165974
166071
  } : raw;
165975
166072
  let input;
165976
166073
  try {
@@ -165990,6 +166087,7 @@ var init_scoring = __esm({
165990
166087
  listBindings(companyId) {
165991
166088
  return this.options.store.listBindings(companyId);
165992
166089
  }
166090
+ /** 改 Case 挂的共享标准 / 判分员工。Case 自己那条标准不走这里(走 saveCaseRubric)。 */
165993
166091
  async putBinding(caseId, body, companyId, actor) {
165994
166092
  const input = body ?? {};
165995
166093
  const rubricIds = Array.isArray(input.rubricIds) ? input.rubricIds.filter((id) => typeof id === "string" && id.length > 0) : [];
@@ -166002,19 +166100,20 @@ var init_scoring = __esm({
166002
166100
  if (!rubric || rubric.companyId !== companyId) {
166003
166101
  throw new ScoringConfigError(400, "RUBRIC_NOT_FOUND", `\u8BC4\u5206\u6807\u51C6 ${rubricId} \u4E0D\u5B58\u5728`);
166004
166102
  }
166103
+ if (rubric.scope !== "shared") {
166104
+ throw new ScoringConfigError(
166105
+ 400,
166106
+ "RUBRIC_NOT_SHARED",
166107
+ `\u300C${rubric.name}\u300D\u662F Case \u7EA7\u6807\u51C6\uFF0C\u53EA\u80FD\u5728\u5B83\u81EA\u5DF1\u7684 Case \u91CC\u7F16\u8F91\uFF0C\u4E0D\u80FD\u6302\u8F7D`
166108
+ );
166109
+ }
166005
166110
  if (rubric.status !== "active") {
166006
166111
  throw new ScoringConfigError(400, "RUBRIC_ARCHIVED", `\u8BC4\u5206\u6807\u51C6\u300C${rubric.name}\u300D\u5DF2\u5F52\u6863\uFF0C\u4E0D\u80FD\u6302\u8F7D`);
166007
166112
  }
166008
166113
  rubrics.push(rubric);
166009
166114
  }
166010
- const sections = rubrics.map((rubric) => rubric.outputSpec.sectionKey);
166011
- if (new Set(sections).size !== sections.length) {
166012
- throw new ScoringConfigError(
166013
- 400,
166014
- "RUBRIC_SECTION_CONFLICT",
166015
- `\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`
166016
- );
166017
- }
166115
+ const caseRubric = await this.options.store.getCaseRubric(companyId, caseId);
166116
+ this.assertNoSectionConflict(rubrics, caseRubric);
166018
166117
  const judgeActorId = typeof input.judgeActorId === "string" && input.judgeActorId.trim() ? input.judgeActorId.trim() : null;
166019
166118
  if (judgeActorId && this.options.verifyJudgeActor && !await this.options.verifyJudgeActor(judgeActorId, companyId)) {
166020
166119
  throw new ScoringConfigError(400, "JUDGE_ACTOR_INVALID", `${judgeActorId} \u4E0D\u662F\u53EF\u7528\u7684\u5224\u5206\u5458\u5DE5`);
@@ -166025,26 +166124,46 @@ var init_scoring = __esm({
166025
166124
  );
166026
166125
  return {
166027
166126
  caseId,
166028
- rubrics,
166127
+ sharedRubrics: rubrics,
166128
+ caseRubric,
166029
166129
  judgeActorId: binding.judgeActorId,
166030
- usesBuiltinFallback: rubrics.length === 0
166130
+ usesBuiltinFallback: rubrics.length === 0 && !caseRubric
166031
166131
  };
166032
166132
  }
166033
- /** Case 当前装配的对外投影(挂载展开 + 是否还在吃回落)。 */
166133
+ /** 两条标准写进同一个结果段 = 后写的覆盖前一条,判分结果里会静默少一套标准。挡在入口。 */
166134
+ assertNoSectionConflict(shared, caseRubric) {
166135
+ const all = caseRubric ? [...shared, caseRubric] : shared;
166136
+ const sections = all.map((rubric) => rubric.outputSpec.sectionKey);
166137
+ if (new Set(sections).size !== sections.length) {
166138
+ throw new ScoringConfigError(
166139
+ 400,
166140
+ "RUBRIC_SECTION_CONFLICT",
166141
+ `\u751F\u6548\u7684\u6807\u51C6\u5199\u5230\u4E86\u540C\u4E00\u4E2A\u7ED3\u679C\u6BB5\uFF08${sections.join("\u3001")}\uFF09\uFF0C\u8BF7\u6539\u5176\u4E2D\u4E00\u6761\u7684 sectionKey`
166142
+ );
166143
+ }
166144
+ }
166145
+ /** Case 当前装配的对外投影(共享挂载 + 自己的标准 + 是否还在吃回落)。 */
166034
166146
  async getCaseScoring(caseId, companyId) {
166035
166147
  const binding = await this.options.store.getBinding(companyId, caseId);
166036
- const rubrics = await this.mountedRubrics(binding, companyId);
166148
+ const [sharedRubrics, caseRubric] = await Promise.all([
166149
+ this.mountedRubrics(binding, companyId),
166150
+ this.options.store.getCaseRubric(companyId, caseId)
166151
+ ]);
166037
166152
  return {
166038
166153
  caseId,
166039
- rubrics,
166154
+ sharedRubrics,
166155
+ caseRubric,
166040
166156
  judgeActorId: binding?.judgeActorId ?? null,
166041
- usesBuiltinFallback: rubrics.length === 0
166157
+ usesBuiltinFallback: sharedRubrics.length === 0 && !caseRubric
166042
166158
  };
166043
166159
  }
166044
166160
  /** 判分前的最终解析:拿到本次真正要用的标准与判分员工。 */
166045
166161
  async resolveForRun(evaluationCase, companyId, requestedJudgeActorId) {
166046
166162
  const binding = await this.options.store.getBinding(companyId, evaluationCase.id);
166047
- const mounted = await this.mountedRubrics(binding, companyId);
166163
+ const [mounted, caseRubric] = await Promise.all([
166164
+ this.mountedRubrics(binding, companyId),
166165
+ this.options.store.getCaseRubric(companyId, evaluationCase.id)
166166
+ ]);
166048
166167
  const judgeActorId = requestedJudgeActorId?.trim() || binding?.judgeActorId || this.options.defaultJudgeActorId;
166049
166168
  if (!judgeActorId) {
166050
166169
  throw new ScoringConfigError(
@@ -166053,10 +166172,20 @@ var init_scoring = __esm({
166053
166172
  "\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"
166054
166173
  );
166055
166174
  }
166175
+ const configured = caseRubric ? [...mounted, caseRubric] : mounted;
166176
+ if (configured.length) {
166177
+ const covered = new Set(configured.map((rubric) => rubric.outputSpec.sectionKey));
166178
+ const filled = builtinRubricsForCase(evaluationCase).filter((rubric) => !covered.has(rubric.outputSpec.sectionKey));
166179
+ return {
166180
+ rubrics: [...configured, ...filled],
166181
+ judgeActorId,
166182
+ usesBuiltinFallback: false
166183
+ };
166184
+ }
166056
166185
  return {
166057
- rubrics: mounted.length ? mounted : builtinRubricsForCase(evaluationCase),
166186
+ rubrics: builtinRubricsForCase(evaluationCase),
166058
166187
  judgeActorId,
166059
- usesBuiltinFallback: mounted.length === 0
166188
+ usesBuiltinFallback: true
166060
166189
  };
166061
166190
  }
166062
166191
  async mountedRubrics(binding, companyId) {
@@ -166337,6 +166466,8 @@ var init_service7 = __esm({
166337
166466
  judgeActorId: resolved.judgeActorId,
166338
166467
  judgeVersion: this.options.judgeVersion,
166339
166468
  rubricVersion: rubricVersionOf(resolved.rubrics, evaluationCase.rubricVersion),
166469
+ // 结构化引用:Case 的标准会变,这里钉死这一次用的是哪几条、各是第几版。
166470
+ rubricRefs: rubricRefsOf(resolved.rubrics),
166340
166471
  evaluatorVersion: evaluationCase.evaluatorVersion,
166341
166472
  createdBy: actor,
166342
166473
  createdAt: now
@@ -166441,6 +166572,20 @@ function evaluationDomain(options) {
166441
166572
  return mapError(error2);
166442
166573
  }
166443
166574
  });
166575
+ router.get("/api/evaluations/rubrics/:rubricId/versions", async (req) => ({
166576
+ status: 200,
166577
+ body: { items: await scoring.listRubricVersions(req.params.rubricId) }
166578
+ }));
166579
+ router.get("/api/evaluations/rubrics/:rubricId/versions/:version", async (req) => {
166580
+ try {
166581
+ return {
166582
+ status: 200,
166583
+ body: await scoring.getRubricVersion(req.params.rubricId, Number(req.params.version))
166584
+ };
166585
+ } catch (error2) {
166586
+ return mapError(error2);
166587
+ }
166588
+ });
166444
166589
  router.get("/api/evaluations/case-scoring", async (req) => ({
166445
166590
  status: 200,
166446
166591
  body: { items: await scoring.listBindings(req.auth.companyId ?? "default") }
@@ -166464,6 +166609,21 @@ function evaluationDomain(options) {
166464
166609
  return mapError(error2);
166465
166610
  }
166466
166611
  });
166612
+ router.put("/api/evaluations/cases/:caseId/rubric", async (req) => {
166613
+ try {
166614
+ return {
166615
+ status: 200,
166616
+ body: await scoring.saveCaseRubric(
166617
+ req.params.caseId,
166618
+ req.body,
166619
+ req.auth.companyId ?? "default",
166620
+ req.auth.actor
166621
+ )
166622
+ };
166623
+ } catch (error2) {
166624
+ return mapError(error2);
166625
+ }
166626
+ });
166467
166627
  router.get("/api/evaluations/judge-candidates", async (req) => ({
166468
166628
  status: 200,
166469
166629
  body: {
@@ -187223,6 +187383,20 @@ function benchmarkSchemaSql(schema) {
187223
187383
  created_by text NOT NULL, created_at timestamptz NOT NULL,
187224
187384
  updated_by text NOT NULL, updated_at timestamptz NOT NULL
187225
187385
  );
187386
+ ALTER TABLE ${s2}.benchmark_rubrics ADD COLUMN IF NOT EXISTS scope text NOT NULL DEFAULT 'shared';
187387
+ ALTER TABLE ${s2}.benchmark_rubrics ADD COLUMN IF NOT EXISTS owner_case_id text;
187388
+ ALTER TABLE ${s2}.benchmark_evaluations ADD COLUMN IF NOT EXISTS rubric_refs jsonb;
187389
+ -- \u7248\u672C\u5FEB\u7167\u53EA\u589E\u4E0D\u6539\uFF1A\u5386\u53F2 Evaluation \u9760 (rubric_id, version) \u56DE\u67E5\u5F53\u65F6\u90A3\u4EFD\u6B63\u6587\u3002
187390
+ CREATE TABLE IF NOT EXISTS ${s2}.benchmark_rubric_versions (
187391
+ rubric_id text NOT NULL, version integer NOT NULL, name text NOT NULL, kind text NOT NULL,
187392
+ scope text NOT NULL, owner_case_id text, description text,
187393
+ prompt_section text NOT NULL, output_spec jsonb NOT NULL,
187394
+ created_by text NOT NULL, created_at timestamptz NOT NULL,
187395
+ PRIMARY KEY (rubric_id, version)
187396
+ );
187397
+ -- \u4E00\u4E2A Case \u53EA\u80FD\u6709\u4E00\u6761\u81EA\u5DF1\u7684\u6807\u51C6\uFF1B\u9760\u552F\u4E00\u7D22\u5F15\u515C\u4F4F\u5E76\u53D1\u91CD\u590D\u5199\u3002
187398
+ CREATE UNIQUE INDEX IF NOT EXISTS benchmark_rubrics_owner_case_idx
187399
+ ON ${s2}.benchmark_rubrics (company_id, owner_case_id) WHERE owner_case_id IS NOT NULL;
187226
187400
  CREATE TABLE IF NOT EXISTS ${s2}.benchmark_case_scoring (
187227
187401
  company_id text NOT NULL, case_id text NOT NULL, rubric_ids jsonb NOT NULL,
187228
187402
  judge_actor_id text, updated_by text NOT NULL, updated_at timestamptz NOT NULL,
@@ -187263,6 +187437,7 @@ function toEvaluation(row) {
187263
187437
  judgeRunId: nullableText(row.judge_run_id),
187264
187438
  judgeVersion: String(row.judge_version),
187265
187439
  rubricVersion: String(row.rubric_version),
187440
+ rubricRefs: row.rubric_refs == null ? null : structuredClone(row.rubric_refs),
187266
187441
  evaluatorVersion: String(row.evaluator_version),
187267
187442
  result: row.result == null ? null : structuredClone(row.result),
187268
187443
  errorCode: nullableText(row.error_code),
@@ -187280,6 +187455,8 @@ function toRubric(row) {
187280
187455
  name: String(row.name),
187281
187456
  kind: String(row.kind),
187282
187457
  ...row.description == null ? {} : { description: String(row.description) },
187458
+ scope: row.scope == null ? "shared" : String(row.scope),
187459
+ ...row.owner_case_id == null ? {} : { ownerCaseId: String(row.owner_case_id) },
187283
187460
  promptSection: String(row.prompt_section),
187284
187461
  outputSpec: structuredClone(row.output_spec),
187285
187462
  version: Number(row.version),
@@ -187300,6 +187477,21 @@ function toBinding(row) {
187300
187477
  updatedAt: iso2(row.updated_at)
187301
187478
  };
187302
187479
  }
187480
+ function toRubricVersion(row) {
187481
+ return {
187482
+ rubricId: String(row.rubric_id),
187483
+ version: Number(row.version),
187484
+ name: String(row.name),
187485
+ kind: String(row.kind),
187486
+ scope: String(row.scope),
187487
+ ...row.owner_case_id == null ? {} : { ownerCaseId: String(row.owner_case_id) },
187488
+ ...row.description == null ? {} : { description: String(row.description) },
187489
+ promptSection: String(row.prompt_section),
187490
+ outputSpec: structuredClone(row.output_spec),
187491
+ createdBy: String(row.created_by),
187492
+ createdAt: iso2(row.created_at)
187493
+ };
187494
+ }
187303
187495
  var import_node_crypto38, ident17, iso2, nullableIso, nullableText, PostgresEvaluationStore, PostgresEvaluationRubricStore;
187304
187496
  var init_postgres_evaluation = __esm({
187305
187497
  "../storage/src/postgres-evaluation.ts"() {
@@ -187425,8 +187617,8 @@ var init_postgres_evaluation = __esm({
187425
187617
  `INSERT INTO ${this.s}.benchmark_evaluations
187426
187618
  (evaluation_id,run_id,evaluation_no,status,judge_actor_id,judge_run_id,judge_version,
187427
187619
  rubric_version,evaluator_version,result,error_code,error_message,created_by,created_at,
187428
- started_at,completed_at)
187429
- VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10::jsonb,$11,$12,$13,$14,$15,$16) RETURNING *`,
187620
+ started_at,completed_at,rubric_refs)
187621
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10::jsonb,$11,$12,$13,$14,$15,$16,$17::jsonb) RETURNING *`,
187430
187622
  [
187431
187623
  input.evaluationId,
187432
187624
  input.runId,
@@ -187443,7 +187635,8 @@ var init_postgres_evaluation = __esm({
187443
187635
  input.createdBy,
187444
187636
  input.createdAt,
187445
187637
  input.startedAt ?? null,
187446
- input.completedAt ?? null
187638
+ input.completedAt ?? null,
187639
+ input.rubricRefs ? JSON.stringify(input.rubricRefs) : null
187447
187640
  ]
187448
187641
  );
187449
187642
  await client.query("COMMIT");
@@ -187473,7 +187666,7 @@ var init_postgres_evaluation = __esm({
187473
187666
  const result = await this.pool.query(
187474
187667
  `UPDATE ${this.s}.benchmark_evaluations SET status=$2,judge_run_id=$3,judge_version=$4,
187475
187668
  rubric_version=$5,evaluator_version=$6,result=$7::jsonb,error_code=$8,error_message=$9,
187476
- started_at=$10,completed_at=$11 WHERE evaluation_id=$1`,
187669
+ started_at=$10,completed_at=$11,rubric_refs=$12::jsonb WHERE evaluation_id=$1`,
187477
187670
  [
187478
187671
  evaluation.evaluationId,
187479
187672
  evaluation.status,
@@ -187485,7 +187678,8 @@ var init_postgres_evaluation = __esm({
187485
187678
  evaluation.errorCode ?? null,
187486
187679
  evaluation.errorMessage ?? null,
187487
187680
  evaluation.startedAt ?? null,
187488
- evaluation.completedAt ?? null
187681
+ evaluation.completedAt ?? null,
187682
+ evaluation.rubricRefs ? JSON.stringify(evaluation.rubricRefs) : null
187489
187683
  ]
187490
187684
  );
187491
187685
  if (result.rowCount !== 1) throw new Error(`Evaluation ${evaluation.evaluationId} \u4E0D\u5B58\u5728`);
@@ -187503,13 +187697,35 @@ var init_postgres_evaluation = __esm({
187503
187697
  await pool.query(benchmarkSchemaSql(safe));
187504
187698
  return new _PostgresEvaluationRubricStore(pool, safe);
187505
187699
  }
187506
- async listRubrics(companyId) {
187700
+ async listRubrics(companyId, scope = "shared") {
187507
187701
  const result = await this.pool.query(
187508
- `SELECT * FROM ${this.s}.benchmark_rubrics WHERE company_id=$1 ORDER BY name ASC`,
187509
- [companyId]
187702
+ `SELECT * FROM ${this.s}.benchmark_rubrics WHERE company_id=$1 AND scope=$2 ORDER BY name ASC`,
187703
+ [companyId, scope]
187510
187704
  );
187511
187705
  return result.rows.map((row) => toRubric(row));
187512
187706
  }
187707
+ async getCaseRubric(companyId, caseId) {
187708
+ const result = await this.pool.query(
187709
+ `SELECT * FROM ${this.s}.benchmark_rubrics
187710
+ WHERE company_id=$1 AND scope='case' AND owner_case_id=$2`,
187711
+ [companyId, caseId]
187712
+ );
187713
+ return result.rows[0] ? toRubric(result.rows[0]) : null;
187714
+ }
187715
+ async listRubricVersions(rubricId) {
187716
+ const result = await this.pool.query(
187717
+ `SELECT * FROM ${this.s}.benchmark_rubric_versions WHERE rubric_id=$1 ORDER BY version DESC`,
187718
+ [rubricId]
187719
+ );
187720
+ return result.rows.map((row) => toRubricVersion(row));
187721
+ }
187722
+ async getRubricVersion(rubricId, version2) {
187723
+ const result = await this.pool.query(
187724
+ `SELECT * FROM ${this.s}.benchmark_rubric_versions WHERE rubric_id=$1 AND version=$2`,
187725
+ [rubricId, version2]
187726
+ );
187727
+ return result.rows[0] ? toRubricVersion(result.rows[0]) : null;
187728
+ }
187513
187729
  async getRubric(rubricId) {
187514
187730
  const result = await this.pool.query(
187515
187731
  `SELECT * FROM ${this.s}.benchmark_rubrics WHERE rubric_id=$1`,
@@ -187533,15 +187749,18 @@ var init_postgres_evaluation = __esm({
187533
187749
  const status = input.status ?? (existing ? String(existing.status) : "active");
187534
187750
  const createdBy = existing ? String(existing.created_by) : input.actor;
187535
187751
  const createdAt = existing ? iso2(existing.created_at) : at;
187752
+ const scope = input.scope ?? (existing ? String(existing.scope ?? "shared") : "shared");
187753
+ const ownerCaseId = scope === "case" ? input.ownerCaseId ?? (existing?.owner_case_id == null ? null : String(existing.owner_case_id)) : null;
187536
187754
  await client.query(
187537
187755
  `INSERT INTO ${this.s}.benchmark_rubrics
187538
187756
  (rubric_id,company_id,name,kind,description,prompt_section,output_spec,version,status,
187539
- created_by,created_at,updated_by,updated_at)
187540
- VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9,$10,$11,$12,$13)
187757
+ created_by,created_at,updated_by,updated_at,scope,owner_case_id)
187758
+ VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9,$10,$11,$12,$13,$14,$15)
187541
187759
  ON CONFLICT (rubric_id) DO UPDATE SET name=EXCLUDED.name,kind=EXCLUDED.kind,
187542
187760
  description=EXCLUDED.description,prompt_section=EXCLUDED.prompt_section,
187543
187761
  output_spec=EXCLUDED.output_spec,version=EXCLUDED.version,status=EXCLUDED.status,
187544
- updated_by=EXCLUDED.updated_by,updated_at=EXCLUDED.updated_at`,
187762
+ updated_by=EXCLUDED.updated_by,updated_at=EXCLUDED.updated_at,
187763
+ scope=EXCLUDED.scope,owner_case_id=EXCLUDED.owner_case_id`,
187545
187764
  [
187546
187765
  rubricId,
187547
187766
  input.companyId,
@@ -187555,6 +187774,28 @@ var init_postgres_evaluation = __esm({
187555
187774
  createdBy,
187556
187775
  createdAt,
187557
187776
  input.actor,
187777
+ at,
187778
+ scope,
187779
+ ownerCaseId
187780
+ ]
187781
+ );
187782
+ await client.query(
187783
+ `INSERT INTO ${this.s}.benchmark_rubric_versions
187784
+ (rubric_id,version,name,kind,scope,owner_case_id,description,prompt_section,output_spec,
187785
+ created_by,created_at)
187786
+ VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9::jsonb,$10,$11)
187787
+ ON CONFLICT (rubric_id,version) DO NOTHING`,
187788
+ [
187789
+ rubricId,
187790
+ version2,
187791
+ input.name,
187792
+ input.kind,
187793
+ scope,
187794
+ ownerCaseId,
187795
+ input.description ?? null,
187796
+ input.promptSection,
187797
+ JSON.stringify(input.outputSpec),
187798
+ input.actor,
187558
187799
  at
187559
187800
  ]
187560
187801
  );
@@ -188125,6 +188366,14 @@ async function buildChatWhoSection(service, rolesAdmin, humanActorId, selfActorI
188125
188366
  lines.push(`\u60F3\u8FDB\u4E00\u6B65\u4E86\u89E3 TA\u3001\u6216\u6838\u5B9E\u5BF9\u8BDD\u91CC\u63D0\u5230\u7684\u5176\u4ED6\u4EBA\u662F\u8C01\uFF1A\`oasis actor <actorId>\`\uFF08\u5355\u4EBA\u5B8C\u6574\u6863\u6848\uFF09\u3002`);
188126
188367
  return lines;
188127
188368
  }
188369
+ var CHAT_FINAL_REPLY_RULE = [
188370
+ "",
188371
+ "## \u6536\u5C3E\u987A\u5E8F\uFF08\u5C55\u793A\u9762\u5951\u7EA6\uFF09",
188372
+ "",
188373
+ "**\u4F60\u7684\u6700\u540E\u4E00\u6BB5\u6B63\u6587\u5C31\u662F\u7528\u6237\u770B\u5230\u7684\u56DE\u590D**\u2014\u2014\u5728\u5B83\u4E4B\u524D\u7684\u5185\u5BB9\uFF0C\u754C\u9762\u9ED8\u8BA4\u6298\u53E0\u6210\u300C\u601D\u8003\u8FC7\u7A0B\u300D\u3002",
188374
+ "\u6240\u4EE5\uFF1A\u6240\u6709\u6536\u5C3E\u526F\u4F5C\u7528\uFF08`oasis mem-write`\u3001\u6539\u56FE / \u5EFA\u5355\u3001\u53D1\u6D88\u606F\u3001\u5199\u6587\u4EF6\uFF09\u90FD\u5728\u7ED9\u51FA\u56DE\u590D**\u4E4B\u524D**\u505A\u5B8C\uFF1B",
188375
+ "\u505A\u5B8C\u4E4B\u540E\u522B\u518D\u8865\u300C\u5DF2\u4FDD\u5B58 / \u5DF2\u8BB0\u5F55 / \u597D\u7684\u300D\u8FD9\u7C7B\u786E\u8BA4\u53E5\u2014\u2014\u8981\u8BF4\u7684\u4E00\u5E76\u5199\u8FDB\u90A3\u6BB5\u56DE\u590D\u6B63\u6587\u91CC\u3002"
188376
+ ];
188128
188377
  function traceRuntimeKind(runtimeKind) {
188129
188378
  if (runtimeKind === "claude" || runtimeKind === "claude-code") return "claude-code";
188130
188379
  if (runtimeKind === "codex") return "codex";
@@ -189265,7 +189514,9 @@ async function startServe(opts) {
189265
189514
  "## \u7528\u6237\u6D88\u606F",
189266
189515
  "",
189267
189516
  message,
189268
- ...chatMemoryLines
189517
+ ...chatMemoryLines,
189518
+ // 压在最末:这条要盖住紧邻其上的「收工前想一下」,否则记忆写入就落到正文之后(见常量注释)。
189519
+ ...CHAT_FINAL_REPLY_RULE
189269
189520
  ].join("\n")
189270
189521
  };
189271
189522
  Object.assign(files, attachmentFiles);
@@ -191548,14 +191799,18 @@ var USAGE = `oasis \u2014\u2014 artifact-centric \u534F\u4F5C\u5185\u6838 CLI\uF
191548
191799
  evaluate <workOrderId> --case <caseId> [--judge <actorId>] [--case-version <v>] # \u5EFA Run \u5E76\u6392\u961F\u9996\u6B21\u8BC4\u5206
191549
191800
  rescore <runId> [--judge <actorId>] # \u53EA\u65B0\u589E\u4E00\u6B21\u8BC4\u5206\uFF0C\u4E0D\u52A8 Run \u5E8F\u53F7
191550
191801
  judges # \u53EF\u5F53\u5224\u5206\u5458\u5DE5\u7684 agent\uFF08\u53EA\u5217\u6709 active runtime \u7ED1\u5B9A\u7684\uFF09
191551
- rubrics [--kind common|specialty|case_special] # \u8BC4\u5206\u6807\u51C6\u6E05\u5355\uFF08\u4E09\u79CD\u6807\u51C6\u662F\u540C\u4E00\u79CD\u5B9E\u4F53\uFF09
191802
+ rubrics [--kind common|specialty] # **\u5171\u4EAB**\u8BC4\u5206\u6807\u51C6\u6E05\u5355\uFF08\u957F\u671F\u8D44\u4EA7\uFF0C\u53EF\u6302\u591A\u4E2A Case\uFF09
191552
191803
  rubric <rubricId> # \u770B\u4E00\u6761\u6807\u51C6\uFF1A\u8BF4\u660E + \u8F93\u51FA\u5951\u7EA6 + \u6CE8\u5165 prompt \u7684\u6B63\u6587\u5168\u6587
191553
191804
  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]
191554
191805
  # \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
191555
191806
  # { "sectionKey": "common", "aggregation": "none"|"mean", "strictIds": true, "dimensions": [{"id":"G1","label":"\u2026","min":1,"max":5,"nullable":false}] }
191556
191807
  # \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
191557
191808
  rubric-delete <rubricId> # \u5220\u6807\u51C6\uFF08\u6302\u8F7D\u4E86\u5B83\u7684 Case \u540C\u6B65\u6458\u5F15\u7528\uFF09
191558
- 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
191809
+ rubric-versions <rubricId> [--version N] # \u7248\u672C\u5386\u53F2 / \u67D0\u4E00\u7248\u7684\u6B63\u6587\uFF08Run \u8BB0\u7684\u662F id@version\uFF0C\u9760\u5B83\u56DE\u67E5\uFF09
191810
+ case-rubric <caseId> # \u770B\u8FD9\u4E2A Case **\u81EA\u5DF1\u90A3\u6761**\u6807\u51C6\uFF08\u4E0D\u5728\u5171\u4EAB\u767B\u8BB0\u8868\u91CC\uFF09
191811
+ case-rubric-save <caseId> --name <\u540D> (--prompt <\u6587\u672C>|--prompt-file <\u8DEF\u5F84>) [--spec-file <json>] [--kind \u2026]
191812
+ # Case \u7EA7\u6807\u51C6\uFF1A\u53EA\u5C5E\u4E8E\u8FD9\u4E00\u4E2A Case\uFF0C\u6BCF\u5B58\u4E00\u6B21\u51FA\u65B0\u7248\u672C\uFF0C\u540C\u4E00 Case \u6052\u53EA\u6709\u4E00\u6761\u3002
191813
+ case-scoring <caseId> # \u770B\u67D0 Case \u6302\u4E86\u54EA\u51E0\u5957\u5171\u4EAB\u6807\u51C6\u3001Case \u7EA7\u6807\u51C6\u3001\u7531\u8C01\u6253\u5206
191559
191814
  case-scoring-set <caseId> [--rubrics id1,id2] [--judge <actorId>|none]
191560
191815
  # \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
191561
191816
  # \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
@@ -193538,7 +193793,7 @@ ${res.warning}`);
193538
193793
  const kind = flags.get("kind");
193539
193794
  const res = await api.request("GET", "/api/evaluations/rubrics");
193540
193795
  const items = kind ? res.items.filter((r) => r.kind === kind) : res.items;
193541
- println(`\u8BC4\u5206\u6807\u51C6(${items.length}${kind ? ` / kind=${kind}` : ""})\u2014\u2014\u6302\u5230 Case \u7528 \`oasis case-scoring-set\`:`);
193796
+ println(`\u5171\u4EAB\u8BC4\u5206\u6807\u51C6(${items.length}${kind ? ` / kind=${kind}` : ""})\u2014\u2014\u6302\u5230 Case \u7528 \`oasis case-scoring-set\`\uFF1BCase \u81EA\u5DF1\u7684\u6807\u51C6\u89C1 \`oasis case-rubric <caseId>\`:`);
193542
193797
  for (const r of items) {
193543
193798
  println(`- ${r.rubricId} ${r.name} [${r.kind}] v${r.version}${r.status === "archived" ? " [\u5DF2\u5F52\u6863]" : ""}`);
193544
193799
  println(` \u8F93\u51FA\u6BB5=${r.outputSpec.sectionKey} \u7EF4\u5EA6=${r.outputSpec.dimensions.length || "\u7531 Case \u5B9A\u4E49"}${r.description ? ` ${r.description}` : ""}`);
@@ -193590,12 +193845,14 @@ ${res.warning}`);
193590
193845
  );
193591
193846
  println(`Case ${res.caseId} \u8BC4\u5206\u88C5\u914D:`);
193592
193847
  println(` \u5224\u5206\u5458\u5DE5: ${res.judgeActorId ?? "\uFF08\u7528\u90E8\u7F72\u9ED8\u8BA4\uFF09"}`);
193848
+ println(` \u5171\u4EAB\u6807\u51C6(${res.sharedRubrics.length}):`);
193849
+ for (const r of res.sharedRubrics) {
193850
+ println(` - ${r.rubricId} ${r.name} [${r.kind}] v${r.version} \u2192 \u8F93\u51FA\u6BB5 ${r.outputSpec.sectionKey}`);
193851
+ }
193852
+ if (!res.sharedRubrics.length) println(" \uFF08\u65E0\uFF09");
193853
+ println(` Case \u7EA7\u6807\u51C6: ${res.caseRubric ? `${res.caseRubric.rubricId} ${res.caseRubric.name} v${res.caseRubric.version} \u2192 \u8F93\u51FA\u6BB5 ${res.caseRubric.outputSpec.sectionKey}` : "\uFF08\u672A\u5199\uFF0C\u8BE5\u6BB5\u56DE\u843D\u5230 bench \u91CC\u7684 case-special.yaml\uFF09"}`);
193593
193854
  if (res.usesBuiltinFallback) {
193594
- 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");
193595
- } else {
193596
- for (const r of res.rubrics) {
193597
- println(` - ${r.rubricId} ${r.name} [${r.kind}] v${r.version} \u2192 \u8F93\u51FA\u6BB5 ${r.outputSpec.sectionKey}`);
193598
- }
193855
+ println(" \u2192 \u4E24\u8005\u90FD\u7A7A\uFF1A\u6574\u6761\u56DE\u843D\u5230 oasis-bench \u81EA\u5E26\u7684\u4E09\u4EFD\u6750\u6599");
193599
193856
  }
193600
193857
  break;
193601
193858
  }
@@ -193605,7 +193862,7 @@ ${res.warning}`);
193605
193862
  "GET",
193606
193863
  `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`
193607
193864
  );
193608
- const rubricIds = flags.get("rubrics") !== void 0 ? flags.get("rubrics").split(",").map((v2) => v2.trim()).filter(Boolean) : current.rubrics.map((r) => r.rubricId);
193865
+ const rubricIds = flags.get("rubrics") !== void 0 ? flags.get("rubrics").split(",").map((v2) => v2.trim()).filter(Boolean) : current.sharedRubrics.map((r) => r.rubricId);
193609
193866
  const judgeFlag = flags.get("judge");
193610
193867
  const judgeActorId = judgeFlag === void 0 ? current.judgeActorId : judgeFlag === "none" || judgeFlag === "" ? null : judgeFlag;
193611
193868
  const saved = await api.request(
@@ -193613,8 +193870,70 @@ ${res.warning}`);
193613
193870
  `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`,
193614
193871
  { rubricIds, judgeActorId }
193615
193872
  );
193616
- 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"}`);
193617
- if (saved.usesBuiltinFallback) println("\uFF08\u4E00\u6761\u90FD\u6CA1\u6302 = \u4ECD\u8D70 oasis-bench \u56DE\u843D\uFF09");
193873
+ println(`\u5DF2\u66F4\u65B0 Case ${saved.caseId} \u7684\u8BC4\u5206\u88C5\u914D\uFF1A\u5171\u4EAB\u6807\u51C6 ${saved.sharedRubrics.length} \u5957\uFF0CCase \u7EA7\u6807\u51C6 ${saved.caseRubric ? "\u6709" : "\u65E0"}\uFF0C\u5224\u5206\u5458\u5DE5 ${saved.judgeActorId ?? "\u90E8\u7F72\u9ED8\u8BA4"}`);
193874
+ if (saved.usesBuiltinFallback) println("\uFF08\u5171\u4EAB\u4E0E Case \u7EA7\u90FD\u7A7A = \u4ECD\u8D70 oasis-bench \u56DE\u843D\uFF09");
193875
+ break;
193876
+ }
193877
+ case "case-rubric": {
193878
+ const caseId = needPos(positional, 0, "oasis case-rubric <caseId>");
193879
+ const res = await api.request(
193880
+ "GET",
193881
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/scoring`
193882
+ );
193883
+ if (!res.caseRubric) {
193884
+ println(`Case ${caseId} \u8FD8\u6CA1\u6709\u81EA\u5DF1\u7684\u8BC4\u5206\u6807\u51C6\uFF08\u8BE5\u6BB5\u56DE\u843D\u5230 bench \u91CC\u7684 case-special.yaml\uFF09\u3002`);
193885
+ println(`\u5199\u4E00\u6761\uFF1Aoasis case-rubric-save ${caseId} --name <\u540D> --prompt <\u6B63\u6587>`);
193886
+ break;
193887
+ }
193888
+ const r = res.caseRubric;
193889
+ println(`${r.name} [Case \u7EA7 / ${r.kind}] v${r.version} \u5F52\u5C5E ${r.ownerCaseId ?? caseId}`);
193890
+ if (r.description) println(`\u8BF4\u660E: ${r.description}`);
193891
+ println(`\u8F93\u51FA\u5951\u7EA6: ${JSON.stringify(r.outputSpec, null, 2)}`);
193892
+ println("--- \u6CE8\u5165\u5224\u5206 prompt \u7684\u6B63\u6587 ---");
193893
+ println(r.promptSection);
193894
+ break;
193895
+ }
193896
+ case "case-rubric-save": {
193897
+ const caseId = needPos(positional, 0, "oasis case-rubric-save <caseId> --name <\u540D> (--prompt <\u6587\u672C>|--prompt-file <\u8DEF\u5F84>)");
193898
+ const promptSection = flags.get("prompt-file") !== void 0 ? readFileArg(flags.get("prompt-file")) : flags.get("prompt");
193899
+ 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;
193900
+ const body = {};
193901
+ if (promptSection !== void 0) body["promptSection"] = promptSection;
193902
+ if (flags.get("name") !== void 0) body["name"] = flags.get("name");
193903
+ if (flags.get("description") !== void 0) body["description"] = flags.get("description");
193904
+ body["kind"] = flags.get("kind") ?? "case_special";
193905
+ if (outputSpec !== void 0) body["outputSpec"] = outputSpec;
193906
+ else body["outputSpec"] = { sectionKey: "caseSpecial", aggregation: "none", dimensions: [] };
193907
+ const saved = await api.request(
193908
+ "PUT",
193909
+ `/api/evaluations/cases/${encodeURIComponent(caseId)}/rubric`,
193910
+ body
193911
+ );
193912
+ println(`\u5DF2\u4FDD\u5B58 Case ${caseId} \u7684\u8BC4\u5206\u6807\u51C6\uFF1A${saved.rubricId} ${saved.name} v${saved.version}`);
193913
+ break;
193914
+ }
193915
+ case "rubric-versions": {
193916
+ const rubricId = needPos(positional, 0, "oasis rubric-versions <rubricId> [--version N]");
193917
+ const one = flags.get("version");
193918
+ if (one) {
193919
+ const v2 = await api.request(
193920
+ "GET",
193921
+ `/api/evaluations/rubrics/${encodeURIComponent(rubricId)}/versions/${encodeURIComponent(one)}`
193922
+ );
193923
+ println(`${v2.name} [${v2.scope}/${v2.kind}] v${v2.version} \u7531 ${v2.createdBy} \u4E8E ${v2.createdAt}`);
193924
+ println(`\u8F93\u51FA\u5951\u7EA6: ${JSON.stringify(v2.outputSpec, null, 2)}`);
193925
+ println("--- \u8BE5\u7248\u672C\u7684\u6B63\u6587 ---");
193926
+ println(v2.promptSection);
193927
+ break;
193928
+ }
193929
+ const res = await api.request(
193930
+ "GET",
193931
+ `/api/evaluations/rubrics/${encodeURIComponent(rubricId)}/versions`
193932
+ );
193933
+ println(`${rubricId} \u7684\u7248\u672C\u5386\u53F2(${res.items.length}\uFF0C\u65B0\u2192\u65E7):`);
193934
+ for (const v2 of res.items) {
193935
+ println(`- v${v2.version} ${v2.name} \u7531 ${v2.createdBy} \u4E8E ${v2.createdAt}`);
193936
+ }
193618
193937
  break;
193619
193938
  }
193620
193939
  case "judges": {
@@ -193635,7 +193954,12 @@ ${res.warning}`);
193635
193954
  for (const item of items) {
193636
193955
  const e = item.latestEvaluation;
193637
193956
  println(`- ${item.run.runId} ${item.run.workOrderName} case=${item.run.caseId}#${item.run.attemptNo}`);
193638
- 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 ?? "-"}`);
193957
+ println(` \u8BC4\u5206=${e ? `${e.status}${e.errorMessage ? ` (${e.errorMessage})` : ""}` : "\u5C1A\u672A\u8BC4\u5206"} \u5224\u5206\u5458\u5DE5=${e?.judgeActorId ?? "-"}`);
193958
+ if (e?.rubricRefs?.length) {
193959
+ println(` \u672C\u6B21\u6807\u51C6: ${e.rubricRefs.map((r) => `${r.name}@v${r.version}[${r.scope}]`).join(" ")}`);
193960
+ } else if (e) {
193961
+ println(` \u672C\u6B21\u6807\u51C6: ${e.rubricVersion}`);
193962
+ }
193639
193963
  }
193640
193964
  break;
193641
193965
  }
@@ -193882,7 +194206,7 @@ function syncRuntimeAssets(candidateRoots, binDir) {
193882
194206
  }
193883
194207
 
193884
194208
  // src/index.ts
193885
- var PKG_VERSION = true ? "0.1.83" : "dev";
194209
+ var PKG_VERSION = true ? "0.1.84" : "dev";
193886
194210
  var OASIS_DIR = path29.join(os9.homedir(), ".oasis");
193887
194211
  var CONFIG_FILE = path29.join(OASIS_DIR, "node-config.json");
193888
194212
  var PID_FILE = path29.join(OASIS_DIR, "node.pid");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oasis_test",
3
- "version": "0.1.83",
3
+ "version": "0.1.84",
4
4
  "description": "Oasis node daemon + CLI — background daemon, auto-start, full server CLI",
5
5
  "bin": {
6
6
  "oasis": "./dist/index.js"
@@ -26,6 +26,6 @@
26
26
  "node": ">=20"
27
27
  },
28
28
  "oasisRelease": {
29
- "sourceHead": "c7ce25f1bebd2a4974a915641921857db07ec9d1"
29
+ "sourceHead": "79b39bef7a68e1bb8d7135fb8e46efeb9a94b8c7"
30
30
  }
31
31
  }