@roll-agent/browser-use-agent 0.22.2 → 0.23.0

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.
@@ -0,0 +1,56 @@
1
+ import { z } from "zod";
2
+ export declare const PreparedReplyOptionValues: readonly ["option_1", "option_2"];
3
+ export declare const PreparedReplyDecisionSourceValues: readonly ["judge", "orchestrator"];
4
+ export declare const PreparedReplySendDecisionSourceValues: readonly ["judge", "orchestrator", "service_recommended_fallback", "explicit_no_judge"];
5
+ export declare const PreparedReplyFallbackReasons: {
6
+ readonly RUBRIC_FETCH_FAILED: "rubric_fetch_failed";
7
+ readonly RUBRIC_MISMATCH: "rubric_mismatch";
8
+ readonly INVALID_VARIANT_SHAPE: "invalid_variant_shape";
9
+ readonly JUDGE_SAMPLING_FAILED: "judge_sampling_failed";
10
+ readonly JUDGE_OUTPUT_INVALID: "judge_output_invalid";
11
+ };
12
+ export declare const PreparedReplyVariantDecisionSchema: z.ZodObject<{
13
+ chosenOption: z.ZodEnum<["option_1", "option_2"]>;
14
+ reason: z.ZodString;
15
+ confirmedFindingCodes: z.ZodOptional<z.ZodEffects<z.ZodArray<z.ZodEnum<["too_many_questions", "audit_tone", "reply_overpacked", "off_axis_fact_disclosure"]>, "many">, ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[], ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[]>>;
16
+ judgeModel: z.ZodOptional<z.ZodString>;
17
+ }, "strip", z.ZodTypeAny, {
18
+ reason: string;
19
+ chosenOption: "option_1" | "option_2";
20
+ confirmedFindingCodes?: ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[] | undefined;
21
+ judgeModel?: string | undefined;
22
+ }, {
23
+ reason: string;
24
+ chosenOption: "option_1" | "option_2";
25
+ confirmedFindingCodes?: ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[] | undefined;
26
+ judgeModel?: string | undefined;
27
+ }>;
28
+ export declare const JudgeModelOutputSchema: z.ZodObject<{
29
+ reason: z.ZodString;
30
+ chosenOption: z.ZodEnum<["option_1", "option_2"]>;
31
+ } & {
32
+ confirmedFindingCodes: z.ZodEffects<z.ZodArray<z.ZodEnum<["too_many_questions", "audit_tone", "reply_overpacked", "off_axis_fact_disclosure"]>, "many">, ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[], ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[]>;
33
+ }, "strip", z.ZodTypeAny, {
34
+ reason: string;
35
+ confirmedFindingCodes: ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[];
36
+ chosenOption: "option_1" | "option_2";
37
+ }, {
38
+ reason: string;
39
+ confirmedFindingCodes: ("too_many_questions" | "audit_tone" | "reply_overpacked" | "off_axis_fact_disclosure")[];
40
+ chosenOption: "option_1" | "option_2";
41
+ }>;
42
+ export type PreparedReplyOption = (typeof PreparedReplyOptionValues)[number];
43
+ export type PreparedReplyDecisionSource = (typeof PreparedReplyDecisionSourceValues)[number];
44
+ export type PreparedReplySendDecisionSource = (typeof PreparedReplySendDecisionSourceValues)[number];
45
+ export type PreparedReplyFallbackReason = (typeof PreparedReplyFallbackReasons)[keyof typeof PreparedReplyFallbackReasons];
46
+ export type PreparedReplyVariantDecision = z.infer<typeof PreparedReplyVariantDecisionSchema>;
47
+ export type PreparedReplyJudgement = {
48
+ readonly kind: "decision";
49
+ readonly source: PreparedReplyDecisionSource;
50
+ readonly decision: PreparedReplyVariantDecision;
51
+ } | {
52
+ readonly kind: "fallback";
53
+ readonly source: "service_recommended_fallback";
54
+ readonly recommendedOption: PreparedReplyOption;
55
+ readonly reason: PreparedReplyFallbackReason;
56
+ };
@@ -0,0 +1,75 @@
1
+ import { type GenerateReplyToolInput } from "@roll-agent/reply-authority-client";
2
+ import { z } from "zod";
3
+ export declare const PreparedReplyJudgeContextSchema: z.ZodObject<{
4
+ candidateMessage: z.ZodString;
5
+ recentConversation: z.ZodArray<z.ZodString, "many">;
6
+ candidateInfo: z.ZodOptional<z.ZodObject<Pick<{
7
+ name: z.ZodOptional<z.ZodString>;
8
+ position: z.ZodOptional<z.ZodString>;
9
+ expectedPosition: z.ZodOptional<z.ZodString>;
10
+ communicationPosition: z.ZodOptional<z.ZodString>;
11
+ age: z.ZodOptional<z.ZodString>;
12
+ gender: z.ZodOptional<z.ZodString>;
13
+ experience: z.ZodOptional<z.ZodString>;
14
+ education: z.ZodOptional<z.ZodString>;
15
+ expectedSalary: z.ZodOptional<z.ZodString>;
16
+ expectedLocation: z.ZodOptional<z.ZodString>;
17
+ jobAddress: z.ZodOptional<z.ZodString>;
18
+ height: z.ZodOptional<z.ZodString>;
19
+ weight: z.ZodOptional<z.ZodString>;
20
+ healthCertificate: z.ZodOptional<z.ZodBoolean>;
21
+ activeTime: z.ZodOptional<z.ZodString>;
22
+ info: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
23
+ fullText: z.ZodOptional<z.ZodString>;
24
+ }, "info" | "experience" | "age" | "education" | "expectedLocation" | "expectedPosition" | "expectedSalary" | "communicationPosition">, "strip", z.ZodTypeAny, {
25
+ info?: string[] | undefined;
26
+ experience?: string | undefined;
27
+ age?: string | undefined;
28
+ education?: string | undefined;
29
+ expectedLocation?: string | undefined;
30
+ expectedPosition?: string | undefined;
31
+ expectedSalary?: string | undefined;
32
+ communicationPosition?: string | undefined;
33
+ }, {
34
+ info?: string[] | undefined;
35
+ experience?: string | undefined;
36
+ age?: string | undefined;
37
+ education?: string | undefined;
38
+ expectedLocation?: string | undefined;
39
+ expectedPosition?: string | undefined;
40
+ expectedSalary?: string | undefined;
41
+ communicationPosition?: string | undefined;
42
+ }>>;
43
+ preferredBrand: z.ZodOptional<z.ZodString>;
44
+ }, "strip", z.ZodTypeAny, {
45
+ candidateMessage: string;
46
+ recentConversation: string[];
47
+ candidateInfo?: {
48
+ info?: string[] | undefined;
49
+ experience?: string | undefined;
50
+ age?: string | undefined;
51
+ education?: string | undefined;
52
+ expectedLocation?: string | undefined;
53
+ expectedPosition?: string | undefined;
54
+ expectedSalary?: string | undefined;
55
+ communicationPosition?: string | undefined;
56
+ } | undefined;
57
+ preferredBrand?: string | undefined;
58
+ }, {
59
+ candidateMessage: string;
60
+ recentConversation: string[];
61
+ candidateInfo?: {
62
+ info?: string[] | undefined;
63
+ experience?: string | undefined;
64
+ age?: string | undefined;
65
+ education?: string | undefined;
66
+ expectedLocation?: string | undefined;
67
+ expectedPosition?: string | undefined;
68
+ expectedSalary?: string | undefined;
69
+ communicationPosition?: string | undefined;
70
+ } | undefined;
71
+ preferredBrand?: string | undefined;
72
+ }>;
73
+ export type PreparedReplyJudgeContext = z.infer<typeof PreparedReplyJudgeContextSchema>;
74
+ export declare function redactPreparedReplyJudgeText(value: string): string;
75
+ export declare function buildPreparedReplyJudgeContext(input: GenerateReplyToolInput): PreparedReplyJudgeContext;
@@ -1,6 +1,8 @@
1
1
  import type { ReplyGateAdvisoryCode, ReplyVariantKind } from "@roll-agent/reply-authority-client";
