@roll-agent/browser-use-agent 0.22.1 → 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.1",
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,9 +45,9 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "zod": "^3.25.76",
48
+ "@roll-agent/reply-authority-client": "0.6.0",
48
49
  "@roll-agent/sdk": "0.3.0",
49
- "@roll-agent/browser": "0.9.1",
50
- "@roll-agent/reply-authority-client": "0.5.0"
50
+ "@roll-agent/browser": "0.9.1"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "^22.0.0"
@@ -1,47 +1,88 @@
1
1
  required:
2
2
  - name: REPLY_AUTHORITY_URL
3
+ secret: false
4
+ type: url
3
5
  purpose: Reply Authority Service API base URL;`zhipin_generate_reply_preview` 使用 SSE 直接生成并展示回复
4
6
  example: https://reply-authority.duliday.com
5
7
  - name: REPLY_AUTHORITY_BEARER_TOKEN
6
- purpose: 调用 Reply Authority Service `POST /generate-signed-reply` 的 Bearer token;只用于生成 prepared reply,不会返回给 orchestrator
8
+ secret: true
9
+ purpose: 调用 Reply Authority Service `POST /generate-signed-reply`、读取冻结 feedback rubric 和 `POST /reply-feedback` 的 Bearer token;必须能访问目标租户并具备 `reply-feedback:write`,不会返回给 orchestrator
7
10
  example: token_xxx
8
11
  - name: REPLY_AUTHORITY_KEYS_URL
12
+ secret: false
13
+ type: url
9
14
  purpose: Reply Authority Service 公钥分发端点;`zhipin_send_prepared_reply` 启动预热和本地 Ed25519 验签都依赖它
10
15
  example: https://reply-authority.duliday.com/.well-known/reply-authority-keys
11
16
  - name: RECRUITMENT_EVENTS_DEFAULT_AGENT_ID
17
+ secret: false
12
18
  purpose: 单 browser-use 实例 / 单 Boss 账号部署下的默认招聘业务 Agent ID;多 browser.instances 下仅作为实例缺少 trackingAgentId 时的 fallback;招聘事件默认启用,上报时必须有可解析归因
13
19
  example: zhipin-shanghai-kfc-001
14
20
  - name: RECRUITMENT_EVENTS_API_TOKEN
21
+ secret: true
15
22
  purpose: 招聘事件 Open API Bearer token;公开 npm 包不内置兜底 token,必须由部署环境提供
16
23
  example: token_xxx
17
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"
18
42
  - name: RECRUITMENT_EVENTS_ENABLED
43
+ secret: false
44
+ type: boolean
19
45
  purpose: 是否启用招聘事件埋点上报;未设置时默认启用,设为 `"false"` 可关闭
20
46
  default: "true"
21
47
  example: "false"
22
48
  - name: RECRUITMENT_EVENTS_API_BASE_URL
49
+ secret: false
50
+ type: url
23
51
  purpose: 招聘事件 Open API base URL;工具成功后会调用 `/api/v1/recruitment-events`
24
52
  default: https://huajune.duliday.com
25
53
  example: https://example.com
26
54
  - name: BROWSER_SECURITY_JSON
55
+ secret: false
56
+ type: json
27
57
  purpose: 浏览器安全策略 JSON;可配置 domainAllowlist、maxPageContentBytes、maxSnapshotNodes、actionPolicy、foregroundPolicy;foregroundPolicy 默认 when-minimized,无需显式配置
28
58
  default: '{"domainAllowlist":[],"maxPageContentBytes":102400,"maxSnapshotNodes":500,"actionPolicy":"log","foregroundPolicy":"when-minimized"}'
29
59
  example: '{"domainAllowlist":["zhipin.com"],"maxPageContentBytes":102400,"maxSnapshotNodes":500,"actionPolicy":"log","foregroundPolicy":"when-minimized"}'
30
60
  - name: BROWSER_USE_POLICY_JSON
61
+ secret: false
62
+ type: json
31
63
  purpose: browser-use 工具级业务策略 JSON;可按 exact tool name 配置 log、deny、confirm
32
64
  default: '{"approvalTtlMs":300000,"tools":{}}'
33
65
  example: '{"approvalTtlMs":300000,"tools":{"zhipin_send_prepared_reply":{"policy":"confirm"}}}'
34
66
  - name: BROWSER_PROFILE_COLOR
67
+ secret: false
35
68
  purpose: legacy 单浏览器运行时的 Chrome profile 颜色,格式为 `#RRGGBB`;配置了 `browser.instances` 时由每个实例的 profileColor 接管,此 env 会被忽略
36
69
  example: "#2563EB"
37
70
  - name: BROWSER_INSTANCES_JSON
71
+ secret: false
72
+ type: json
73
+ configurable: false
74
+ sourcePath: [browser, instances]
38
75
  purpose: Roll core 注入的多浏览器实例声明 JSON;由 `browser.instances` 派生,包含每个实例的 profile、CDP 端口、session 目录、可选 profileName/profileColor/windowBounds 和招聘事件归因 ID;orchestrator 不应手工拼接,手工配置时必须保持 cdpPort/userDataDir 唯一
39
76
  example: '{"defaultInstance":"boss-a","instances":{"boss-a":{"platform":"zhipin","mode":"managed-cdp","cdpPort":9222,"userDataDir":"/tmp/roll-browser/profiles/boss-a","profileName":"boss-a","profileColor":"#2563EB","windowBounds":{"x":0,"y":0,"width":680,"height":1000},"trackingAgentId":"zhipin-boss-a"}}}'
40
77
  - name: BROWSER_VISUAL_CURSOR
78
+ secret: false
79
+ type: boolean
41
80
  purpose: 在可见浏览器页面内显示 browser-use 的页内虚拟指针和点击波纹;默认开启,设为 `"false"` 可关闭
42
81
  default: "true"
43
82
  example: "false"
44
83
  - name: BROWSER_VISUAL_ACTIVITY
84
+ secret: false
85
+ type: boolean
45
86
  purpose: 在消息读取、账号识别、聊天详情提取等非点击型操作期间显示页内状态胶囊、区域柔光和完成态反馈;默认开启,设为 `"false"` 可关闭
46
87
  default: "true"
47
88
  example: "true"
@@ -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