@roll-agent/smart-reply-agent 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SKILL.md CHANGED
@@ -37,6 +37,13 @@ npm 包名:`@roll-agent/smart-reply-agent`
37
37
  1. 直接传完整绑定:`tenantId + recruiterBinding`
38
38
  2. 便利代理模式:`recruiterUsername`(smart-reply 会先调用 `POST /resolve-recruiter-binding` 解析出 `tenantId + recruiterBinding`)
39
39
 
40
+ 招聘场景调用约束:
41
+
42
+ - 调用前应先尝试从页面读取 `candidateInfo.communicationPosition`、`candidateInfo.expectedLocation`、`candidateInfo.expectedPosition`
43
+ - 能读到就如实透传;读不到就省略该字段
44
+ - `preferredBrand` 为可选页面信号:若 `browser-use-agent` 提取到的 `communicationPosition` 含连字符类分隔符(`-` / `-` / `—` / `–`),则取第一段透传;没有分隔符就省略该字段
45
+ - 严禁把通用岗位名(如“餐饮兼职服务员”“门店服务员”)或候选人现/前雇主公司名塞进 `preferredBrand`
46
+
40
47
  Minimal valid input 示例(代理模式):
41
48
 
42
49
  ```json
@@ -75,23 +82,31 @@ npm 包名:`@roll-agent/smart-reply-agent`
75
82
  - 实际回复生成、reply-policy、FactGate、ReplyGate、年龄校验都在云端执行
76
83
  - 返回的 `signedEnvelope` 为 v2 信封,已绑定 `tenantId + recruiterBinding + conversationId + candidateId`,供 `browser-use-agent.zhipin_send_reply` 本地验签后发送
77
84
  - 调用失败时抛 `ReplyAuthorityRequestError`,携带 `meta: {url, timeoutMs, requestId}` 与 `Error.cause` 链。通过 `roll run` 运行时 stderr 会展开 `cause: ...` 行用于定位;透传的 `x-request-id` 可跨服务端追踪
85
+ - `diagnostics.brandResolutionSource="none"`、`diagnostics.resolvedBrand=""`、`diagnostics.ageGate.status="unknown"` 都是合法服务端结果,不代表 tool 调用失败。是否补问用户或转人工,是 orch 层策略,不是本 Agent 的重试条件
78
86
 
79
87
  ## Environment Variables
80
88
 
81
89
  机器可读的 env 契约见 `references/env.yaml`。如果你是上层编排 Agent,请优先读取它来生成/校验 `agents.env.smart-reply-agent` 配置。
82
90
 
83
- - `REPLY_AUTHORITY_URL` — Reply Authority Service 基础地址
84
- - `REPLY_AUTHORITY_BEARER_TOKEN` — 调用 `POST /generate-signed-reply` 的 Bearer token
91
+ - `REPLY_AUTHORITY_URL` — Reply Authority Service 基础地址(必填)
92
+ - `REPLY_AUTHORITY_BEARER_TOKEN` — 调用 `POST /generate-signed-reply` 的 Bearer token(必填)
93
+ - `REPLY_AUTHORITY_TIMEOUT_MS` — Reply Authority Service HTTP 请求超时毫秒数(可选,默认 `30000`)。非正整数或非法值会被静默忽略并回落到默认值
85
94
 
86
95
  ## 典型跨 Agent 工作流
87
96
 
88
97
  1. `browser-use-agent.zhipin_get_username()` → 获取当前 BOSS 账号 `username`
89
98
  2. `browser-use-agent` 读取候选人资料、聊天记录或当前页面上下文,并从 `zhipin_read_messages` / `zhipin_get_candidate_info` 获取 `conversationId + candidateId`
90
- 3. 调用 `smart-reply-agent.generate_reply(..., target)`:
99
+ 3. 调用前先尝试补齐页面信号:
100
+ - `candidateInfo.communicationPosition`
101
+ - `candidateInfo.expectedLocation`
102
+ - `candidateInfo.expectedPosition`
103
+ - `preferredBrand`:若 `browser-use-agent` 从 `communicationPosition` 里识别到“品牌-职位”格式,则透传第一段;否则保持缺省
104
+ - 如果读不到,保持缺省;不要用通用岗位名或候选人公司名冒充品牌
105
+ 4. 调用 `smart-reply-agent.generate_reply(..., target)`:
91
106
  - 直接模式:传 `target.tenantId + target.recruiterBinding`
92
107
  - 代理模式:只传 `target.recruiterUsername=username`,由 smart-reply 代调用 `POST /resolve-recruiter-binding`
93
- 4. `smart-reply-agent.generate_reply(..., target)` 获取 `suggestedReply + signedEnvelope`
94
- 5. `browser-use-agent.zhipin_send_reply(signedEnvelope)` 本地验签并校验 recruiter 绑定后发送
108
+ 5. `smart-reply-agent.generate_reply(..., target)` 获取 `suggestedReply + signedEnvelope`
109
+ 6. `browser-use-agent.zhipin_send_reply(signedEnvelope)` 本地验签并校验 recruiter 绑定后发送
95
110
 
96
111
  ## Recommended roll.config.yaml
97
112
 
@@ -103,4 +118,6 @@ agents:
103
118
  smart-reply-agent:
104
119
  REPLY_AUTHORITY_URL: https://reply-authority.duliday.com
105
120
  REPLY_AUTHORITY_BEARER_TOKEN: ${REPLY_AUTHORITY_BEARER_TOKEN}
121
+ # 可选:自定义 HTTP 超时(毫秒,默认 30000)
122
+ # REPLY_AUTHORITY_TIMEOUT_MS: "45000"
106
123
  ```
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- export declare const SMART_REPLY_DECLARED_ENV_KEYS: readonly ["REPLY_AUTHORITY_URL", "REPLY_AUTHORITY_BEARER_TOKEN"];
2
+ export declare const SMART_REPLY_DECLARED_ENV_KEYS: readonly ["REPLY_AUTHORITY_URL", "REPLY_AUTHORITY_BEARER_TOKEN", "REPLY_AUTHORITY_TIMEOUT_MS"];
3
3
  export declare const EffectiveEnvSourceSchema: z.ZodObject<{
4
4
  present: z.ZodBoolean;
5
5
  fingerprint: z.ZodOptional<z.ZodString>;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{defineAgent as e}from"@roll-agent/sdk";import{defineTool as t}from"@roll-agent/sdk";import{z as r}from"zod";import{createHash as n}from"node:crypto";import{z as i}from"zod";var o=["REPLY_AUTHORITY_URL","REPLY_AUTHORITY_BEARER_TOKEN"],a=/^[0-9a-f]{8}$/,s=i.object({present:i.boolean(),fingerprint:i.string().regex(a).optional()}),c=i.record(s);function d(e,t=process.env){return Object.fromEntries(e.map(e=>{const r=t[e];return"string"==typeof r&&r.length>0?[e,{present:!0,fingerprint:u(r)}]:[e,{present:!1}]}))}function u(e){return n("sha256").update(e).digest("hex").slice(0,8)}var g=r.object({effectiveEnvSources:c}),l=t({name:"diagnostic_status",description:"返回 smart-reply 运行态进程中已声明环境变量的存在状态与短指纹",input:r.object({}),output:g,execute:async(e,t)=>(t.logger.info("Querying smart-reply diagnostic status"),{effectiveEnvSources:d(o)})});import{defineTool as p}from"@roll-agent/sdk";import{randomUUID as m}from"node:crypto";import{z as f}from"zod";import{z as y}from"zod";var I=y.object({name:y.string(),baseURL:y.string(),description:y.string()}),h=y.record(y.string(),I),b=y.object({chatModel:y.string().optional(),classifyModel:y.string().optional(),replyModel:y.string().optional(),providerConfigs:h.optional()});import{z as v}from"zod";var R=["trust_building","private_channel","qualify_candidate","job_consultation","interview_scheduling","onboard_followup"],w=v.enum(R);import{z as S}from"zod";var E=S.object({name:S.string().optional(),position:S.string().optional(),expectedPosition:S.string().optional(),communicationPosition:S.string().optional(),age:S.string().optional(),gender:S.string().optional(),experience:S.string().optional(),education:S.string().optional(),expectedSalary:S.string().optional(),expectedLocation:S.string().optional(),jobAddress:S.string().optional(),height:S.string().optional(),weight:S.string().optional(),healthCertificate:S.boolean().optional(),activeTime:S.string().optional(),info:S.array(S.string()).optional(),fullText:S.string().optional()}),B=f.object({platform:f.literal("zhipin"),username:f.string().min(1),accountId:f.string().min(1).optional()}),A=f.object({platform:f.literal("zhipin"),tenantId:f.string().min(1).optional(),conversationId:f.string().min(1),candidateId:f.string().min(1)}),T=A.extend({recruiterBinding:B.optional(),recruiterUsername:f.string().min(1).optional()}).superRefine((e,t)=>{const r=void 0!==e.recruiterBinding,n=void 0!==e.recruiterUsername;r||n||t.addIssue({code:f.ZodIssueCode.custom,message:"target.recruiterBinding 或 target.recruiterUsername 至少需要提供一个。",path:["recruiterBinding"]}),r&&!n&&void 0===e.tenantId&&t.addIssue({code:f.ZodIssueCode.custom,message:"直接传 target.recruiterBinding 时,target.tenantId 也必须显式提供。",path:["tenantId"]}),r&&n&&void 0!==e.recruiterBinding&&e.recruiterBinding.username!==e.recruiterUsername&&t.addIssue({code:f.ZodIssueCode.custom,message:"target.recruiterUsername 必须与 target.recruiterBinding.username 一致。",path:["recruiterUsername"]})}),x=A.extend({tenantId:f.string().min(1),recruiterBinding:B}),j=f.object({candidateMessage:f.string().describe("候选人发送的消息"),conversationHistory:f.array(f.string()).optional().describe("对话历史(最近几轮)"),candidateInfo:E.optional().describe("候选人基本信息"),preferredBrand:f.string().optional().describe("偏好品牌"),channelType:f.enum(["public","private"]).optional().describe("渠道类型: public(BOSS直聘) 或 private(微信)"),defaultWechatId:f.string().optional().describe("默认微信号"),industryVoiceId:f.string().optional().describe("行业语调ID"),turnIndex:f.number().int().min(1).optional().describe("当前会话回复轮次"),modelConfig:b.optional().describe("模型配置覆盖"),target:T.describe("签名绑定目标:租户、会话和候选人标识")}),q=j.omit({target:!0}).extend({target:x,requestId:f.string().optional()}),U=f.object({suggestedReply:f.string(),signedEnvelope:f.string().describe("Reply Authority Service v2 紧凑签名信封"),envelopeExp:f.number().int(),confidence:f.number(),stage:w,replyPolicySource:f.enum(["file","default"]),latencyMs:f.number().optional(),shouldExchangeWechat:f.boolean().optional(),error:f.string().optional(),diagnostics:f.record(f.unknown()).optional()}),_=f.object({platform:f.literal("zhipin"),username:f.string().min(1),accountId:f.string().min(1).optional()}),$=f.object({tenantId:f.string().min(1),recruiterBinding:B}),z=f.object({statusCode:f.number().int(),error:f.string(),message:f.string()}),O=2e4,P=class extends Error{meta;constructor(e,t){super(`${e} (${H(t.meta)})`,{cause:t.cause}),this.name="ReplyAuthorityRequestError",this.meta=t.meta}};function M(e){const t=process.env[e]?.trim();if(!t)throw new Error(`${e} 未配置,smart-reply-agent 无法调用 Reply Authority Service。`);return t}function C(){return{baseUrl:M("REPLY_AUTHORITY_URL"),bearerToken:M("REPLY_AUTHORITY_BEARER_TOKEN")}}function L(e,t){const r=e.endsWith("/")?e:`${e}/`;return new URL(t,r).toString()}function Y(e,t){return{"Content-Type":"application/json",Authorization:`Bearer ${e.bearerToken}`,"x-request-id":t.requestId}}function k(e,t){const r=z.safeParse(t);return r.success?`Reply Authority Service 请求失败 (${e}): ${r.data.message}`:`Reply Authority Service 请求失败 (${e})`}function H(e){const t=[`url=${e.url}`,`timeoutMs=${String(e.timeoutMs)}`];return void 0!==e.requestId&&t.push(`requestId=${e.requestId}`),t.join(", ")}function N(e,t,r){return{url:L(e.baseUrl,t),timeoutMs:r.timeoutMs,requestId:r.requestId}}function J(e,t){return e instanceof P?e:e instanceof Error&&"AbortError"===e.name?new P("Reply Authority Service 请求超时。",{cause:e,meta:t}):e instanceof Error?new P(e.message,{cause:e,meta:t}):new P("Reply Authority Service 请求失败。",{cause:e,meta:t})}function W(e,t,r,n){const i=e.safeParse(t);if(i.success)return i.data;throw new P(`${n} 响应校验失败。`,{cause:i.error,meta:r})}async function Z(e){const t=await e.text();if(0===t.trim().length)return null;try{return JSON.parse(t)}catch{throw new Error("Reply Authority Service 返回了非 JSON 响应。")}}async function K(e,t,r,n){const i=N(e,t,n);try{const t=await fetch(i.url,{method:"POST",headers:Y(e,n),body:JSON.stringify(r),signal:n.signal}),o=await Z(t);if(!t.ok)throw new Error(k(t.status,o));return o}catch(e){throw J(e,i)}}function D(e){return _.parse({platform:e.platform,username:e.recruiterUsername})}async function F(e,t,r){const n=D(t),i=await K(e,"resolve-recruiter-binding",n,r);return W($,i,N(e,"resolve-recruiter-binding",r),"Reply Authority Service recruiter 解析")}function Q(e,t,r){if(void 0!==t.tenantId&&t.tenantId!==e.tenantId)throw new P(`Reply Authority Service recruiter 解析结果与 target.tenantId 不一致:${e.tenantId}`,{meta:r});return{tenantId:e.tenantId,recruiterBinding:e.recruiterBinding}}async function V(e,t,r){if(void 0!==e.target.recruiterBinding&&void 0!==e.target.tenantId)return q.parse({...e,target:{platform:e.target.platform,tenantId:e.target.tenantId,conversationId:e.target.conversationId,candidateId:e.target.candidateId,recruiterBinding:e.target.recruiterBinding},requestId:r.requestId});const n=Q(await F(t,e.target,r),e.target,N(t,"resolve-recruiter-binding",r));return q.parse({...e,target:{platform:e.target.platform,tenantId:n.tenantId,conversationId:e.target.conversationId,candidateId:e.target.candidateId,recruiterBinding:n.recruiterBinding},requestId:r.requestId})}async function G(e){const t=j.parse(e),r=q.safeParse(t),n=C(),i=new AbortController,o={signal:i.signal,timeoutMs:O,requestId:m()},a=setTimeout(()=>i.abort(),O);try{const e=r.success?q.parse({...r.data,requestId:r.data.requestId??o.requestId}):await V(t,n,o),i=await K(n,"generate-signed-reply",e,o);return W(U,i,N(n,"generate-signed-reply",o),"Reply Authority Service 签名回复")}finally{clearTimeout(a)}}var X=p({name:"generate_reply",description:"根据候选人消息生成智能招聘回复,并向 Reply Authority Service 请求签名信封;调用方必须提供 target 以绑定会话和招聘者身份,可直接传 tenantId+recruiterBinding,或只传 recruiterUsername 交给 smart-reply 代理解析。",input:j,output:U,execute:async(e,t)=>{t.logger.info(`Processing message: ${e.candidateMessage.slice(0,50)}...`);const r=await G(e);return t.logger.info(`Signed reply generated. Stage: ${r.stage}, Confidence: ${r.confidence}`),r}}),ee=e({name:"smart-reply-agent",tools:[X,l]});ee.listen().catch(e=>{console.error("Fatal error:",e),process.exit(1)});
1
+ import{defineAgent as e}from"@roll-agent/sdk";import{defineTool as t}from"@roll-agent/sdk";import{z as r}from"zod";import{createHash as n}from"node:crypto";import{z as i}from"zod";var o=["REPLY_AUTHORITY_URL","REPLY_AUTHORITY_BEARER_TOKEN","REPLY_AUTHORITY_TIMEOUT_MS"],a=/^[0-9a-f]{8}$/,s=i.object({present:i.boolean(),fingerprint:i.string().regex(a).optional()}),c=i.record(s);function u(e,t=process.env){return Object.fromEntries(e.map(e=>{const r=t[e];return"string"==typeof r&&r.length>0?[e,{present:!0,fingerprint:d(r)}]:[e,{present:!1}]}))}function d(e){return n("sha256").update(e).digest("hex").slice(0,8)}var g=r.object({effectiveEnvSources:c}),l=t({name:"diagnostic_status",description:"返回 smart-reply 运行态进程中已声明环境变量的存在状态与短指纹",input:r.object({}),output:g,execute:async(e,t)=>(t.logger.info("Querying smart-reply diagnostic status"),{effectiveEnvSources:u(o)})});import{defineTool as p}from"@roll-agent/sdk";import{randomUUID as m}from"node:crypto";import{z as f}from"zod";import{z as I}from"zod";var y=I.object({name:I.string(),baseURL:I.string(),description:I.string()}),b=I.record(I.string(),y),h=I.object({chatModel:I.string().optional(),classifyModel:I.string().optional(),replyModel:I.string().optional(),providerConfigs:b.optional()});import{z as v}from"zod";var R=["trust_building","private_channel","qualify_candidate","job_consultation","interview_scheduling","onboard_followup"],w=v.enum(R);import{z as E}from"zod";var S=E.object({name:E.string().optional(),position:E.string().optional(),expectedPosition:E.string().optional(),communicationPosition:E.string().optional(),age:E.string().optional(),gender:E.string().optional(),experience:E.string().optional(),education:E.string().optional(),expectedSalary:E.string().optional(),expectedLocation:E.string().optional(),jobAddress:E.string().optional(),height:E.string().optional(),weight:E.string().optional(),healthCertificate:E.boolean().optional(),activeTime:E.string().optional(),info:E.array(E.string()).optional(),fullText:E.string().optional()}),T=f.object({platform:f.literal("zhipin"),username:f.string().min(1),accountId:f.string().min(1).optional()}),A=f.object({platform:f.literal("zhipin"),tenantId:f.string().min(1).optional(),conversationId:f.string().min(1),candidateId:f.string().min(1)}),_=A.extend({recruiterBinding:T.optional(),recruiterUsername:f.string().min(1).optional()}).superRefine((e,t)=>{const r=void 0!==e.recruiterBinding,n=void 0!==e.recruiterUsername;r||n||t.addIssue({code:f.ZodIssueCode.custom,message:"target.recruiterBinding 或 target.recruiterUsername 至少需要提供一个。",path:["recruiterBinding"]}),r&&!n&&void 0===e.tenantId&&t.addIssue({code:f.ZodIssueCode.custom,message:"直接传 target.recruiterBinding 时,target.tenantId 也必须显式提供。",path:["tenantId"]}),r&&n&&void 0!==e.recruiterBinding&&e.recruiterBinding.username!==e.recruiterUsername&&t.addIssue({code:f.ZodIssueCode.custom,message:"target.recruiterUsername 必须与 target.recruiterBinding.username 一致。",path:["recruiterUsername"]})}),B=A.extend({tenantId:f.string().min(1),recruiterBinding:T}),U=f.object({candidateMessage:f.string().describe("候选人发送的消息"),conversationHistory:f.array(f.string()).optional().describe("对话历史(最近几轮)"),candidateInfo:S.optional().describe("候选人基本信息"),preferredBrand:f.string().optional().describe("偏好品牌"),channelType:f.enum(["public","private"]).optional().describe("渠道类型: public(BOSS直聘) 或 private(微信)"),defaultWechatId:f.string().optional().describe("默认微信号"),industryVoiceId:f.string().optional().describe("行业语调ID"),turnIndex:f.number().int().min(1).optional().describe("当前会话回复轮次"),modelConfig:h.optional().describe("模型配置覆盖"),target:_.describe("签名绑定目标:租户、会话和候选人标识")}),x=U.omit({target:!0}).extend({target:B,requestId:f.string().optional()}),j=f.object({suggestedReply:f.string(),signedEnvelope:f.string().describe("Reply Authority Service v2 紧凑签名信封"),envelopeExp:f.number().int(),confidence:f.number(),stage:w,replyPolicySource:f.enum(["file","default"]),latencyMs:f.number().optional(),shouldExchangeWechat:f.boolean().optional(),error:f.string().optional(),diagnostics:f.record(f.unknown()).optional()}),q=f.object({platform:f.literal("zhipin"),username:f.string().min(1),accountId:f.string().min(1).optional()}),$=f.object({tenantId:f.string().min(1),recruiterBinding:T}),O=f.object({statusCode:f.number().int(),error:f.string(),message:f.string()}),z=3e4;function M(){const e=process.env.REPLY_AUTHORITY_TIMEOUT_MS?.trim();if(!e)return z;const t=Number.parseInt(e,10);return!Number.isInteger(t)||t<=0||String(t)!==e?z:t}var P=class extends Error{meta;constructor(e,t){super(`${e} (${N(t.meta)})`,{cause:t.cause}),this.name="ReplyAuthorityRequestError",this.meta=t.meta}};function Y(e){const t=process.env[e]?.trim();if(!t)throw new Error(`${e} 未配置,smart-reply-agent 无法调用 Reply Authority Service。`);return t}function L(){return{baseUrl:Y("REPLY_AUTHORITY_URL"),bearerToken:Y("REPLY_AUTHORITY_BEARER_TOKEN")}}function C(e,t){const r=e.endsWith("/")?e:`${e}/`;return new URL(t,r).toString()}function k(e,t){return{"Content-Type":"application/json",Authorization:`Bearer ${e.bearerToken}`,"x-request-id":t.requestId}}function H(e,t){const r=O.safeParse(t);return r.success?`Reply Authority Service 请求失败 (${e}): ${r.data.message}`:`Reply Authority Service 请求失败 (${e})`}function N(e){const t=[`url=${e.url}`,`timeoutMs=${String(e.timeoutMs)}`];return void 0!==e.requestId&&t.push(`requestId=${e.requestId}`),t.join(", ")}function J(e,t,r){return{url:C(e.baseUrl,t),timeoutMs:r.timeoutMs,requestId:r.requestId}}function W(e,t){return e instanceof P?e:e instanceof Error&&"AbortError"===e.name?new P("Reply Authority Service 请求超时。",{cause:e,meta:t}):e instanceof Error?new P(e.message,{cause:e,meta:t}):new P("Reply Authority Service 请求失败。",{cause:e,meta:t})}function Z(e,t,r,n){const i=e.safeParse(t);if(i.success)return i.data;throw new P(`${n} 响应校验失败。`,{cause:i.error,meta:r})}async function K(e){const t=await e.text();if(0===t.trim().length)return null;try{return JSON.parse(t)}catch{throw new Error("Reply Authority Service 返回了非 JSON 响应。")}}async function D(e,t,r,n){const i=J(e,t,n);try{const t=await fetch(i.url,{method:"POST",headers:k(e,n),body:JSON.stringify(r),signal:n.signal}),o=await K(t);if(!t.ok)throw new Error(H(t.status,o));return o}catch(e){throw W(e,i)}}function F(e){return q.parse({platform:e.platform,username:e.recruiterUsername})}async function Q(e,t,r){const n=F(t),i=await D(e,"resolve-recruiter-binding",n,r);return Z($,i,J(e,"resolve-recruiter-binding",r),"Reply Authority Service recruiter 解析")}function V(e,t,r){if(void 0!==t.tenantId&&t.tenantId!==e.tenantId)throw new P(`Reply Authority Service recruiter 解析结果与 target.tenantId 不一致:${e.tenantId}`,{meta:r});return{tenantId:e.tenantId,recruiterBinding:e.recruiterBinding}}async function G(e,t,r){if(void 0!==e.target.recruiterBinding&&void 0!==e.target.tenantId)return x.parse({...e,target:{platform:e.target.platform,tenantId:e.target.tenantId,conversationId:e.target.conversationId,candidateId:e.target.candidateId,recruiterBinding:e.target.recruiterBinding},requestId:r.requestId});const n=V(await Q(t,e.target,r),e.target,J(t,"resolve-recruiter-binding",r));return x.parse({...e,target:{platform:e.target.platform,tenantId:n.tenantId,conversationId:e.target.conversationId,candidateId:e.target.candidateId,recruiterBinding:n.recruiterBinding},requestId:r.requestId})}async function X(e){const t=U.parse(e),r=x.safeParse(t),n=L(),i=M(),o=new AbortController,a={signal:o.signal,timeoutMs:i,requestId:m()},s=setTimeout(()=>o.abort(),i);try{const e=r.success?x.parse({...r.data,requestId:r.data.requestId??a.requestId}):await G(t,n,a),i=await D(n,"generate-signed-reply",e,a);return Z(j,i,J(n,"generate-signed-reply",a),"Reply Authority Service 签名回复")}finally{clearTimeout(s)}}var ee=p({name:"generate_reply",description:"根据候选人消息生成智能招聘回复,并向 Reply Authority Service 请求签名信封;调用方必须提供 target 以绑定会话和招聘者身份,可直接传 tenantId+recruiterBinding,或只传 recruiterUsername 交给 smart-reply 代理解析。",input:U,output:j,execute:async(e,t)=>{t.logger.info(`Processing message: ${e.candidateMessage.slice(0,50)}...`);const r=await X(e);return t.logger.info(`Signed reply generated. Stage: ${r.stage}, Confidence: ${r.confidence}`),r}}),te=e({name:"smart-reply-agent",tools:[ee,l]});te.listen().catch(e=>{console.error("Fatal error:",e),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roll-agent/smart-reply-agent",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -5,3 +5,8 @@ required:
5
5
  - name: REPLY_AUTHORITY_BEARER_TOKEN
6
6
  purpose: Reply Authority Service Bearer token;服务端据此反查 clientId 并校验可访问的 tenantId
7
7
  example: ${REPLY_AUTHORITY_BEARER_TOKEN}
8
+ optional:
9
+ - name: REPLY_AUTHORITY_TIMEOUT_MS
10
+ purpose: Reply Authority Service HTTP 请求超时(毫秒)。未设置或值无效时回落默认 30000
11
+ example: "30000"
12
+ default: "30000"