2
- export declare const PreparedReplyOptionValues: readonly ["option_1", "option_2"];
3
- export type PreparedReplyOption = (typeof PreparedReplyOptionValues)[number];
2
+ import { PreparedReplyOptionValues, type PreparedReplyFallbackReason, type PreparedReplyJudgement, type PreparedReplyOption } from "./prepared-reply-decision.ts";
3
+ import type { PreparedReplyJudgeContext } from "./prepared-reply-judge-context.ts";
4
+ export { PreparedReplyOptionValues };
5
+ export type { PreparedReplyOption };
4
6
  export type PreparedReplyVariantOption = {
5
7
  readonly option: PreparedReplyOption;
6
8
  readonly variant: ReplyVariantKind;
@@ -12,19 +14,28 @@ export type PreparedReplyVariantFinding = {
12
14
  readonly code: ReplyGateAdvisoryCode;
13
15
  readonly description: string;
14
16
  };
15
- export type PreparedReplyVariantGroup = {
17
+ type PreparedReplyVariantGroupBase = {
16
18
  readonly groupId: string;
17
- readonly options: readonly PreparedReplyVariantOption[];
18
- readonly findings: readonly PreparedReplyVariantFinding[];
19
19
  readonly rubricVersion: string;
20
20
  readonly rubricHash: string;
21
+ readonly feedbackExpiresAt?: number;
21
22
  readonly target: {
22
23
  readonly platform: "zhipin";
23
24
  readonly tenantId: string;
24
25
  readonly conversationId: string;
25
26
  };
26
- readonly recommendedOption: PreparedReplyOption;
27
27
  };
28
+ export type PreparedReplyVariantGroup = (PreparedReplyVariantGroupBase & {
29
+ readonly state: "judge_ready";
30
+ readonly options: readonly PreparedReplyVariantOption[];
31
+ readonly findings: readonly PreparedReplyVariantFinding[];
32
+ readonly recommendedOption: PreparedReplyOption;
33
+ readonly judgeContext: PreparedReplyJudgeContext;
34
+ }) | (PreparedReplyVariantGroupBase & {
35
+ readonly state: "not_learned";
36
+ readonly chosenVariant: "draft";
37
+ readonly reason: PreparedReplyFallbackReason;
38
+ });
28
39
  export type PreparedReplyRecord = {
29
40
  readonly preparedReplyId: string;
30
41
  readonly signedEnvelope: string;
@@ -35,6 +46,7 @@ export type PreparedReplyRecord = {
35
46
  readonly requestId?: string;
36
47
  readonly unreadCountBeforeReply?: number;
37
48
  readonly variantGroup?: PreparedReplyVariantGroup;
49
+ readonly judgement?: PreparedReplyJudgement;
38
50
  };
39
51
  export type PreparedReplyConsumeResult = {
40
52
  readonly ok: true;
@@ -44,7 +56,9 @@ export type PreparedReplyConsumeResult = {
44
56
  readonly reason: "not_found" | "expired" | "consumed";
45
57
  };
46
58
  export type PreparedReplyInspectResult = PreparedReplyConsumeResult;
59
+ export type PreparedReplyJudgementUpdateResult = PreparedReplyConsumeResult;
47
60
  export declare function savePreparedReply(input: Omit<PreparedReplyRecord, "preparedReplyId">, nowSeconds?: number): PreparedReplyRecord;
48
61
  export declare function consumePreparedReply(preparedReplyId: string, nowSeconds?: number): PreparedReplyConsumeResult;
49
62
  export declare function inspectPreparedReply(preparedReplyId: string, nowSeconds?: number): PreparedReplyInspectResult;
63
+ export declare function setPreparedReplyJudgement(preparedReplyId: string, judgement: PreparedReplyJudgement, nowSeconds?: number): PreparedReplyJudgementUpdateResult;
50
64
  export declare function resetPreparedReplyStoreForTests(): void;
@@ -0,0 +1,24 @@
1
+ import { type ReplyFeedbackBody, type ReplyFeedbackResponse } from "@roll-agent/reply-authority-client";
2
+ import { type AgentLogger } from "@roll-agent/sdk";
3
+ export declare const REPLY_FEEDBACK_SUBMISSION_STATUS_VALUES: readonly ["accepted", "duplicate", "queued", "failed"];
4
+ export type ReplyFeedbackSubmissionStatus = (typeof REPLY_FEEDBACK_SUBMISSION_STATUS_VALUES)[number];
5
+ export interface ReplyFeedbackSubmissionResult {
6
+ readonly status: ReplyFeedbackSubmissionStatus;
7
+ readonly error?: string;
8
+ }
9
+ export interface SubmitReplyFeedbackOptions {
10
+ readonly feedbackExpiresAt?: number;
11
+ }
12
+ export type ReplyFeedbackDeliver = (body: ReplyFeedbackBody) => Promise<ReplyFeedbackResponse>;
13
+ export interface InitializeReplyFeedbackOutboxOptions {
14
+ readonly dbPath?: string;
15
+ readonly retentionSeconds?: number;
16
+ readonly flushIntervalMs?: number;
17
+ readonly retryBaseDelayMs?: number;
18
+ readonly authRetryDelayMs?: number;
19
+ readonly deliver?: ReplyFeedbackDeliver;
20
+ readonly logger?: AgentLogger;
21
+ }
22
+ export declare function initializeReplyFeedbackOutbox(options?: InitializeReplyFeedbackOutboxOptions): void;
23
+ export declare function shutdownReplyFeedbackOutbox(): Promise<void>;
24
+ export declare function submitReplyFeedback(body: ReplyFeedbackBody, deliver: ReplyFeedbackDeliver, logger: AgentLogger, options?: SubmitReplyFeedbackOptions): Promise<ReplyFeedbackSubmissionResult>;
@@ -1,8 +1,12 @@
1
+ import { type AgentContext } from "@roll-agent/sdk";
1
2
  import { fetchReplyFeedbackRubric } from "@roll-agent/reply-authority-client";
3
+ import { type PreparedReplyJudgement } from "../reply-authority/prepared-reply-decision.ts";
4
+ import { type PreparedReplyRecord } from "../reply-authority/prepared-reply-store.ts";
2
5
  type ZhipinJudgePreparedReplyDeps = {
3
6
  readonly fetchReplyFeedbackRubric: typeof fetchReplyFeedbackRubric;
4
7
  };
5
8
  export declare function setZhipinJudgePreparedReplyDepsForTests(override: Partial<ZhipinJudgePreparedReplyDeps> | undefined): void;
9
+ export declare function ensurePreparedReplyJudgement(record: PreparedReplyRecord, ctx: AgentContext, judgeModel?: string): Promise<PreparedReplyJudgement>;
6
10
  export declare const zhipinJudgePreparedReply: import("@roll-agent/sdk").ToolDefinition<{
7
11
  preparedReplyId: string;
8
12
  judgeModel?: string | undefined;
@@ -10,6 +14,7 @@ export declare const zhipinJudgePreparedReply: import("@roll-agent/sdk").ToolDef
10
14
  success: boolean;
11
15
  error?: string | undefined;
12
16
  fallback?: boolean | undefined;
17
+ decisionSource?: "judge" | "orchestrator" | "service_recommended_fallback" | "explicit_no_judge" | undefined;
13
18
  recommendedOption?: "option_1" | "option_2" | undefined;
14
19
  variantDecision?: {
15
20
  reason: string;
@@ -1,8 +1,10 @@
1
1
  import { postReplyFeedback } from "@roll-agent/reply-authority-client";
2
+ import { submitReplyFeedback } from "../reply-authority/reply-feedback-outbox.ts";
2
3
  import { sendSignedZhipinReply } from "./zhipin-send-reply.ts";
3
4
  type ZhipinSendPreparedReplyDeps = {
4
5
  readonly sendSignedZhipinReply: typeof sendSignedZhipinReply;
5
6
  readonly postReplyFeedback: typeof postReplyFeedback;
7
+ readonly submitReplyFeedback: typeof submitReplyFeedback;
6
8
  };
7
9
  export declare function setZhipinSendPreparedReplyDepsForTests(override: Partial<ZhipinSendPreparedReplyDeps> | undefined): void;
8
10
  export declare const zhipinSendPreparedReply: import("@roll-agent/sdk").ToolDefinition<{
@@ -19,11 +21,17 @@ export declare const zhipinSendPreparedReply: import("@roll-agent/sdk").ToolDefi
19
21
  toolActionApproval?: {
20
22
  id: string;
21
23
  } | undefined;
24
+ skipVariantJudge?: boolean | undefined;
22
25
  }, {
23
26
  success: boolean;
24
27
  sentMessage: string;
25
28
  error?: string | undefined;
26
- feedbackStatus?: "failed" | "accepted" | "duplicate" | "skipped" | undefined;
29
+ decisionSource?: "judge" | "orchestrator" | "service_recommended_fallback" | "explicit_no_judge" | undefined;
30
+ judgeModel?: string | undefined;
31
+ chosenOption?: "option_1" | "option_2" | undefined;
32
+ decisionReason?: string | undefined;
33
+ feedbackExpected?: boolean | undefined;
34
+ feedbackStatus?: "failed" | "accepted" | "duplicate" | "queued" | "skipped" | undefined;
27
35
  feedbackError?: string | undefined;
28
36
  }>;
29
37
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roll-agent/browser-use-agent",
3
- "version": "0.22.2",
3
+ "version": "0.23.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,7 @@
16
16
  "references"
17
17
  ],
18
18
  "engines": {
19
- "node": ">=22.6.0"
19
+ "node": ">=22.13.0"
20
20
  },
21
21
  "exports": {
22
22
  ".": {
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "zod": "^3.25.76",
48
- "@roll-agent/reply-authority-client": "0.5.0",
48
+ "@roll-agent/reply-authority-client": "0.6.0",
49
49
  "@roll-agent/sdk": "0.3.0",
50
50
  "@roll-agent/browser": "0.9.1"
51
51
  },
@@ -6,7 +6,7 @@ required:
6
6
  example: https://reply-authority.duliday.com
7
7
  - name: REPLY_AUTHORITY_BEARER_TOKEN
8
8
  secret: true
9
- purpose: 调用 Reply Authority Service `POST /generate-signed-reply` 的 Bearer token;只用于生成 prepared reply,不会返回给 orchestrator
9
+ purpose: 调用 Reply Authority Service `POST /generate-signed-reply`、读取冻结 feedback rubric 和 `POST /reply-feedback` 的 Bearer token;必须能访问目标租户并具备 `reply-feedback:write`,不会返回给 orchestrator
10
10
  example: token_xxx
11
11
  - name: REPLY_AUTHORITY_KEYS_URL
12
12
  secret: false
@@ -22,6 +22,23 @@ required:
22
22
  purpose: 招聘事件 Open API Bearer token;公开 npm 包不内置兜底 token,必须由部署环境提供
23
23
  example: token_xxx
24
24
  optional:
25
+ - name: REPLY_FEEDBACK_OUTBOX_DB_PATH
26
+ secret: false
27
+ purpose: browser-use-agent 双稿 feedback SQLite outbox 路径;独立于浏览器 session,容器部署时应挂载到持久卷
28
+ default: ~/.roll-agent/browser/reply-feedback-outbox.sqlite
29
+ example: /data/roll-agent/reply-feedback-outbox.sqlite
30
+ - name: REPLY_FEEDBACK_OUTBOX_RETENTION_SECONDS
31
+ secret: false
32
+ type: number
33
+ purpose: feedback 临时失败后的本地最长重试时间;双稿闭环要求 Reply Authority RFC V3,实际截止时间取服务端 feedbackExpiresAt 与本值的较早者
34
+ default: "604800"
35
+ example: "604800"
36
+ - name: REPLY_FEEDBACK_OUTBOX_FLUSH_INTERVAL_MS
37
+ secret: false
38
+ type: number
39
+ purpose: feedback outbox 后台扫描待重试记录的间隔毫秒数
40
+ default: "30000"
41
+ example: "30000"
25
42
  - name: RECRUITMENT_EVENTS_ENABLED
26
43
  secret: false
27
44
  type: boolean
@@ -185,7 +185,7 @@ recommend-list -> 推荐牛人列表,默认向下滚动,去重主键 candid
185
185
 
186
186
  ## Reply Authority
187
187
 
188
- `zhipin_send_prepared_reply` 只接受 `zhipin_generate_reply_preview` 生成的 `preparedReplyId`,内部再取回 Reply Authority Service 签发的 envelope 并完成验签。
188
+ `zhipin_send_prepared_reply` 只接受 `zhipin_generate_reply_preview` 生成的 `preparedReplyId`,从 prepared store 读取预览阶段保存的 Reply Authority 签名 envelope 并完成验签。
189
189
 
190
190
  发送前校验:
191
191
 
@@ -218,7 +218,46 @@ recommend-list -> 推荐牛人列表,默认向下滚动,去重主键 candid
218
218
  }
219
219
  ```
220
220
 
221
- 第二种代理模式由 `smart-reply-agent` 调用 Reply Authority resolver 解析 `tenantId + recruiterBinding`。
221
+ 第二种代理模式由当前 Agent 使用的共享 `reply-authority-client` 先调用 Reply Authority resolver,解析出 `tenantId + recruiterBinding`;`browser-use-agent` 与 `smart-reply-agent` 都能独立完成该解析,不需要为了 resolver 在两者之间跳转。
222
+
223
+ ### RFC V3 双稿反馈闭环
224
+
225
+ 当前 browser-use 双稿链路要求 Reply Authority RFC V3;部署顺序必须是 **Reply Authority V3 → 新版 browser-use-agent**。调用方 token 必须能访问目标租户并具备 `reply-feedback:write`。
226
+
227
+ ```text
228
+ preview 保存 group / rubric / feedbackExpiresAt
229
+ -> send 内部 Judge,或复用独立 Judge / orchestrator 显式选择
230
+ -> 发送一份签名 option
231
+ -> 将 selected 或 not_learned 终态写入 SQLite outbox
232
+ -> POST /reply-feedback
233
+ ```
234
+
235
+ | `feedbackOutcome` | `decisionSource` | Beta 学习 | Pending |
236
+ | --- | --- | --- | --- |
237
+ | `selected` | `judge` / `orchestrator` | 更新 | 闭合 |
238
+ | `not_learned` | `service_recommended_fallback` / `explicit_no_judge` | 不更新 | 闭合 |
239
+
240
+ `zhipin_judge_prepared_reply` 只是可选预览工具;默认直接调用 send 即可,send 会在双稿缺少 `variantDecision` 时确定性执行并缓存 Judge。若 preview 阶段 rubric 拉取、hash 或双稿结构异常,prepared store 会保留 group 生命周期元数据;send 发送顶层推荐稿成功后提交 `not_learned`,不会让服务端 Pending 静默过期。
241
+
242
+ 发送后的 feedback 状态:
243
+
244
+ | `feedbackStatus` | 用户消息 | feedback 闭环 | 后续动作 |
245
+ | --- | --- | --- | --- |
246
+ | `accepted` / `duplicate` | 已发送 | 已闭合 | 无需处理 |
247
+ | `queued` | 已发送 | 等待 outbox 重试 | 不重调 send;等待 outbox 仅重试 POST |
248
+ | `failed` | 已发送 | 有缺口 | 不重调 send;修复 token、服务或 outbox 后单独排查 |
249
+
250
+ `feedbackExpected:false` 只表示 fallback/no-Judge 不进入 Beta 学习,不表示无需终态。outbox 的实际重试截止时间取服务端 `feedbackExpiresAt` 与本地 retention 的较早值。
251
+
252
+ 跨服务 fallback 只使用稳定安全码,原始 provider / HTTP / parser 错误只留在 browser-use-agent 本地日志:
253
+
254
+ | Code | 含义 |
255
+ | --- | --- |
256
+ | `rubric_fetch_failed` | rubric 获取失败 |
257
+ | `rubric_mismatch` | rubric version/hash 不一致 |
258
+ | `invalid_variant_shape` | 服务端双稿结构无法安全判定 |
259
+ | `judge_sampling_failed` | MCP Sampling 调用失败 |
260
+ | `judge_output_invalid` | Judge 输出无法验证 |
222
261
 
223
262
  ## 推荐候选人链路
224
263