@roll-agent/smart-reply-agent 0.3.0 → 0.4.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.
package/SKILL.md CHANGED
@@ -32,13 +32,13 @@ npm 包名:`@roll-agent/smart-reply-agent`
32
32
  ## Tools
33
33
 
34
34
  - `generate_reply(candidateMessage, conversationHistory?, candidateInfo?, preferredBrand?, channelType?, defaultWechatId?, industryVoiceId?, turnIndex?, modelConfig?)`
35
- 根据候选人消息生成智能回复,返回建议回复文本、置信度、漏斗阶段和诊断信息。适用于“已拿到消息内容,想生成怎么回”的场景。内部流程:回合规划 → primaryNeed 驱动上下文构建 → 年龄资格校验 → 策略化回复生成 → FactGate/ReplyGate 校验。
35
+ 根据候选人消息生成智能回复,返回建议回复文本、置信度、漏斗阶段和诊断信息。输出包含 `replyPolicySource`(`”file”` = 自定义配置, `”default”` = 内置默认策略),调用方据此判断当前回复是否受自定义策略驱动。内部流程:回合规划 → primaryNeed 驱动上下文构建 → 年龄资格校验 → 策略化回复生成 → FactGate/ReplyGate 校验。
36
36
  - `sync_brand_data(cityName, brandAlias?)`
37
37
  从 Duliday API 拉取并同步品牌配置数据(门店、岗位、薪资等)到本地。`cityName` 为必填城市名称,`brandAlias` 为可选品牌过滤。适用于首次初始化、定期刷新或切换城市/品牌数据源的场景。
38
38
 
39
39
  ## Reply Policy(回复策略配置)
40
40
 
41
- 回复行为由 `data/reply-policy.json` 驱动。上层编排器应只修改文档化字段,不要添加自定义字段;未声明字段不属于稳定契约,可能被忽略。完整字段说明见 [references/reply-policy-schema.md](./references/reply-policy-schema.md)。
41
+ 回复行为由 `data/reply-policy.json` 驱动。文件不存在时回退到内置默认策略(`generate_reply` 输出 `replyPolicySource: "default"` 可识别)。上层编排器应只修改文档化字段,不要添加自定义字段;未声明字段不属于稳定契约,可能被忽略。完整字段说明见 [references/reply-policy-schema.md](./references/reply-policy-schema.md)。
42
42
 
43
43
  主要可配置维度:
44
44
  - **stageGoals** — 6 个漏斗阶段各自的目标、成功标准和推进策略
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{defineAgent as e}from"@roll-agent/sdk";import{defineTool as n}from"@roll-agent/sdk";import{z as t}from"zod";import{z as r}from"zod";import{z as a}from"zod";var o=a.object({lat:a.number(),lng:a.number()}),i=r.object({name:r.string().optional(),position:r.string().optional(),expectedPosition:r.string().optional(),communicationPosition:r.string().optional(),age:r.string().optional(),gender:r.string().optional(),experience:r.string().optional(),education:r.string().optional(),expectedSalary:r.string().optional(),expectedLocation:r.string().optional(),jobAddress:r.string().optional(),height:r.string().optional(),weight:r.string().optional(),healthCertificate:r.boolean().optional(),activeTime:r.string().optional(),info:r.array(r.string()).optional(),fullText:r.string().optional()}),s=r.object({base:r.number().nullable(),unit:r.string().nullable(),range:r.string().optional(),bonus:r.string().optional(),memo:r.string().nullable(),scenarioSummary:r.string().optional(),settlementCycle:r.string().optional()}),l=r.object({insurance:r.string().nullable(),accommodation:r.string().nullable(),catering:r.string().nullable(),moreWelfares:r.array(r.string()).nullable(),memo:r.string().nullable(),promotion:r.string().nullable()}),u=r.object({requiredDays:r.array(r.number().min(1).max(7)).optional(),minimumDays:r.number().min(0).nullable(),description:r.string().nullable()}),c=r.object({slot:r.string(),maxCapacity:r.number().min(0),currentBooked:r.number().min(0),isAvailable:r.boolean(),priority:r.enum(["high","medium","low"])}),d=r.object({minAge:r.number().nullable().optional(),maxAge:r.number().nullable().optional(),genderRequirement:r.string().nullable().optional(),education:r.string().nullable().optional(),healthCertificate:r.string().nullable().optional(),languages:r.string().nullable().optional(),certificatesRaw:r.string().nullable().optional(),recruitmentRemark:r.string().nullable().optional(),socialIdentity:r.string().nullable().optional()}),m=r.object({id:r.string(),name:r.string(),sourceJobName:r.string(),jobCategory:r.string().nullable(),brandId:r.string().optional(),brandName:r.string().optional(),projectId:r.string().optional(),projectName:r.string().optional(),description:r.string().nullable(),laborForm:r.string().nullable(),employmentForm:r.string().nullable(),trainingRequired:r.string().nullable(),probationRequired:r.string().nullable(),salary:s,timeSlots:r.array(r.string()),workHours:r.string().nullable(),minHoursPerWeek:r.number().min(0).nullable(),maxHoursPerWeek:r.number().min(0).nullable(),perMonthMinWorkTime:r.number().nullable(),perMonthMinWorkTimeUnit:r.union([r.string(),r.number()]).nullable(),attendanceRequirement:u.optional(),availableSlots:r.array(c),benefits:l,hiringRequirements:d.optional()}),p=r.object({id:r.string(),brandId:r.string(),name:r.string(),city:r.string().optional(),location:r.string(),district:r.string().nullable(),subarea:r.string().nullable(),coordinates:o,positions:r.array(m)}),g=r.object({defaultBrandId:r.string().optional(),syncedAt:r.string().optional(),source:r.string().optional()}),f=r.object({id:r.string(),name:r.string(),aliases:r.array(r.string()).optional(),stores:r.array(p)}),y=r.object({meta:g,brands:r.array(f)});import{existsSync as b,readFileSync as h,writeFileSync as N}from"node:fs";import{dirname as S,join as T}from"node:path";import{z as A}from"zod";var I=A.enum(["trust_building","private_channel","qualify_candidate","job_consultation","interview_scheduling","onboard_followup"]),_=A.enum(["public","private"]),E=A.enum(["minimal","focused"]),R=A.enum(["salary","schedule","location","policy","requirements","availability"]),L={trust_building:{description:"初次接触,建立信任并了解求职意向",transitionSignal:"候选人表达明确兴趣或开始询问具体岗位信息",applicableChannels:["public","private"]},private_channel:{description:"引导用户从公域平台(如BOSS直聘/鱼泡)转入微信私聊",transitionSignal:"候选人有继续深入了解的意愿,适合引导到私域",applicableChannels:["public"]},qualify_candidate:{description:"轻量确认候选人的关键匹配信息,避免审查式盘问",transitionSignal:"候选人表达求职意向后,需要核实基本资格",applicableChannels:["public","private"]},job_consultation:{description:"回答岗位相关问题(薪资、排班、地点等)并提升兴趣",transitionSignal:"候选人主动询问岗位细节",applicableChannels:["public","private"]},interview_scheduling:{description:"推动面试预约,确认时间和到店安排",transitionSignal:"候选人核心问题已解答,准备推进面试",applicableChannels:["public","private"]},onboard_followup:{description:"促进到岗并保持回访",transitionSignal:"候选人确认上岗安排",applicableChannels:["public","private"]}},O=A.enum(["stores","location","salary","schedule","policy","availability","requirements","interview","wechat","none"]),k=A.enum(["insurance_promise_risk","age_sensitive","confrontation_emotion","urgency_high","qualification_mismatch"]),M={stores:["location"],location:["location"],salary:["salary"],schedule:["schedule"],policy:["policy"],availability:["availability"],requirements:["requirements"],interview:[],wechat:[],none:[]},v=A.object({mentionedBrand:A.string().nullable(),city:A.string().nullable(),mentionedLocations:A.array(A.object({location:A.string(),confidence:A.number().min(0).max(1)})).nullable(),mentionedDistricts:A.array(A.object({district:A.string(),confidence:A.number().min(0).max(1)})).max(10).nullable(),specificAge:A.number().nullable(),hasUrgency:A.boolean().nullable(),preferredSchedule:A.string().nullable()}),w=A.object({stage:I,subGoals:A.array(A.string()).max(2),needs:A.array(O).max(8),primaryNeed:O,riskFlags:A.array(k).max(6),confidence:A.number().min(0).max(1),extractedInfo:v,reasoningText:A.string()}),D=A.object({description:A.string().optional(),primaryGoal:A.string(),successCriteria:A.array(A.string()),ctaStrategy:A.preprocess(e=>Array.isArray(e)?e.join("\n"):e,A.string()),disallowedActions:A.array(A.string()).optional()}),C=A.object({tone:A.string(),warmth:A.string(),humor:A.string(),length:A.enum(["short","medium","long"]),questionStyle:A.string(),empathyStrategy:A.string(),addressStyle:A.string(),professionalIdentity:A.string(),companyBackground:A.string()}),U=A.object({name:A.string(),industryBackground:A.string(),jargon:A.array(A.string()),styleKeywords:A.array(A.string()),tabooPhrases:A.array(A.string()),guidance:A.array(A.string())}),x=A.object({id:A.string(),rule:A.string(),severity:A.enum(["high","medium","low"])}),$=A.object({rules:A.array(x)}),j=A.object({mode:A.enum(["strict","balanced","open"]),verifiableClaimTypes:A.array(A.string()),fallbackBehavior:A.enum(["generic_answer","ask_followup","handoff"]),forbiddenWhenMissingFacts:A.array(A.string())}),W={maxQuestionsByMode:{minimal:1,focused:2},blockedAuditPhrases:["是否满足","是否符合","基本入职要求","先确认资格","年龄是否符合"],blockFirstTurnSpecificFacts:!0},F=A.object({maxQuestionsByMode:A.object({minimal:A.number().int().min(0),focused:A.number().int().min(0)}),blockedAuditPhrases:A.array(A.string()),blockFirstTurnSpecificFacts:A.boolean()}),P=A.object({enabled:A.boolean().default(!0),revealRange:A.boolean().default(!1),failStrategy:A.string().default("礼貌说明不匹配,避免承诺"),unknownStrategy:A.string().default("先核实年龄或资格条件"),passStrategy:A.string().default("确认匹配后推进下一步"),allowRedirect:A.boolean().default(!0),redirectPriority:A.enum(["low","medium","high"]).default("medium")}),B=A.object({age:P.default({enabled:!0,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!0,redirectPriority:"medium"})}).default({age:{enabled:!0,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!0,redirectPriority:"medium"}}),G=A.object({trust_building:D,private_channel:D.optional(),qualify_candidate:D,job_consultation:D,interview_scheduling:D,onboard_followup:D}).transform(e=>({...e,private_channel:e.private_channel??e.trust_building})),q=A.object({stageGoals:G,persona:C,industryVoices:A.record(A.string(),U),defaultIndustryVoiceId:A.string(),hardConstraints:$,factGate:j,qualificationPolicy:B,outputGuards:F.default(W)}),H={stageGoals:{trust_building:{description:"初次接触,建立信任并了解求职意向",primaryGoal:"建立信任并了解求职意向",successCriteria:["候选人愿意继续沟通"],ctaStrategy:"用轻量提问引导需求细化",disallowedActions:["过早承诺具体待遇"]},private_channel:{description:"引导用户从公域平台(如BOSS直聘/鱼泡)转入微信私聊",primaryGoal:"推动进入私域沟通",successCriteria:["候选人愿意交换联系方式"],ctaStrategy:"说明后续沟通效率与资料同步价值",disallowedActions:["强迫式要微信"]},qualify_candidate:{description:"轻量确认候选人的关键匹配信息,避免审查式盘问",primaryGoal:"确认一个关键匹配信息并保持继续沟通意愿",successCriteria:["明确一个关键匹配信息","候选人愿意继续沟通"],ctaStrategy:"先回应关切,再顺带确认一个最关键条件",disallowedActions:["连续盘问多个资格条件","直接否定候选人"]},job_consultation:{description:"回答岗位相关问题(薪资、排班、地点等)并提升兴趣",primaryGoal:"回答岗位问题并提升兴趣",successCriteria:["候选人对岗位保持兴趣"],ctaStrategy:"先答核心问题,再给下一步建议",disallowedActions:["编造数字或政策"]},interview_scheduling:{description:"推动面试预约,确认时间和到店安排",primaryGoal:"推动面试预约",successCriteria:["候选人给出可面试时间"],ctaStrategy:"给出明确时间选项并确认",disallowedActions:["不确认候选人可到店性"]},onboard_followup:{description:"促进到岗并保持回访",primaryGoal:"促进到岗并保持回访",successCriteria:["候选人确认上岗安排"],ctaStrategy:"明确下一步动作与提醒",disallowedActions:["承诺不确定资源"]}},persona:{tone:"口语化",warmth:"高",humor:"低",length:"short",questionStyle:"单轮一个关键问题",empathyStrategy:"先认可关切再给建议",addressStyle:"使用你",professionalIdentity:"资深招聘专员",companyBackground:"连锁餐饮招聘"},industryVoices:{default:{name:"餐饮连锁招聘",industryBackground:"门店密集、排班灵活、强调稳定出勤",jargon:["排班","到岗","门店","班次"],styleKeywords:["直接","清晰","可信"],tabooPhrases:["包过","绝对","随便都行"],guidance:["先解决顾虑,再推动下一步"]}},defaultIndustryVoiceId:"default",hardConstraints:{rules:[{id:"no-fabrication",rule:"不得编造门店、薪资、排班、福利等事实信息",severity:"high"},{id:"no-insurance-promise",rule:"兼职场景不得承诺五险一金",severity:"high"},{id:"age-sensitive",rule:"年龄敏感问题使用合规话术,不暴露内部筛选线",severity:"high"}]},factGate:{mode:"strict",verifiableClaimTypes:["salary","location","schedule","policy","availability"],fallbackBehavior:"generic_answer",forbiddenWhenMissingFacts:["具体数字","具体门店承诺","明确福利承诺"]},qualificationPolicy:{age:{enabled:!0,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!0,redirectPriority:"medium"}},outputGuards:W};function K(e){let n=e;for(;;){if(b(T(n,"package.json")))return n;const t=S(n);if(t===n)throw new Error(`Could not locate package root from ${e}`);n=t}}var V=T(K(import.meta.dirname),"data"),z=T(V,"brand-config.json"),Y=T(V,"reply-policy.json"),J=3e5,Q=null,Z=null;function X(e){return Date.now()-e<J}function ee(){if(Q&&X(Q.loadedAt))return Q.data;const e=h(z,"utf-8"),n=y.parse(JSON.parse(e));return Q={data:n,loadedAt:Date.now()},n}function ne(e){N(z,JSON.stringify(e,null,2),"utf-8"),Q={data:e,loadedAt:Date.now()}}function te(){if(Z&&X(Z.loadedAt))return Z.data;try{const e=h(Y,"utf-8"),n=q.parse(JSON.parse(e));return Z={data:n,loadedAt:Date.now()},n}catch{return H}}import{createAnthropic as re}from"@ai-sdk/anthropic";import{createAlibaba as ae}from"@ai-sdk/alibaba";import{createProviderRegistry as oe}from"ai";import{createOpenAICompatible as ie}from"@ai-sdk/openai-compatible";import{createDeepSeek as se}from"@ai-sdk/deepseek";import{createGoogleGenerativeAI as le}from"@ai-sdk/google";import{createOpenAI as ue}from"@ai-sdk/openai";var ce=!1;function de(e){ce=e}function me(...e){ce||console.error(...e)}var pe=process.env.SMART_REPLY_PROXY_BASE_URL,ge="https://apic1.ohmycdn.com/v1",fe=pe||ge,ye={anthropic:process.env.ANTHROPIC_BASE_URL||fe,openai:process.env.OPENAI_BASE_URL||fe,ohmygpt:process.env.OHMYGPT_BASE_URL||fe,moonshotai:process.env.MOONSHOT_BASE_URL||"https://api.moonshot.cn/v1",deepseek:process.env.DEEPSEEK_BASE_URL||"https://api.deepseek.com",qwen:process.env.QWEN_BASE_URL||"https://dashscope.aliyuncs.com/compatible-mode/v1",google:process.env.GOOGLE_BASE_URL||"https://generativelanguage.googleapis.com/v1beta"},be={anthropic:{name:"Anthropic",baseURL:ye.anthropic,description:"Anthropic Claude"},openai:{name:"OpenAI",baseURL:ye.openai,description:"OpenAI GPT"},ohmygpt:{name:"OhMyGPT",baseURL:ye.ohmygpt,description:"OhMyGPT"},moonshotai:{name:"MoonshotAI",baseURL:ye.moonshotai,description:"MoonshotAI"},deepseek:{name:"DeepSeek",baseURL:ye.deepseek,description:"DeepSeek"},qwen:{name:"Qwen",baseURL:ye.qwen,description:"Qwen"},google:{name:"Google",baseURL:ye.google,description:"Google Gemini"}},he={chatModel:"anthropic/claude-haiku-4-5",classifyModel:process.env.SMART_REPLY_CLASSIFY_MODEL||"openai/gpt-5-mini",replyModel:process.env.SMART_REPLY_REPLY_MODEL||"openai/gpt-5.4"};function Ne(){return process.env.ANTHROPIC_API_KEY||process.env.OPENAI_API_KEY||""}function Se(e){const n=ue({apiKey:e.apiKey||"",...void 0!==e.baseURL?{baseURL:e.baseURL}:{}});return new Proxy(n,{get(e,t){if("languageModel"===t)return e=>n.chat(e);if("chat"===t||"completion"===t)return n[t];if("embeddingModel"===t||"imageModel"===t){return n[t]||void 0}return n[t]}})}function Te(e){const n=Ne();return oe({anthropic:re({apiKey:n,baseURL:e.anthropic?.baseURL||ye.anthropic}),openai:Se({apiKey:n,baseURL:e.openai?.baseURL||ye.openai}),ohmygpt:ie({name:"ohmygpt",baseURL:e.ohmygpt?.baseURL||ye.ohmygpt,apiKey:n}),moonshotai:ie({name:"moonshotai",baseURL:e.moonshotai?.baseURL||ye.moonshotai,apiKey:process.env.MOONSHOT_API_KEY||""}),deepseek:se({baseURL:e.deepseek?.baseURL||ye.deepseek,apiKey:process.env.DEEPSEEK_API_KEY||""}),google:le({apiKey:process.env.GEMINI_API_KEY||"",baseURL:e.google?.baseURL||ye.google}),qwen:ae({apiKey:process.env.DASHSCOPE_API_KEY||process.env.ALIBABA_API_KEY||"",baseURL:e.qwen?.baseURL||ye.qwen})},{separator:"/"})}var Ae=null,Ie=null;function _e(e){const n=JSON.stringify(e);return Ae&&Ie===n||(Ae=Te(e),Ie=n,me("[DYNAMIC REGISTRY] 创建新的动态registry,配置哈希:",n.substring(0,16)+"...")),Ae}function Ee(e){return e.brands.flatMap(e=>e.stores)}function Re(e){return e.brands.map(e=>e.name)}function Le(e,n){if(n)return e.brands.find(e=>e.name===n)}function Oe(e){if(e.meta.defaultBrandId){const n=e.brands.find(n=>n.id===e.meta.defaultBrandId);if(n)return n}return e.brands[0]}function ke(e){return Oe(e)?.name??""}function Me(e,n){const t=n?Le(e,n)?.stores??[]:Ee(e);return t.find(e=>"string"==typeof e.city&&e.city.trim().length>0)?.city}import{z as ve}from"zod";var we=6e4,De=200,Ce=2e4,Ue=null,xe=null;function $e(){const e=process.env.DULIDAY_JOB_LIST_URL;return"string"==typeof e&&e.trim().length>0?e:void 0}function je(){const e=process.env.DULIDAY_TOKEN;return"string"==typeof e&&e.trim().length>0?e:void 0}function We(e){return(e??"").trim()}function Fe(e){const n=We(e);if(!n)return[];const t=new Set([n]);return n.endsWith("市")?t.add(n.slice(0,-1)):t.add(`${n}市`),Array.from(t).filter(Boolean)}function Pe(e,n){const t=We(e);if(!t)return[];const r=new Set([t]),a=Fe(n);for(const e of a)if(t.startsWith(e)){const n=t.slice(e.length).trim();n&&r.add(n)}return Array.from(r).filter(Boolean)}var Be=ve.object({data:ve.object({result:ve.array(ve.unknown()).optional(),list:ve.array(ve.unknown()).optional(),total:ve.number().optional()}).nullable().optional(),result:ve.array(ve.unknown()).optional()});function Ge(e){const n=Be.safeParse(e);if(!n.success)return{items:[],total:0};const t=n.data,r=t.data?.result??t.data?.list??(Array.isArray(t.result)?t.result:[]),a=t.data?.total??(Array.isArray(r)?r.length:0);return{items:Array.isArray(r)?r:[],total:"number"==typeof a?a:0}}var qe={includeBasicInfo:!0,includeJobSalary:!0,includeWelfare:!0,includeHiringRequirement:!0,includeWorkTime:!0},He={includeBasicInfo:!0,includeHiringRequirement:!0};async function Ke(e,n,t,r,a){const o="test"!==process.env.NODE_ENV,i=Pe(a?.brandAlias,a?.cityName),s=Fe(a?.cityName),l=a?.include??He,u=JSON.stringify({token:e,brandCandidates:i,cityCandidates:s,pageNum:t,includeOpts:l}),c=Date.now();if(o&&Ue&&Ue.cacheKey===u&&c-Ue.fetchedAt<we)return Ue.payload;if(o&&xe?.cacheKey===u)return xe.promise;const d=(async()=>{const a=new AbortController,o=setTimeout(()=>a.abort(),Ce),c={};i.length>0&&(c.brandAliasList=i),s.length>0&&(c.cityNameList=s);const d={pageNum:t,pageSize:r,queryParam:c,options:l};try{const t=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json","Duliday-Token":e},body:JSON.stringify(d),signal:a.signal});if(!t.ok)throw new Error(`Duliday job list fetch failed: ${t.status}`);const r=await t.json();return Ue={cacheKey:u,payload:r,fetchedAt:Date.now()},r}finally{clearTimeout(o),xe=null}})();return o&&(xe={cacheKey:u,promise:d}),d}async function Ve(e,n,t){const r=[];let a=1,o=0;for(;;){const i=Ge(await Ke(e,n,a,De,t));if(1===a&&(o=i.total),r.push(...i.items),i.items.length<De||r.length>=o)break;a+=1}return{items:r,total:o}}import{z as ze}from"zod";import{setTimeout as Ye,clearTimeout as Je}from"node:timers";import{performance as Qe}from"node:perf_hooks";import{asSchema as Ze,generateText as Xe,jsonSchema as en,NoObjectGeneratedError as nn,Output as tn}from"ai";import"zod";var rn={CONFIG:"CONFIG",AUTH:"AUTH",NETWORK:"NETWORK",LLM:"LLM",VALIDATION:"VALIDATION",BUSINESS:"BUSINESS",SYSTEM:"SYSTEM"},an={LLM_UNAUTHORIZED:"LLM_UNAUTHORIZED",LLM_MODEL_NOT_FOUND:"LLM_MODEL_NOT_FOUND",LLM_RATE_LIMITED:"LLM_RATE_LIMITED",LLM_TIMEOUT:"LLM_TIMEOUT",LLM_GENERATION_FAILED:"LLM_GENERATION_FAILED",LLM_RESPONSE_PARSE_ERROR:"LLM_RESPONSE_PARSE_ERROR",CONFIG_NOT_FOUND:"CONFIG_NOT_FOUND",CONFIG_INVALID:"CONFIG_INVALID",CONFIG_MISSING_FIELD:"CONFIG_MISSING_FIELD",CONFIG_LOAD_FAILED:"CONFIG_LOAD_FAILED",NETWORK_TIMEOUT:"NETWORK_TIMEOUT",NETWORK_CONNECTION_FAILED:"NETWORK_CONNECTION_FAILED",NETWORK_HTTP_ERROR:"NETWORK_HTTP_ERROR",NETWORK_DNS_FAILED:"NETWORK_DNS_FAILED",AUTH_UNAUTHORIZED:"AUTH_UNAUTHORIZED",AUTH_FORBIDDEN:"AUTH_FORBIDDEN",AUTH_TOKEN_EXPIRED:"AUTH_TOKEN_EXPIRED",AUTH_TOKEN_INVALID:"AUTH_TOKEN_INVALID",VALIDATION_INVALID_INPUT:"VALIDATION_INVALID_INPUT",VALIDATION_MISSING_REQUIRED:"VALIDATION_MISSING_REQUIRED",VALIDATION_FORMAT_ERROR:"VALIDATION_FORMAT_ERROR",VALIDATION_SCHEMA_ERROR:"VALIDATION_SCHEMA_ERROR",BUSINESS_RULE_VIOLATION:"BUSINESS_RULE_VIOLATION",BUSINESS_RESOURCE_NOT_FOUND:"BUSINESS_RESOURCE_NOT_FOUND",BUSINESS_RESOURCE_EXISTS:"BUSINESS_RESOURCE_EXISTS",BUSINESS_OPERATION_NOT_ALLOWED:"BUSINESS_OPERATION_NOT_ALLOWED",SYSTEM_INTERNAL:"SYSTEM_INTERNAL",SYSTEM_DEPENDENCY_FAILED:"SYSTEM_DEPENDENCY_FAILED",SYSTEM_RESOURCE_UNAVAILABLE:"SYSTEM_RESOURCE_UNAVAILABLE",SYSTEM_UNKNOWN:"SYSTEM_UNKNOWN"},on={[an.LLM_UNAUTHORIZED]:rn.LLM,[an.LLM_MODEL_NOT_FOUND]:rn.LLM,[an.LLM_RATE_LIMITED]:rn.LLM,[an.LLM_TIMEOUT]:rn.LLM,[an.LLM_GENERATION_FAILED]:rn.LLM,[an.LLM_RESPONSE_PARSE_ERROR]:rn.LLM,[an.CONFIG_NOT_FOUND]:rn.CONFIG,[an.CONFIG_INVALID]:rn.CONFIG,[an.CONFIG_MISSING_FIELD]:rn.CONFIG,[an.CONFIG_LOAD_FAILED]:rn.CONFIG,[an.NETWORK_TIMEOUT]:rn.NETWORK,[an.NETWORK_CONNECTION_FAILED]:rn.NETWORK,[an.NETWORK_HTTP_ERROR]:rn.NETWORK,[an.NETWORK_DNS_FAILED]:rn.NETWORK,[an.AUTH_UNAUTHORIZED]:rn.AUTH,[an.AUTH_FORBIDDEN]:rn.AUTH,[an.AUTH_TOKEN_EXPIRED]:rn.AUTH,[an.AUTH_TOKEN_INVALID]:rn.AUTH,[an.VALIDATION_INVALID_INPUT]:rn.VALIDATION,[an.VALIDATION_MISSING_REQUIRED]:rn.VALIDATION,[an.VALIDATION_FORMAT_ERROR]:rn.VALIDATION,[an.VALIDATION_SCHEMA_ERROR]:rn.VALIDATION,[an.BUSINESS_RULE_VIOLATION]:rn.BUSINESS,[an.BUSINESS_RESOURCE_NOT_FOUND]:rn.BUSINESS,[an.BUSINESS_RESOURCE_EXISTS]:rn.BUSINESS,[an.BUSINESS_OPERATION_NOT_ALLOWED]:rn.BUSINESS,[an.SYSTEM_INTERNAL]:rn.SYSTEM,[an.SYSTEM_DEPENDENCY_FAILED]:rn.SYSTEM,[an.SYSTEM_RESOURCE_UNAVAILABLE]:rn.SYSTEM,[an.SYSTEM_UNKNOWN]:rn.SYSTEM},sn={[an.LLM_UNAUTHORIZED]:"AI 服务认证失败,请检查配置",[an.LLM_MODEL_NOT_FOUND]:"所选模型暂时不可用,请尝试其他模型",[an.LLM_RATE_LIMITED]:"请求过于频繁,请稍后重试",[an.LLM_TIMEOUT]:"AI 响应超时,请稍后重试",[an.LLM_GENERATION_FAILED]:"内容生成失败,请稍后重试",[an.LLM_RESPONSE_PARSE_ERROR]:"AI 响应格式异常,请重试",[an.CONFIG_NOT_FOUND]:"配置数据未找到,请先进行初始化",[an.CONFIG_INVALID]:"配置格式无效,请检查配置",[an.CONFIG_MISSING_FIELD]:"配置缺少必需字段",[an.CONFIG_LOAD_FAILED]:"配置加载失败,请重试",[an.NETWORK_TIMEOUT]:"网络请求超时,请检查网络连接",[an.NETWORK_CONNECTION_FAILED]:"网络连接失败,请检查网络",[an.NETWORK_HTTP_ERROR]:"服务器返回错误,请稍后重试",[an.NETWORK_DNS_FAILED]:"域名解析失败,请检查网络",[an.AUTH_UNAUTHORIZED]:"请先登录",[an.AUTH_FORBIDDEN]:"您没有权限执行此操作",[an.AUTH_TOKEN_EXPIRED]:"登录已过期,请重新登录",[an.AUTH_TOKEN_INVALID]:"认证信息无效,请重新登录",[an.VALIDATION_INVALID_INPUT]:"输入参数无效",[an.VALIDATION_MISSING_REQUIRED]:"缺少必需参数",[an.VALIDATION_FORMAT_ERROR]:"数据格式错误",[an.VALIDATION_SCHEMA_ERROR]:"数据验证失败",[an.BUSINESS_RULE_VIOLATION]:"操作违反业务规则",[an.BUSINESS_RESOURCE_NOT_FOUND]:"请求的资源不存在",[an.BUSINESS_RESOURCE_EXISTS]:"资源已存在",[an.BUSINESS_OPERATION_NOT_ALLOWED]:"当前操作不被允许",[an.SYSTEM_INTERNAL]:"系统内部错误,请稍后重试",[an.SYSTEM_DEPENDENCY_FAILED]:"依赖服务异常,请稍后重试",[an.SYSTEM_RESOURCE_UNAVAILABLE]:"系统资源不可用,请稍后重试",[an.SYSTEM_UNKNOWN]:"发生未知错误,请稍后重试"};function ln(e){return on[e]}function un(e){return sn[e]}var cn=class _AppError extends Error{code;category;userMessage;details;cause;timestamp;constructor(e){super(e.message),this.name="AppError",this.code=e.code,this.category=ln(e.code),this.userMessage=e.userMessage||un(e.code),this.details=e.details,this.cause=e.cause,this.timestamp=(new Date).toISOString(),Error.captureStackTrace&&Error.captureStackTrace(this,_AppError)}toJSON(){const e={code:this.code,category:this.category,message:this.message,userMessage:this.userMessage,timestamp:this.timestamp};return void 0!==this.details&&(e.details=this.details),this.cause&&(this.cause instanceof _AppError?e.cause=this.cause.toJSON():e.cause={message:this.cause.message,stack:this.cause.stack}),e}getErrorChain(){const e=[this];let n=this.cause;for(;n;)e.push(n),n=n instanceof _AppError?n.cause:void 0;return e}getRootCause(){const e=this.getErrorChain();return e[e.length-1]}hasErrorCode(e){return this.getErrorChain().some(n=>n instanceof _AppError&&n.code===e)}hasErrorCategory(e){return this.getErrorChain().some(n=>n instanceof _AppError&&n.category===e)}toLogString(){const e=[`[${this.code}]`,this.message];return this.details&&e.push(`Details: ${JSON.stringify(this.details)}`),this.cause&&e.push(`Caused by: ${this.cause.message}`),e.join(" | ")}};function dn(e){return e instanceof cn}function mn(e,n,t){const r=t?.model?` (model: ${t.model})`:"",a=t?.provider?` [${t.provider}]`:"",o={[an.LLM_UNAUTHORIZED]:`LLM API authentication failed${a}${r}`,[an.LLM_MODEL_NOT_FOUND]:`Model not found or unavailable${r}${a}`,[an.LLM_RATE_LIMITED]:`LLM API rate limited${a}`,[an.LLM_TIMEOUT]:`LLM API request timeout${a}${r}`,[an.LLM_GENERATION_FAILED]:`LLM generation failed${a}${r}`,[an.LLM_RESPONSE_PARSE_ERROR]:`Failed to parse LLM response${a}`};return new cn({code:e,message:o[e]||`LLM error: ${n.message}`,cause:n,details:t})}function pn(e,n,t){const r=t?.url?` (${t.url})`:"",a=t?.statusCode?` [${t.statusCode}]`:"",o={[an.NETWORK_TIMEOUT]:`Network request timeout${r}`,[an.NETWORK_CONNECTION_FAILED]:`Failed to connect${r}`,[an.NETWORK_HTTP_ERROR]:`HTTP error${a}${r}`,[an.NETWORK_DNS_FAILED]:`DNS resolution failed${r}`};return new cn({code:e,message:o[e]||`Network error: ${n.message}`,cause:n,details:t})}function gn(e,n,t){const r=t.isMarkdownFormat?" (detected markdown format)":"",a=t.schemaName?` for schema "${t.schemaName}"`:"";return new cn({code:e,message:`Failed to parse structured output${a}${r}`,cause:n,details:{rawText:t.rawText,isMarkdownFormat:t.isMarkdownFormat,parseErrorMessage:t.parseErrorMessage,model:t.model,provider:t.provider,schemaName:t.schemaName,usage:t.usage}})}import{NoObjectGeneratedError as fn}from"ai";function yn(e){if(!e||"object"!=typeof e)return null;const n=e;if(!("AI_APICallError"===n.name||"APICallError"===n.name||"string"==typeof n.url&&"number"==typeof n.statusCode))return null;const t="number"==typeof n.statusCode?n.statusCode:void 0,r="string"==typeof n.responseBody?n.responseBody:void 0,a="string"==typeof n.url?n.url:void 0,o=n.message;let i,s;if(a&&(a.includes("openai.com")?i="openai":a.includes("anthropic.com")?i="anthropic":a.includes("dashscope.aliyuncs.com")?i="qwen":a.includes("openrouter.ai")?i="openrouter":a.includes("deepseek.com")?i="deepseek":a.includes("moonshot.cn")?i="moonshotai":a.includes("googleapis.com")&&(i="google")),r){const e=r.match(/model[`'":\s]+([^`'"}\s,]+)/i);e&&(s=e[1])}return{isAuthError:401===t||403===t,isModelNotFound:r?.includes("model")&&r?.includes("not exist")||r?.includes("not authorized to access this model")||!1,isRateLimited:429===t,isTimeout:408===t||504===t||o?.toLowerCase().includes("timeout")||!1,statusCode:t,provider:i,model:s,originalMessage:o,responseBody:r}}function bn(e){return[/^```/m,/^#{1,6}\s/m,/^\s*[-*+]\s/m,/^\s*\d+\.\s/m,/\[.+\]\(.+\)/,/^\s*>/m].some(n=>n.test(e))}function hn(e){try{if(void 0===fn||"function"!=typeof fn.isInstance)return null;if(!fn.isInstance(e))return null}catch{return null}const n=e.text,t=!!n&&bn(n),r=e.response?{id:e.response.id,timestamp:e.response.timestamp,modelId:e.response.modelId}:void 0,a=e.usage??void 0,o={isNoObjectGeneratedError:!0,isMarkdownFormat:t};return void 0!==n&&(o.rawText=n),e.cause instanceof Error&&(o.cause=e.cause),void 0!==r&&(o.response=r),void 0!==a&&(o.usage=a),o}function Nn(e,n=an.SYSTEM_UNKNOWN,t){if(dn(e))return t&&t!==e.userMessage?new cn({code:e.code,message:e.message,userMessage:t,cause:e.cause,details:e.details}):e;const r=Sn(e),a=yn(e);if(a){const e={model:a.model,provider:a.provider,statusCode:a.statusCode,responseBody:a.responseBody};return a.isModelNotFound?mn(an.LLM_MODEL_NOT_FOUND,r,e):a.isAuthError?mn(an.LLM_UNAUTHORIZED,r,e):a.isRateLimited?mn(an.LLM_RATE_LIMITED,r,e):a.isTimeout?mn(an.LLM_TIMEOUT,r,e):mn(an.LLM_GENERATION_FAILED,r,e)}const o=hn(e);if(o)return gn(an.LLM_RESPONSE_PARSE_ERROR,r,{rawText:o.rawText,isMarkdownFormat:o.isMarkdownFormat,parseErrorMessage:o.cause?.message,usage:o.usage});const i=r.message.toLowerCase();return i.includes("timeout")||i.includes("econnrefused")||i.includes("network")||i.includes("fetch failed")?i.includes("timeout")?pn(an.NETWORK_TIMEOUT,r):pn(an.NETWORK_CONNECTION_FAILED,r):new cn({code:n,message:r.message,cause:r})}function Sn(e){if(e instanceof Error)return e;if("string"==typeof e)return new Error(e);if("object"==typeof e&&null!==e){const n=e.message||e.error||JSON.stringify(e);return new Error(String(n))}return new Error(String(e))}function Tn(e,n){console.error(`[${n.code}] ${e}:`,n.toLogString()),n.cause&&console.error("Original error:",n.cause)}function An(e){return"object"==typeof e&&null!==e}function In(e,n){n&&An(e.details)&&(e.details.schemaName=n)}function _n(e){const n=e.type;return"string"==typeof n?[n]:Array.isArray(n)?n.filter(e=>"string"==typeof e):[]}function En(e,n){let t=null;for(const r of e){const e=n.get(r);if(void 0!==e&&e.size>0){t??=new Set;for(const n of e)t.add(n)}}return t}function Rn(e,n){if(Array.isArray(e))return e.map(e=>Rn(e,n));if(null===e||"object"!=typeof e)return e;const t=e,r=En(_n(t),n),a={};for(const[e,o]of Object.entries(t))null!==r&&r.has(e)||(a[e]=Rn(o,n));return a}function Ln(e){const n=e.unsupportedKeywordsByType;if(void 0===n)return new Map;const t=new Map;for(const[e,r]of Object.entries(n)){if(0===r.length)continue;const n=t.get(e);if(void 0!==n)for(const e of r)n.add(e);else t.set(e,new Set(r))}const r=t.get("number");if(void 0!==r&&r.size>0){const e=t.get("integer");if(void 0!==e)for(const n of r)e.add(n);else t.set("integer",new Set(r))}return t}function On(e,n={}){const t=Ln(n);if(0===t.size)return e;const r=Ze(e);return en(async()=>Rn(await r.jsonSchema,t),{validate:e=>({success:!0,value:e})})}async function kn(e){const{model:n,schema:t,outputSchema:r,schemaName:a,system:o,prompt:i,transformOutput:s,onError:l}=e;try{const e=await Xe({model:n,...void 0!==o?{system:o}:{},prompt:i,output:tn.object({schema:r??t,...void 0!==a?{name:a}:{}})});if(void 0===r&&void 0===s)return{success:!0,data:e.output,usage:e.usage};const u=void 0!==s?await s(e.output):e.output,c=await t.safeParseAsync(u);if(!c.success){const n=Nn(c.error,an.LLM_RESPONSE_PARSE_ERROR);return In(n,a),Tn(`Structured output validation (${a||"unknown"})`,n),l&&l(n,e.text),{success:!1,error:n,rawText:e.text}}return{success:!0,data:c.data,usage:e.usage}}catch(e){const n=Nn(e,an.LLM_RESPONSE_PARSE_ERROR);let t;return nn.isInstance(e)&&(t=e.text),In(n,a),Tn(`Structured output generation (${a||"unknown"})`,n),l&&l(n,t),{success:!1,error:n,rawText:t}}}var Mn=3e4,vn=2e3;async function wn(e){const{model:n,system:t,prompt:r,timeoutMs:a=Mn,maxOutputTokens:o=vn,context:i="generateText",onError:s}=e,l=Qe.now();try{const e=new AbortController,s=Ye(()=>e.abort(),a),u=await Xe({model:n,...void 0!==t?{system:t}:{},prompt:r,maxOutputTokens:o,abortSignal:e.signal});Je(s);const c=Math.round(Qe.now()-l),d=u.usage,m=void 0!==d?.inputTokens&&void 0!==d?.outputTokens?d.inputTokens+d.outputTokens:void 0,p={inputTokens:d?.inputTokens,outputTokens:d?.outputTokens,totalTokens:m};return me(`[${i}] 生成成功 | 耗时: ${c}ms | Tokens: ${m??"N/A"} (input: ${p.inputTokens??"?"}, output: ${p.outputTokens??"?"})`),{success:!0,text:u.text,usage:p,latencyMs:c}}catch(e){const n=Math.round(Qe.now()-l),t=e instanceof Error&&("AbortError"===e.name||e.message.includes("aborted")),r=Nn(e,t?an.LLM_TIMEOUT:an.LLM_GENERATION_FAILED);return An(r.details)&&(r.details.context=i,r.details.latencyMs=n),Tn(`${i} (${n}ms)`,r),s&&s(r),{success:!1,error:r}}}import{z as Dn}from"zod";var Cn=Dn.object({name:Dn.string(),baseURL:Dn.string(),description:Dn.string()}),Un=Dn.record(Dn.string(),Cn),xn=Dn.object({chatModel:Dn.string().optional(),classifyModel:Dn.string().optional(),replyModel:Dn.string().optional(),providerConfigs:Un.optional()}),$n=Dn.object({city:Dn.string().optional(),defaultBrand:Dn.string(),availableBrands:Dn.array(Dn.string()),storeCount:Dn.number()}),jn=Dn.object({modelConfig:xn,candidateMessage:Dn.string(),conversationHistory:Dn.array(Dn.string()).default([]),brandData:$n.optional(),channelType:_.optional()});function Wn(e){const n=_.safeParse(e);return n.success?n.data:"public"}function Fn(e="public"){const n=Wn(e),t=I.options.filter(e=>L[e].applicableChannels.includes(n));return t.length>0?t:[...I.options]}function Pn(e){return ze.object({stage:ze.enum(e),subGoals:w.shape.subGoals,needs:w.shape.needs,primaryNeed:w.shape.primaryNeed,riskFlags:w.shape.riskFlags,confidence:w.shape.confidence,extractedInfo:w.shape.extractedInfo,reasoningText:w.shape.reasoningText})}var Bn={subGoals:2,needs:8,riskFlags:6,mentionedDistricts:10};function Gn(e){return e.startsWith("anthropic/")}function qn(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function Hn(e){if(!qn(e))return e;const n={...e};if(Array.isArray(n.subGoals)&&(n.subGoals=n.subGoals.slice(0,Bn.subGoals)),Array.isArray(n.needs)&&(n.needs=n.needs.slice(0,Bn.needs)),Array.isArray(n.riskFlags)&&(n.riskFlags=n.riskFlags.slice(0,Bn.riskFlags)),qn(n.extractedInfo)){const e={...n.extractedInfo};Array.isArray(e.mentionedDistricts)&&(e.mentionedDistricts=e.mentionedDistricts.slice(0,Bn.mentionedDistricts)),n.extractedInfo=e}return n}var Kn=[{need:"salary",patterns:[/薪资|工资|时薪|底薪|提成|奖金|补贴|多少钱|收入/i]},{need:"schedule",patterns:[/排班|班次|几点|上班|下班|工时|周末|节假日|做几天/i]},{need:"policy",patterns:[/五险一金|社保|保险|合同|考勤|迟到|补班|试用期/i]},{need:"availability",patterns:[/还有名额|空位|可用时段|什么时候能上|明天能面/i]},{need:"location",patterns:[/在哪|位置|地址|附近|地铁|门店|哪个区|多远/i]},{need:"stores",patterns:[/门店|哪家店|哪些店|有店吗/i]},{need:"requirements",patterns:[/要求|条件|年龄|经验|学历|健康证|身高|体重/i]},{need:"interview",patterns:[/面试|到店|约时间|约面/i]},{need:"wechat",patterns:[/微信|vx|私聊|联系方式|加你/i]}],Vn=["salary","schedule","location","stores","policy","requirements","availability","interview","wechat","none"];function zn(e){const n=new Set;for(const t of Kn)t.patterns.some(n=>n.test(e))&&n.add(t.need);return 0===n.size?n.add("none"):n.delete("none"),n}function Yn(e,n){return zn(`${n.slice(-4).join(" ")} ${e}`)}function Jn(e){return zn(e)}function Qn(e,n,t,r=1){const a=new Set(n);a.size>1&&a.has("none")&&a.delete("none");const o=Jn(t);o.delete("none");const i=[];"none"!==e&&a.has(e)&&i.push(e);for(const n of Vn){if(i.length>=r)break;"none"!==n&&n!==e&&(o.has(n)&&a.has(n)&&i.push(n))}return i.length>0?i:"none"===e?["none"]:a.has(e)?[e]:["none"]}function Zn(e,n,t){const r=new Set(n);if(r.size>1&&r.has("none")&&r.delete("none"),e&&r.has(e))return e;const a=Jn(t);a.delete("none");for(const e of Vn)if(a.has(e)&&r.has(e))return e;for(const e of Vn)if(r.has(e))return e;return"none"}function Xn(e,n,t){const r=new Set([...e.needs,...Array.from(n)]);return r.size>1&&r.has("none")&&r.delete("none"),{...e,subGoals:e.subGoals.slice(0,2),needs:Array.from(r),primaryNeed:Zn(e.primaryNeed,r,t),confidence:Number.isFinite(e.confidence)?Math.max(0,Math.min(1,e.confidence)):.5}}function et(e,n,t,r="public",a,o){const i=["你是招聘对话回合规划器,不直接回复候选人。","你只输出结构化规划结果,用于后续回复生成。","规划目标:确定阶段目标(stage)、子目标(subGoals)、事实需求(needs)、主回答轴(primaryNeed)、风险标记(riskFlags)。"].join("\n"),s=Wn(r);return{system:i,prompt:["[阶段枚举与定义]",...Fn(s).map(e=>{const n=L[e];return`- ${e}: ${a?.stageGoals[e]?.description||n.description} (转入条件: ${n.transitionSignal})`}),"","[needs枚举]","private"===s?"- stores, location, salary, schedule, policy, availability, requirements, interview, none":"- stores, location, salary, schedule, policy, availability, requirements, interview, wechat, none","","[riskFlags枚举]","- insurance_promise_risk, age_sensitive, confrontation_emotion, urgency_high, qualification_mismatch","","[规则]","- 优先判断本轮主阶段(stage);subGoals 最多 2 项,只保留最关键的。","- 候选人追问事实时,必须打开对应 needs。","- primaryNeed 必须从 needs 中选择一个最主的 need;如果没有明确事实轴则填 none。","- 不确定时 confidence 降低,不要臆断。","- 根据转入条件判断阶段转化,不要停留在不匹配的阶段。",...o&&o.length>0?[`- 候选人资料中已有:${o.join("、")}。不要生成追问这些字段的 subGoal。`]:[],"","[品牌数据]",JSON.stringify(t||{}),"","[历史对话]",n.slice(-8).join("\n")||"无","","[候选人消息]",e].join("\n")}}async function nt(e,n){const{providerConfigs:t=be,modelConfig:r,conversationHistory:a=[],brandData:o,channelType:i,replyPolicy:s,knownCandidateFields:l}=n,u=_e(t),c=r?.classifyModel||he.classifyModel,d=Wn(i),m=Pn(Fn(d)),p=Gn(c),g=et(e,a,o,d,s,l),f=await kn({model:u.languageModel(c),schema:m,...p?{outputSchema:On(m,{unsupportedKeywordsByType:{array:["maxItems","minItems"],number:["maximum","minimum","exclusiveMaximum","exclusiveMinimum"]}}),transformOutput:Hn}:{},schemaName:"TurnPlanningOutput",system:g.system,prompt:g.prompt}),y=Yn(e,a),b=Zn(void 0,y,e);return f.success?Xn(f.data,y,e):{stage:"trust_building",subGoals:["保持对话并澄清需求"],needs:Array.from(y),primaryNeed:b,riskFlags:[],confidence:.35,extractedInfo:{mentionedBrand:null,city:o?.city||null,mentionedLocations:null,mentionedDistricts:null,specificAge:null,hasUrgency:null,preferredSchedule:null},reasoningText:"规划模型失败,使用规则降级策略"}}import{z as tt}from"zod";var rt=tt.object({id:tt.number(),name:tt.string(),aliases:tt.array(tt.string()),projectIdList:tt.array(tt.number())}),at=tt.object({code:tt.number(),message:tt.string().optional(),data:tt.object({result:tt.array(rt),total:tt.number()})}),ot=3e5,it=null;function st(){return null!==it&&Date.now()-it.timestamp<ot}var lt=3e4;function ut(){const e=process.env.DULIDAY_BRAND_LIST_URL;return"string"==typeof e&&e.trim().length>0?e:void 0}async function ct(e){const n=e||process.env.DULIDAY_TOKEN,t=ut();if(!n)throw new cn({code:an.CONFIG_MISSING_FIELD,message:"DULIDAY_TOKEN 未配置,无法获取品牌别名数据",userMessage:"品牌别名数据加载失败:缺少 Duliday Token 配置"});if(!t)throw new cn({code:an.CONFIG_MISSING_FIELD,message:"DULIDAY_BRAND_LIST_URL 未配置,无法获取品牌别名数据",userMessage:"品牌别名数据加载失败:缺少 Duliday 品牌接口配置"});const r=new AbortController,a=setTimeout(()=>r.abort(),lt);try{const e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json","Duliday-Token":n},body:JSON.stringify({pageNum:1,pageSize:1e3}),signal:r.signal});if(!e.ok)throw new cn({code:an.NETWORK_HTTP_ERROR,message:`Duliday 品牌列表 API 返回 HTTP ${e.status}: ${e.statusText}`,userMessage:`品牌别名数据加载失败:服务端返回 ${e.status}`});const a=await e.json(),o=at.safeParse(a);if(!o.success)throw new cn({code:an.VALIDATION_SCHEMA_ERROR,message:`Duliday 品牌列表响应格式校验失败: ${o.error.message}`,userMessage:"品牌别名数据加载失败:响应格式异常"});return o.data.data.result}catch(e){if(e instanceof cn)throw e;if(e instanceof Error&&"AbortError"===e.name)throw new cn({code:an.NETWORK_TIMEOUT,message:`Duliday 品牌列表 API 请求超时 (${lt}ms)`,userMessage:"品牌别名数据加载超时,请稍后重试",cause:e});throw new cn({code:an.SYSTEM_DEPENDENCY_FAILED,message:`获取品牌别名数据失败: ${e instanceof Error?e.message:String(e)}`,userMessage:"品牌别名数据加载失败,请检查网络连接",...e instanceof Error?{cause:e}:{}})}finally{clearTimeout(a)}}function dt(e,n,t){const r={},a=new Map,o=e=>e.trim(),i=(e,n)=>{const t=o(e).toLowerCase().replace(/[\s._-]+/g,"");if(!t)return;const r=a.get(t);(!r||n.length>r.length)&&a.set(t,n)},s=[...e].sort((e,n)=>n.name.length-e.name.length);for(const e of s){const n=o(e.name);if(!n)continue;const a=Array.from(new Set([n,...e.aliases.map(o).filter(Boolean)].filter(e=>e!==n)));a.unshift(n),r[n]=a;for(const e of a)i(e,n);if(t&&e.projectIdList.length>0)for(const o of e.projectIdList){const e=t[String(o)];if(!e||e===n)continue;if(!e.includes(n))continue;const s=e.replace(n,"");if(!s)continue;const l=[e];for(const e of a)e!==n&&l.push(`${s}${e}`);if(r[e]){const n=new Set(r[e]);for(const t of l)n.has(t)||r[e].push(t)}else r[e]=l;for(const n of l)i(n,e)}}for(const e of n)r[e]||(r[e]=[e],i(e,e));return{dictionary:r,aliasMap:a}}async function mt(e){if(st())return;const n=await ct(e),t=new Set,{dictionary:r,aliasMap:a}=dt(n,t);it={aliasMap:a,dictionary:r,timestamp:Date.now()}}async function pt(e){return await mt(e),it.aliasMap}function gt(e){const{base:n,unit:t,range:r,memo:a}=e,o=a?.replace(/\n/g," ").trim()??"";if(null==n)return e.scenarioSummary&&o?`${o}(${e.scenarioSummary})`:e.scenarioSummary?e.scenarioSummary:o;let i="";return n<10&&a?i=`${n}${t??""}(${o})`:(i=`${n}${t??""}`,r&&r!==`${n}-${n}`&&r!==`${n}元-${n}元`&&(i+=`,范围${r}`),o&&o.length<50&&(i+=`(${o})`)),e.scenarioSummary&&(i+=`(${e.scenarioSummary})`),i}function ft(e,n,t){if(!e)return null;const r=e=>e.toLowerCase().replace(/[\s._-]+/g,"");if(t){const a=t.get(r(e))||t.get(e.toLowerCase());if(a&&n.includes(a))return a}const a=e.toLowerCase(),o=r(e),i=n.find(e=>e.toLowerCase()===a);if(i)return i;const s=n.find(e=>r(e)===o);if(s)return s;const l=n.filter(e=>{const n=e.toLowerCase();if(n.includes(a)||a.includes(n))return!0;const t=r(e);return t.includes(o)||o.includes(t)});if(l.length>0)return l.sort((e,n)=>n.length-e.length)[0]??null;if(a.includes("山姆")||a.includes("sam")){const e=n.find(e=>{const n=e.toLowerCase();return n.includes("山姆")||n.includes("sam")});if(e)return e}return null}function yt(e){const{uiSelectedBrand:n,configDefaultBrand:t,conversationBrand:r,availableBrands:a,strategy:o="smart",aliasMap:i}=e,s=(e,n)=>{if(e)return ft(e,a,i)??void 0};switch(o){case"user-selected":{const e=s(n);if(e)return{resolvedBrand:e,matchType:e===n?"exact":"fuzzy",source:"ui",reason:"用户选择策略",originalInput:n};const r=s(t);return r?{resolvedBrand:r,matchType:r===t?"exact":"fuzzy",source:"config",reason:"配置默认",originalInput:t}:{resolvedBrand:a[0]??"",matchType:"fallback",source:"default",reason:"系统默认"}}case"conversation-extracted":{const e=s(r);if(e)return{resolvedBrand:e,matchType:e===r?"exact":"fuzzy",source:"conversation",reason:"对话提取",originalInput:r};const o=s(n);if(o)return{resolvedBrand:o,matchType:o===n?"exact":"fuzzy",source:"ui",reason:"UI选择",originalInput:n};const i=s(t);return i?{resolvedBrand:i,matchType:i===t?"exact":"fuzzy",source:"config",reason:"配置默认",originalInput:t}:{resolvedBrand:a[0]??"",matchType:"fallback",source:"default",reason:"系统默认"}}default:{const e=s(r),o=s(n);if(e)return{resolvedBrand:e,matchType:e===r?"exact":"fuzzy",source:"conversation",reason:"智能策略: 对话提取",originalInput:r};if(o)return{resolvedBrand:o,matchType:o===n?"exact":"fuzzy",source:"ui",reason:"智能策略: UI选择",originalInput:n};const i=s(t);return i?{resolvedBrand:i,matchType:i===t?"exact":"fuzzy",source:"config",reason:"智能策略: 配置默认",originalInput:t}:{resolvedBrand:a[0]??"",matchType:"fallback",source:"default",reason:"智能策略: 系统默认"}}}}function bt(e,n){const{mentionedLocations:t,mentionedDistricts:r}=n;return e.map(e=>{let n=0,a=0,o=0,i=0;if(t&&t.length>0){const r=t.find(n=>e.name.includes(n.location)||e.location.includes(n.location)||(e.subarea??"").includes(n.location));r&&(n=40*r.confidence)}if(r&&r.length>0){const n=r.find(n=>(e.district??"").includes(n.district)||(e.subarea??"").includes(n.district));n&&(a=30*n.confidence)}const s=new Set(e.positions.map(e=>e.name));o=Math.min(5*s.size,20);const l=e.positions.filter(e=>e.availableSlots?.some(e=>e.isAvailable));return i=Math.min(2*l.length,10),{store:e,score:n+a+o+i,breakdown:{locationMatch:n,districtMatch:a,positionDiversity:o,availability:i}}}).sort((e,n)=>n.score-e.score).map(e=>({store:e.store,distance:void 0}))}function ht(e){return M[e].length>0}function Nt(e,n){return e.has(n)}function St(e,n,t){return"minimal"===n||(1===e||"trust_building"===t||"private_channel"===t)}async function Tt(e,n,t,r,a,o,i,s,l=1,u="minimal",c=[n.primaryNeed]){const d=n.extractedInfo,m=n.primaryNeed,p=c.length>0?Array.from(new Set(c.filter(e=>"none"!==e))):"none"===m?[]:[m],g=new Set(p.flatMap(e=>M[e])),f=St(l,u,n.stage),y=!f&&ht(m);let b,h;try{b=await pt()}catch(e){const n="object"==typeof e&&null!==e&&"userMessage"in e&&"string"==typeof e.userMessage?e.userMessage:e instanceof Error?e.message:String(e);h=n,me(`[buildContextInfoByNeeds] 品牌别名服务不可用,回退 fuzzy 解析: ${n}`)}const N=yt({uiSelectedBrand:t,configDefaultBrand:ke(e),conversationBrand:r||void 0,availableBrands:Re(e),strategy:a||"smart",aliasMap:b}),S=N.resolvedBrand;me(`[品牌解析] 工具传参: ${r??"(未指定)"} → 结果: ${S} (${N.matchType}, ${N.source})`);const T=Le(e,S),A=T?.stores??[];let I=A;if(I.length>0){const e=d.mentionedLocations||[];if(e.length>0){const n=e[0]?.location?.trim();if(n){const e=I.filter(e=>e.name.includes(n)||e.location.includes(n)||(e.district??"").includes(n)||(e.subarea??"").includes(n));e.length>0&&(I=e)}}const n=d.mentionedDistricts||[];if(n.length>0){const e=I.filter(e=>n.some(n=>(e.district??"").includes(n.district)||(e.subarea??"").includes(n.district)));e.length>0&&(I=e)}if(I.length===A.length&&o?.jobAddress&&Nt(g,"location")){const e=I.filter(e=>e.name.includes(o.jobAddress||"")||e.location.includes(o.jobAddress||"")||(e.district??"").includes(o.jobAddress||"")||(e.subarea??"").includes(o.jobAddress||""));e.length>0&&(I=e)}}let _=[];I.length>0&&(_=bt(I,d));const E=y?Math.min(1,_.length):0,R=y?"focused":"minimal";let L=`阶段目标:${n.stage}\n默认推荐品牌:${S}\n`;if(h&&(L+=`系统状态:品牌别名服务暂不可用,已回退为规则匹配(${h})。\n`),i){const e=i.stageGoals[n.stage],t=s||i.defaultIndustryVoiceId,r=i.industryVoices[t];L+=`策略目标:${e.primaryGoal}\n`,L+=`推进方式:${e.ctaStrategy}\n`,L+=`主回答轴:${m}\n`,r&&(L+=`行业指纹:${r.name} | 风格:${r.styleKeywords.join("、")}\n`),L+=`红线:${i.hardConstraints.rules.map(e=>e.rule).join(";")}\n`}return y?0===E?L+="暂无可用的门店事实信息,请使用泛化回答,避免任何具体承诺。\n":(L+="匹配到的门店信息:\n",_.slice(0,E).forEach(({store:e})=>{const n=Nt(g,"location"),t=Array.from(g).some(e=>"location"!==e),r=[e.district,e.subarea].filter(e=>Boolean(e)).join("");L+=n?r?`• ${e.name}(${r}):${e.location}\n`:`• ${e.name}:${e.location}\n`:`• ${e.name}\n`,t&&e.positions.slice(0,3).forEach(e=>{if(L+=` 职位:${e.name}\n`,Nt(g,"salary")){const n=gt(e.salary);n&&(L+=` 薪资:${n}\n`)}if(Nt(g,"schedule")){if(e.laborForm){const n=[e.laborForm];e.employmentForm&&"长期用工"!==e.employmentForm&&n.push(e.employmentForm),L+=` 用工形式:${n.join(",")}\n`}if(e.timeSlots.length>0&&(L+=` 时间:${e.timeSlots.slice(0,3).join("、")}\n`),(e.minHoursPerWeek||e.maxHoursPerWeek)&&(L+=` 每周工时:${e.minHoursPerWeek||0}-${e.maxHoursPerWeek||"不限"}小时\n`),null!=e.perMonthMinWorkTime){const n=null!=e.perMonthMinWorkTimeUnit?String(e.perMonthMinWorkTimeUnit):"";L+=` 月最低工时:${e.perMonthMinWorkTime}${n}\n`}}if(Nt(g,"policy")&&(e.attendanceRequirement?.description&&(L+=` 出勤要求:${e.attendanceRequirement.description}\n`),e.trainingRequired&&"不需要"!==e.trainingRequired&&(L+=` 培训要求:${e.trainingRequired}\n`),e.probationRequired&&"不需要"!==e.probationRequired&&(L+=` 试岗要求:${e.probationRequired}\n`)),Nt(g,"availability")){const n=e.availableSlots?.filter(e=>e.isAvailable).slice(0,3)||[];n.length>0&&(L+=` 可用时段:${n.map(e=>e.slot).join("、")}\n`)}if(Nt(g,"requirements")&&e.hiringRequirements){const n=e.hiringRequirements,t=[];null==n.minAge&&null==n.maxAge||t.push(`年龄${n.minAge??"不限"}-${n.maxAge??"不限"}岁`),n.genderRequirement&&"0"!==n.genderRequirement&&t.push(`性别:${n.genderRequirement}`),n.education&&"不限"!==n.education&&t.push(`学历:${n.education}`),n.healthCertificate&&t.push(n.healthCertificate),n.languages&&t.push(`语言:${n.languages}`),n.socialIdentity&&"不限"!==n.socialIdentity&&t.push(`社会身份:${n.socialIdentity}`),t.length>0&&(L+=` 要求:${t.join("、")}\n`),n.recruitmentRemark&&(L+=` 招聘备注:${n.recruitmentRemark.slice(0,200)}\n`)}})})):L+=f?"当前处于首轮或浅层沟通,优先泛化回答,不主动展开具体门店、数字或筛选条件。\n":"本轮以推进沟通为主,无需展开岗位细节,请保持回答聚焦且克制。\n",{contextInfo:L,resolvedBrand:S,debugInfo:{relevantStores:_.length>0?_:I.map(e=>({store:e,distance:void 0})),storeCount:E,detailLevel:R,primaryNeed:m,turnPlan:n,aliasLookupError:h}}}var At=["too_many_questions","audit_tone","premature_numeric_disclosure","off_axis_fact_disclosure","reply_overpacked"],It=/[^。!?!?]*[??]/g,_t={salary:{mention:[/\d+(?:\.\d+)?\s*元(?:\/时|\/小时)?/i,/时薪|薪资|工资|底薪|收入/i],concrete:[/\d+(?:\.\d+)?\s*元(?:\/时|\/小时)?/i]},schedule:{mention:[/\d{1,2}:\d{2}\s*[~-]\s*\d{1,2}:\d{2}/,/班次|轮班|白班|晚班|工时|排班/i],concrete:[/\d{1,2}:\d{2}\s*[~-]\s*\d{1,2}:\d{2}/,/轮班|白班|晚班|早班|中班|夜班/i]},location:{mention:[/地址|地铁|附近|位于|门店|在.+(?:路|街|广场|商场|大厦)/i],concrete:[/地址|位于|地铁\S*站|在.+(?:路|街|广场|商场|大厦)/i]},policy:{mention:[/考勤|试用期|社保|五险一金|迟到|补班/i],concrete:[/考勤|试用期|社保|五险一金|迟到|补班/i]},requirements:{mention:[/年龄|学历|经验|健康证|要求/i],concrete:[/年龄|学历|经验|健康证/i]},availability:{mention:[/名额|空位|可用时段|可安排/i],concrete:[/名额|空位|可用时段/i]}};function Et(e){return e?.outputGuards??W}function Rt(e){const n=e.match(It)??[],t=new Set(n.map(e=>e.replace(/[??]/g,"").trim()).filter(Boolean)),r=e.split(/[。!?!?]/).map(e=>e.trim()).filter(Boolean).filter(e=>/[吗呢么]$/.test(e)&&!t.has(e)).length;return n.length+r}function Lt(e){return e.split(/[。!?!?]/).map(e=>e.trim()).filter(Boolean).length}function Ot(e){return/(?:^|\s)(?:\d+\.\s|- |•)/m.test(e)}function kt(e,n="mention"){return Object.entries(_t).filter(([,t])=>t[n].some(n=>n.test(e))).map(([e])=>e)}function Mt(e,n){return n.some(n=>n&&e.includes(n))}function vt(e){return/\d+(?:\.\d+)?\s*元(?:\/时|\/小时)?/i.test(e)||/\d{1,2}:\d{2}\s*[~-]\s*\d{1,2}:\d{2}/.test(e)||/年龄\s*\d{1,2}\s*[-~到]\s*\d{1,2}\s*岁/i.test(e)||/\d{1,2}\s*[-~到]\s*\d{1,2}\s*岁/i.test(e)||/地址在|门店在|位于|在.+(?:路|街|广场|商场|大厦|地铁)/i.test(e)}function wt(e,n,t){let r=0;return Lt(e)>=4&&(r+=1),Ot(e)&&(r+=1),n>=3&&(r+=1),t.length>=2&&(r+=1),r>=2}function Dt(e){return kt(e,"concrete")}function Ct(e){const n=[];return/薪资:/.test(e)&&n.push("salary"),/排班:|时间:|每周工时:/.test(e)&&n.push("schedule"),/匹配到的门店信息:[\s\S]*• .*:/.test(e)&&n.push("location"),/考勤:|出勤要求:/.test(e)&&n.push("policy"),/要求:/.test(e)&&n.push("requirements"),/可用时段:/.test(e)&&n.push("availability"),n}function Ut(e,n){const t=new Set(e.flatMap(e=>M[e]));return 0===t.size?n.length>0:n.some(e=>!t.has(e))}function xt(e){const{text:n,turnIndex:t,mode:r,policy:a}=e,o=Et(a),i=Rt(n),s=o.maxQuestionsByMode[r],l=Dt(n),u=e.allowedNeeds?.length?e.allowedNeeds:[e.primaryNeed],c=[];return i>s&&c.push("too_many_questions"),Mt(n,o.blockedAuditPhrases)&&c.push("audit_tone"),o.blockFirstTurnSpecificFacts&&1===t&&vt(n)&&c.push("premature_numeric_disclosure"),Ut(u,l)&&c.push("off_axis_fact_disclosure"),wt(n,i,l)&&c.push("reply_overpacked"),{violations:c,questionCount:i,factFamilies:l}}import $t from"ora";function jt(){let e=null;return{update(n){e?e.text=n:e=$t({text:n,stream:process.stderr}).start()},succeed(n){e?(e.succeed(n),e=null):console.error(`✓ ${n}`)},fail(n){e?(e.fail(n),e=null):console.error(`✗ ${n}`)}}}import{z as Wt}from"zod";var Ft=["pass","fail","unknown"],Pt=Wt.object({minAge:Wt.number().nullable(),maxAge:Wt.number().nullable()}),Bt=Wt.object({evidence:Wt.array(Pt),matchedCount:Wt.number().int().min(0),total:Wt.number().int().min(0),isComplete:Wt.boolean()}),Gt={enabled:!1,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!1,redirectPriority:"low"},qt=200;function Ht(e){return(e??"").trim().toLowerCase()}function Kt(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function Vt(e){if("string"==typeof e)return e;if(Array.isArray(e)){const n=e.find(e=>"string"==typeof e);return"string"==typeof n?n:""}return""}function zt(e,n){for(const t of n){if(!(t in e))continue;const n=Vt(e[t]);if(n)return n}return""}function Yt(e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e&&""!==e.trim()){const n=Number(e);if(Number.isFinite(n))return n}return null}function Jt(e){return e.map(e=>Ht(e)).filter(Boolean)}function Qt(e,n){if(0===n.length)return!0;const t=Ht(e);return!!t&&n.some(e=>t.includes(e)||e.includes(t))}function Zt(e,n){return 0===n.length||e.some(e=>Qt(e,n))}function Xt(e,n){return!n||e.some(e=>Ht(e).includes(n))}function er(e){return e.some(e=>null!==e.minAge||null!==e.maxAge)}function nr(e,n){const t=n??Gt;let r=t.unknownStrategy;return"pass"===e?r=t.passStrategy:"fail"===e&&(r=t.failStrategy),{...t,status:e,strategy:r}}function tr(){return{evidence:[],matchedCount:0,total:0,isComplete:!0}}function rr(e){if(Array.isArray(e)){const n=e.map(e=>Pt.safeParse(e)).filter(e=>e.success).map(e=>e.data);return{evidence:n,matchedCount:n.length,total:n.length,isComplete:!0}}const n=Bt.safeParse(e);if(!n.success)return tr();return{evidence:n.data.evidence.map(e=>Pt.safeParse(e)).filter(e=>e.success).map(e=>e.data),matchedCount:n.data.matchedCount,total:n.data.total,isComplete:n.data.isComplete}}function ar(e){return{name:"config-data",async collect(n){const t=Jt(Pe(n.brandAlias,n.cityName)),r=Jt(Fe(n.cityName)),a=Ht(n.regionName),o=[];let i=0,s=0;for(const n of e.brands){if(Zt([n.name,...n.aliases??[]],t))for(const e of n.stores)if(Zt([e.city],r)&&(i+=e.positions.length,Xt([e.district,e.subarea,e.location,e.name],a))){s+=e.positions.length;for(const n of e.positions)o.push({minAge:n.hiringRequirements?.minAge??null,maxAge:n.hiringRequirements?.maxAge??null})}}return{evidence:o,matchedCount:s,total:i,isComplete:!0}}}}function or({token:e,jobListUrl:n}){return{name:"duliday-api",async collect(t){try{const r=await Ke(e,n,1,qt,{brandAlias:t.brandAlias??null,cityName:t.cityName??null}),{items:a,total:o}=Ge(r),i=o>a.length&&a.length>=qt,s=Jt(Pe(t.brandAlias,t.cityName)),l=Jt(Fe(t.cityName)),u=Ht(t.regionName),c=[];let d=0;for(const e of a){if(!Kt(e))continue;const n=e,t=Kt(n.basicInfo)?n.basicInfo:null,r=t&&Kt(t.storeInfo)?t.storeInfo:null,a=zt(n,["brandAlias","brandName","brand","organizationName"])||(t?zt(t,["brandAlias","brandName","brand"]):""),o=zt(n,["cityName","storeCityName","jobCityName"])||(r?zt(r,["storeCityName","cityName"]):""),i=zt(n,["regionName","storeRegionName","districtName"])||(r?zt(r,["storeRegionName","regionName","districtName"]):""),m=zt(n,["storeAddress","jobAddress","address","storeExactAddress"])||(r?zt(r,["storeAddress","storeExactAddress","address"]):"");if(!Qt(a,s))continue;if(!Qt(o,l))continue;if(!Xt([i,m],u))continue;d+=1;const p=Kt(n.hiringRequirement)?n.hiringRequirement:void 0,g=Kt(p?.basicPersonalRequirements)?p.basicPersonalRequirements:void 0;c.push({minAge:Yt(g?.minAge??n.minAge),maxAge:Yt(g?.maxAge??n.maxAge)})}return{evidence:c,matchedCount:d,total:o,isComplete:!i}}catch{return tr()}}}}function ir({configData:e,token:n,jobListUrl:t}){const r=[ar(e)];return n&&t&&r.push(or({token:n,jobListUrl:t})),r}async function sr({sources:e,...n}){let t=tr();for(const r of e??[])try{const e=rr(await r.collect(n));if(0===e.total&&0===e.matchedCount&&0===e.evidence.length)continue;if(e.isComplete&&er(e.evidence))return e;0===t.total&&0===t.matchedCount&&0===t.evidence.length&&(t=e)}catch{continue}return t}function lr({age:e,evidence:n,matchedCount:t,total:r,isComplete:a=!0,strategy:o}){const i=n.map(e=>Pt.safeParse(e)).filter(e=>e.success).map(e=>e.data),s={minAgeObserved:null,maxAgeObserved:null,matchedCount:t??i.length,total:r??i.length};if("number"!=typeof e||!Number.isFinite(e)||0===i.length||!a)return{status:"unknown",summary:s,appliedStrategy:nr("unknown",o)};let l=!1,u=!1;for(const n of i){const{minAge:t,maxAge:r}=n;null!==t&&(l=!0,s.minAgeObserved=null===s.minAgeObserved?t:Math.min(s.minAgeObserved,t)),null!==r&&(l=!0,s.maxAgeObserved=null===s.maxAgeObserved?r:Math.max(s.maxAgeObserved,r));null!==t&&e<t||null!==r&&e>r||(u=!0)}if(!l)return{status:"unknown",summary:s,appliedStrategy:nr("unknown",o)};const c=u?"pass":"fail";return{status:c,summary:s,appliedStrategy:nr(c,o)}}function ur(e){if(!e)return;const n=e.match(/(\d+)/);return n?n[1]:e}function cr(e,n){if("number"==typeof n?.age)return n.age;const t=ur(n?.age);if(t){const e=Number(t);if(Number.isFinite(e))return e}return"number"==typeof e.extractedInfo.specificAge?e.extractedInfo.specificAge:void 0}function dr(e,n){const t=e.extractedInfo.mentionedDistricts?.[0]?.district;if(t)return t;const r=e.extractedInfo.mentionedLocations?.[0]?.location;return r||(n?.jobAddress?n.jobAddress:void 0)}var mr=[{key:"age",label:"年龄"},{key:"gender",label:"性别"},{key:"education",label:"学历"},{key:"experience",label:"工作经验"},{key:"expectedSalary",label:"期望薪资"},{key:"expectedLocation",label:"期望位置"},{key:"jobAddress",label:"工作地址"},{key:"healthCertificate",label:"健康证"}];function pr(e){if(!e)return{factsText:"",knownFieldNames:[]};const n=[];for(const{key:t,label:r}of mr){const a=e[t];"string"==typeof a&&a.trim()?n.push({label:r,value:a.trim()}):"boolean"==typeof a&&n.push({label:r,value:a?"是":"否"})}return 0===n.length?{factsText:"",knownFieldNames:[]}:{factsText:n.map(e=>`${e.label}:${e.value}`).join("\n"),knownFieldNames:n.map(e=>e.label)}}function gr(e){if(null===e.minAgeObserved&&null===e.maxAgeObserved)return null;return`${e.minAgeObserved??"?"}-${e.maxAgeObserved??"?"}`}function fr(e,n,t){const r=n?.qualificationPolicy?.age;if(!e||!r||!r.enabled)return[];if("unknown"===e.status&&!t.riskFlags.includes("age_sensitive"))return[];const a=["[QualificationPolicy:Age]"],o=gr(e.summary);return a.push(`- gateStatus: ${e.status}`),a.push(`- expressionStrategy: ${e.appliedStrategy.strategy}`),a.push("- redirect: "+(r.allowRedirect?`allowed priority=${r.redirectPriority}`:"not allowed")),a.push("- revealRange: "+(r.revealRange?"allowed":"not allowed")),r.revealRange&&o&&a.push(`- rangeObserved: ${o}`),"pass"===e.status?a.push(`- writingConstraint: ${e.appliedStrategy.strategy};匹配通过后推进下一步,避免强调年龄筛选`):"fail"===e.status?(a.push(`- writingConstraint: ${e.appliedStrategy.strategy};礼貌说明不匹配,避免承诺或争辩`),r.allowRedirect&&a.push("- writingConstraint: 可提示其他岗位或门店选项")):a.push("- writingConstraint: 如确需涉及年龄或资格,用合规、轻量的方式核实,不要审查式逐条盘问"),a}function yr(e){return"minimal"===e?["4. 当前为浅层沟通,优先泛化回答,不主动抛具体数字、时间、地址或筛选条件。","5. 若候选人追问具体事实,承接需求并引导进一步沟通,不编造细节。"]:["4. 围绕 primaryNeed 回答,上下文中有的事实可以正常引用,不要刻意回避。","5. 不主动展开其他事实轴;若候选人同时问两个点,只在上下文支持时简要带上次要问题。"]}function br(e,n,t,r,a,o,i,s,l,u,c,d){if(!e)return{system:"你是招聘助手。遵循事实,不夸大承诺,回复简洁自然。",prompt:`候选人消息:${a}\n\n上下文:\n${r}\n\n请直接回复候选人。`};const m=e.stageGoals[n.stage],p=e.industryVoices[u||e.defaultIndustryVoiceId],g=e.outputGuards.maxQuestionsByMode[s];return{system:["你是政策驱动的招聘助手。",`当前阶段:${n.stage}`,`当前轮次:${i}`,`当前披露模式:${s}`,`主回答轴:${n.primaryNeed}`,`阶段目标:${m.primaryGoal}`,`阶段成功标准:${m.successCriteria.join(";")}`,`推进策略:${m.ctaStrategy}`,m.disallowedActions?.length?`阶段禁止:${m.disallowedActions.join(";")}`:"",`人格设定:语气=${e.persona.tone},亲和度=${e.persona.warmth},长度=${e.persona.length},称呼=${e.persona.addressStyle},提问风格=${e.persona.questionStyle}`,`共情策略:${e.persona.empathyStrategy}`,p?`行业指纹:${p.name};背景=${p.industryBackground};行业词=${p.jargon.join("、")};避免=${p.tabooPhrases.join("、")}`:"",`红线规则:${e.hardConstraints.rules.map(e=>e.rule).join(";")}`,`FactGate模式:${e.factGate.mode};缺事实回退=${e.factGate.fallbackBehavior}`,`禁止审查措辞:${e.outputGuards.blockedAuditPhrases.join("、")}`,...l.knownFieldNames.length>0?[`候选人资料已确认:${l.knownFieldNames.join("、")}。这些信息不得重复追问;如需引用,自然带过即可,不要像念资料一样复述。`]:[],...fr(d,e,n),c?`如涉及换微信,优先引导平台交换,必要时可提供默认微信号:${c}`:"如涉及换微信,优先引导平台交换,不编造联系方式。","必须口语化、简洁,不输出解释。"].filter(Boolean).join("\n"),prompt:["[回合规划]",`stage=${n.stage}`,`subGoals=${n.subGoals.join("、")||"无"}`,`contextNeeds=${t.join("、")||"none"}`,`primaryNeed=${n.primaryNeed}`,`riskFlags=${n.riskFlags.join("、")||"无"}`,`confidence=${n.confidence.toFixed(2)}`,"","[对话历史]",o.slice(-6).join("\n")||"无","","[业务上下文]",r,"",...l.factsText?["[候选人已知信息]",l.factsText,""]:[],"[候选人消息]",a,"","[输出要求]","1. 直接给候选人的单条回复,不得输出多段解释或元信息。",`2. 最多追问 ${g} 个关键问题。`,"3. 禁止使用“是否满足”“是否符合”“基本入职要求”等审查措辞。",...yr(s)].join("\n")}}function hr(e,n,t){const r=Dt(e);if(0===r.length)return!1;const a=new Set(Ct(n)),o=new Set(t.flatMap(e=>M[e]));return r.some(e=>!o.has(e)||!a.has(e))}function Nr(e){return"private_channel"===e||"interview_scheduling"===e}function Sr(e,n){return Number.isInteger(n)&&void 0!==n&&n>=1?n:0===e.length?1:2}function Tr(e,n){return 1===e||"trust_building"===n||"private_channel"===n?"minimal":"focused"}function Ar(e,n){const t=["- 只修正命中的违规点,没有命中的部分不要过度改写。"];return e.includes("too_many_questions")&&t.push(`- 删除多余追问,只保留最关键的 ${n} 个问题。`),e.includes("audit_tone")&&t.push("- 保留原意,但把审查式措辞改成自然口语,不要像筛选候选人。"),e.includes("premature_numeric_disclosure")&&t.push("- 把具体数字、时间和地址细节改成泛化表达,例如“细节我帮你确认”或“以门店安排为准”。"),e.includes("off_axis_fact_disclosure")&&t.push("- 删除不属于主回答轴的具体事实;如果要提到次要问题,只能做不带细节的承接。"),e.includes("reply_overpacked")&&t.push("- 压缩成最多两句,不要列表、不要枚举、不要一口气展开太多信息。"),t}async function Ir(e,n,t){const r=["请重写下面这条招聘回复。","要求:","- 不新增任何具体数字、地址、福利承诺。","- 仅保留泛化表达,强调可进一步沟通确认细节。","- 口语化、单行、简洁。","","[原回复]",e,"","[可用上下文]",t].join("\n"),a=await wn({model:n,prompt:r,context:"SmartReplyFactGateRewrite",timeoutMs:2e4,maxOutputTokens:500});return a.success?{text:a.text,usage:a.usage,latencyMs:a.latencyMs}:{text:e}}async function _r(e,n,t,r){const{turnIndex:a,effectiveDisclosureMode:o,primaryNeed:i,allowedNeeds:s,violations:l,policy:u}=r,c=u?.outputGuards.maxQuestionsByMode[o]??1,d=u?.outputGuards.blockedAuditPhrases.join("、")??"",m=Ar(l,c),p=(s??[]).filter(e=>e!==i&&"none"!==e),g=["请重写下面这条招聘回复。","要求:",`- 当前轮次=${a},披露模式=${o},主回答轴=${i}。`,p.length>0?`- 允许顺带覆盖的次要轴:${p.join("、")}。`:"",`- 当前违规点:${l.join("、")}。`,...m,"- 只保留单条口语化回复,不输出解释。",`- 问题数最多 ${c} 个。`,"- 围绕主回答轴回答,不主动展开其他事实轴。","- 首轮时不要主动报具体数字、时间、地址或筛选条件。",d?`- 禁止使用这些措辞:${d}。`:"","","[原回复]",e,"","[可用上下文]",t].filter(Boolean).join("\n"),f=await wn({model:n,prompt:g,context:"SmartReplyReplyGateRewrite",timeoutMs:2e4,maxOutputTokens:500});return f.success?{text:f.text,usage:f.usage,latencyMs:f.latencyMs}:{text:e}}async function Er(e){const n=jt();de(!0);try{return await Rr(e,n)}catch(e){throw n.fail("回复生成失败"),e}finally{de(!1)}}async function Rr(e,n){const{modelConfig:t,preferredBrand:r,toolBrand:a,brandPriorityStrategy:o,conversationHistory:i=[],candidateMessage:s,configData:l,replyPolicy:u,candidateInfo:c,defaultWechatId:d,industryVoiceId:m,channelType:p,turnIndex:g,ageEligibilitySources:f}=e,y=t?.providerConfigs||be,b=Me(l),h={...b?{city:b}:{},defaultBrand:ke(l),availableBrands:Re(l),storeCount:Ee(l).length},N=pr(c);n.update("分析对话意图...");const S=await nt(s,{modelConfig:t||{},conversationHistory:i,brandData:h,providerConfigs:y,...void 0!==p?{channelType:p}:{},...void 0!==u?{replyPolicy:u}:{},...N.knownFieldNames.length>0?{knownCandidateFields:N.knownFieldNames}:{}}),T=Sr(i,g),A=Tr(T,S.stage),I="focused"===A?Qn(S.primaryNeed,S.needs,s,2):[S.primaryNeed],_=a||S.extractedInfo.mentionedBrand||void 0;n.update("构建业务上下文...");const{contextInfo:E,debugInfo:R,resolvedBrand:L}=await Tt(l,S,r,_,o,c,u,m,T,A,I);n.update("校验候选人资格...");const O=cr(S,c),k=dr(S,c),M=S.extractedInfo.city??Me(l,L),v=f??ir({configData:l,token:je(),jobListUrl:$e()}),w=await sr({sources:v,brandAlias:L,..."string"==typeof M?{cityName:M}:{},...void 0!==k?{regionName:k}:{}}),D=lr({...void 0!==O?{age:O}:{},evidence:w.evidence,matchedCount:w.matchedCount,total:w.total,isComplete:w.isComplete,...void 0!==u?.qualificationPolicy?.age?{strategy:u.qualificationPolicy.age}:{}}),C=_e(y),U=t?.replyModel||he.replyModel,x=C.languageModel(U),$=br(u,S,I,E,s,i,T,A,N,m,d,D);n.update("生成回复...");const j=await wn({model:x,system:$.system,prompt:$.prompt,context:"SmartReply",timeoutMs:3e4,maxOutputTokens:2e3});if(!j.success)return n.fail("回复生成失败"),Tn("SmartReply 生成失败",j.error),{turnPlan:S,suggestedReply:"",confidence:0,shouldExchangeWechat:Nr(S.stage),factGateRewritten:!1,replyGateRewritten:!1,gateViolations:[],contextInfo:E,debugInfo:{...R,resolvedBrand:L,turnIndex:T,effectiveDisclosureMode:A,primaryNeed:S.primaryNeed,replyGateRewritten:!1,gateViolations:[],gateStatus:D.status,appliedStrategy:D.appliedStrategy,ageRangeSummary:D.summary},usage:void 0,error:j.error};let W=j.text,F=j.usage,P=j.latencyMs,B=!1,G=!1,q=[];if(n.update("检查回复质量..."),"strict"===u?.factGate.mode){if(hr(W,E,I)){B=!0;const e=await Ir(W,x,E);W=e.text,e.usage&&(F=e.usage),void 0!==e.latencyMs&&(P=(P??0)+e.latencyMs)}}if(q=xt({text:W,turnIndex:T,mode:A,primaryNeed:S.primaryNeed,allowedNeeds:I,policy:u}).violations,q.length>0){n.update("优化回复..."),G=!0;const e=await _r(W,x,E,{turnIndex:T,effectiveDisclosureMode:A,primaryNeed:S.primaryNeed,allowedNeeds:I,violations:q,policy:u});W=e.text,e.usage&&(F=e.usage),void 0!==e.latencyMs&&(P=(P??0)+e.latencyMs),q=xt({text:W,turnIndex:T,mode:A,primaryNeed:S.primaryNeed,allowedNeeds:I,policy:u}).violations}const H=P??0,K=F?.totalTokens??0;return n.succeed(`回复已生成 | ${S.stage} | ${H}ms | ${K} tokens${G?" | 已优化":""}`),{turnPlan:S,suggestedReply:W,confidence:Math.max(0,Math.min(1,S.confidence)),shouldExchangeWechat:Nr(S.stage),factGateRewritten:B,replyGateRewritten:G,gateViolations:q,contextInfo:`${E}\n当前品牌:${L}`,debugInfo:{...R,resolvedBrand:L,turnIndex:T,effectiveDisclosureMode:A,primaryNeed:S.primaryNeed,replyGateRewritten:G,gateViolations:q,gateStatus:D.status,appliedStrategy:D.appliedStrategy,ageRangeSummary:D.summary},usage:F,latencyMs:P}}var Lr=t.enum(At),Or=t.enum(Ft),kr=n({name:"generate_reply",description:"根据候选人消息、对话历史和品牌数据生成智能招聘回复。内部流程:回合规划 → primaryNeed 驱动上下文构建 → 年龄资格校验 → 策略化回复生成 → FactGate/ReplyGate 校验。",input:t.object({candidateMessage:t.string().describe("候选人发送的消息"),conversationHistory:t.array(t.string()).optional().describe("对话历史(最近几轮)"),candidateInfo:i.optional().describe("候选人基本信息"),preferredBrand:t.string().optional().describe("偏好品牌"),channelType:_.optional().describe("渠道类型: public(BOSS直聘) 或 private(微信)"),defaultWechatId:t.string().optional().describe("默认微信号"),industryVoiceId:t.string().optional().describe("行业语调ID"),turnIndex:t.number().int().min(1).optional().describe("当前会话回复轮次"),modelConfig:xn.optional().describe("模型配置覆盖")}),output:t.object({suggestedReply:t.string(),confidence:t.number(),stage:I,latencyMs:t.number().optional(),shouldExchangeWechat:t.boolean().optional(),error:t.string().optional(),diagnostics:t.object({subGoals:t.array(t.string()),needs:t.array(O),primaryNeed:O,riskFlags:t.array(k),reasoningText:t.string(),extractedInfo:t.object({mentionedBrand:t.string().nullable(),city:t.string().nullable(),specificAge:t.number().nullable(),hasUrgency:t.boolean().nullable(),preferredSchedule:t.string().nullable()}),ageGate:t.object({enabled:t.boolean(),status:Or,strategy:t.string()}),resolvedBrand:t.string(),storeCount:t.number(),detailLevel:E,turnIndex:t.number(),effectiveDisclosureMode:E,replyGateRewritten:t.boolean(),gateViolations:t.array(Lr),factGateRewritten:t.boolean()}).optional()}),execute:async(e,n)=>{let t;n.logger.info(`Processing message: ${e.candidateMessage.slice(0,50)}...`);try{t=ee()}catch{return{suggestedReply:"",confidence:0,stage:"trust_building",error:"品牌数据未配置,请先调用 sync_brand_data 写入数据"}}const r=te(),a=await Er({candidateMessage:e.candidateMessage,conversationHistory:e.conversationHistory,candidateInfo:e.candidateInfo,preferredBrand:e.preferredBrand,channelType:e.channelType,defaultWechatId:e.defaultWechatId,industryVoiceId:e.industryVoiceId,turnIndex:e.turnIndex,modelConfig:e.modelConfig,configData:t,replyPolicy:r});n.logger.info(`Reply generated. Stage: ${a.turnPlan.stage}, Confidence: ${a.confidence}`);const o=a.debugInfo;return{suggestedReply:a.suggestedReply,confidence:a.confidence,stage:a.turnPlan.stage,latencyMs:a.latencyMs,shouldExchangeWechat:a.shouldExchangeWechat,error:a.error?.userMessage,diagnostics:o?{subGoals:a.turnPlan.subGoals,needs:a.turnPlan.needs,primaryNeed:a.turnPlan.primaryNeed,riskFlags:a.turnPlan.riskFlags,reasoningText:a.turnPlan.reasoningText,extractedInfo:{mentionedBrand:a.turnPlan.extractedInfo.mentionedBrand??null,city:a.turnPlan.extractedInfo.city??null,specificAge:a.turnPlan.extractedInfo.specificAge??null,hasUrgency:a.turnPlan.extractedInfo.hasUrgency??null,preferredSchedule:a.turnPlan.extractedInfo.preferredSchedule??null},ageGate:{enabled:o.appliedStrategy.enabled,status:o.gateStatus,strategy:o.appliedStrategy.strategy},resolvedBrand:o.resolvedBrand,storeCount:o.storeCount,detailLevel:o.detailLevel,turnIndex:o.turnIndex,effectiveDisclosureMode:o.effectiveDisclosureMode,replyGateRewritten:a.replyGateRewritten,gateViolations:a.gateViolations,factGateRewritten:a.factGateRewritten}:void 0}}});import{defineTool as Mr}from"@roll-agent/sdk";import{z as vr}from"zod";import{z as wr}from"zod";var Dr=wr.object({content:wr.string(),image:wr.string().nullable().optional()}).passthrough(),Cr=wr.object({storeId:wr.number().optional(),storeName:wr.string(),storeCityName:wr.string().optional(),storeRegionName:wr.string().optional(),storeAddress:wr.string().optional(),longitude:wr.number().optional(),latitude:wr.number().optional()}).passthrough(),Ur=wr.object({jobId:wr.number(),jobName:wr.string(),jobNickName:wr.string().nullable().optional(),jobCategoryName:wr.string().nullable().optional(),jobContent:wr.string().nullable().optional(),laborForm:wr.string().nullable().optional(),needTraining:wr.string().nullable().optional(),needProbationWork:wr.string().nullable().optional(),brandId:wr.number().optional(),brandName:wr.string().optional(),projectId:wr.number().optional(),projectName:wr.string().optional(),storeInfo:Cr.optional()}).passthrough(),xr=wr.object({salaryType:wr.string().nullable().optional(),salaryPeriod:wr.string().nullable().optional(),hasStairSalary:wr.string().nullable().optional(),basicSalary:wr.object({basicSalary:wr.number().nullable().optional(),basicSalaryUnit:wr.string().nullable().optional()}).passthrough().nullable().optional(),stairSalaries:wr.array(wr.object({fullWorkTime:wr.number().nullable().optional(),fullWorkTimeUnit:wr.string().nullable().optional(),salary:wr.number().nullable().optional(),salaryUnit:wr.string().nullable().optional()}).passthrough()).nullable().optional(),comprehensiveSalary:wr.object({minComprehensiveSalary:wr.number().nullable().optional(),maxComprehensiveSalary:wr.number().nullable().optional(),comprehensiveSalaryUnit:wr.string().nullable().optional()}).passthrough().nullable().optional(),holidaySalary:wr.object({holidaySalaryType:wr.string().nullable().optional(),holidaySalaryMultiple:wr.number().nullable().optional(),holidayFixedSalary:wr.number().nullable().optional(),holidayFixedSalaryUnit:wr.string().nullable().optional()}).passthrough().nullable().optional()}).passthrough(),$r=wr.object({salary:wr.number().optional(),salaryUnitStr:wr.string().optional(),salaryScenarioList:wr.array(xr).nullable().optional()}).passthrough(),jr=wr.object({haveInsurance:wr.string(),accommodation:wr.string(),catering:wr.string().optional(),otherWelfare:wr.array(wr.string()).nullable().optional(),accommodationAllowance:wr.number().nullable().optional(),accommodationAllowanceUnit:wr.string().nullable().optional(),cateringSalary:wr.number().nullable().optional(),cateringSalaryUnit:wr.string().nullable().optional(),trafficAllowanceSalary:wr.number().nullable().optional(),trafficAllowanceSalaryUnit:wr.string().nullable().optional(),memo:wr.string().nullable().optional(),promotionWelfare:wr.string().nullable().optional(),moreWelfares:wr.array(Dr).nullable().optional()}).passthrough(),Wr=wr.object({minAge:wr.number().nullable().optional(),maxAge:wr.number().nullable().optional(),genderRequirement:wr.string().nullable().optional()}).passthrough(),Fr=wr.object({education:wr.string().nullable().optional(),healthCertificate:wr.string().nullable().optional(),certificates:wr.string().nullable().optional()}).passthrough(),Pr=wr.object({languages:wr.string().nullable().optional(),languageRemark:wr.string().nullable().optional()}).passthrough(),Br=wr.object({cooperationMode:wr.number().optional(),requirementNum:wr.number().optional(),thresholdNum:wr.number().optional(),signUpNum:wr.number().nullable().optional(),basicPersonalRequirements:Wr.nullable().optional(),certificate:Fr.nullable().optional(),language:Pr.nullable().optional(),figure:wr.string().nullable().optional(),remark:wr.string().nullable().optional()}).passthrough(),Gr=wr.object({employmentForm:wr.string(),minWorkMonths:wr.number().nullable().optional(),maxWorkTakingTime:wr.number().nullable().optional(),restTimeDesc:wr.string().nullable().optional(),workTimeRemark:wr.string().nullable().optional(),employmentDescription:wr.string().nullable().optional(),weekWorkTime:wr.object({weekWorkTimeRequirement:wr.string().nullable().optional(),perWeekWorkDays:wr.number().nullable().optional(),perWeekRestDays:wr.number().nullable().optional(),perWeekNeedWorkDays:wr.union([wr.string(),wr.number()]).nullable().optional(),workSingleDouble:wr.string().nullable().optional(),customnWorkTimeList:wr.array(wr.object({customMinWorkDays:wr.number().nullable().optional(),customMaxWorkDays:wr.number().nullable().optional(),customWorkWeekdays:wr.array(wr.union([wr.string(),wr.number()])).nullable().optional()}).passthrough()).nullable().optional()}).passthrough().nullable().optional(),monthWorkTime:wr.object({perMonthMinWorkTime:wr.number().nullable().optional(),perMonthMinWorkTimeUnit:wr.union([wr.string(),wr.number()]).nullable().optional(),monthWorkTimeRequirement:wr.string().nullable().optional(),perMonthMaxRestTime:wr.number().nullable().optional(),perMonthMaxRestTimeUnit:wr.number().nullable().optional()}).passthrough().nullable().optional(),dayWorkTime:wr.object({perDayMinWorkHours:wr.union([wr.string(),wr.number()]).nullable().optional(),dayWorkTimeRequirement:wr.string().nullable().optional()}).passthrough().nullable().optional(),dailyShiftSchedule:wr.object({arrangementType:wr.string().nullable().optional(),fixedScheduleList:wr.array(wr.object({fixedShiftStartTime:wr.union([wr.string(),wr.number()]).optional(),fixedShiftEndTime:wr.union([wr.string(),wr.number()]).optional(),startTime:wr.number().optional(),endTime:wr.number().optional()}).passthrough()).nullable().optional(),combinedArrangement:wr.array(wr.object({CombinedArrangementWeekdays:wr.union([wr.string(),wr.array(wr.number())]).optional(),CombinedArrangementStartTime:wr.number().optional(),CombinedArrangementEndTime:wr.number().optional(),combinedArrangementStartTime:wr.union([wr.string(),wr.number()]).optional(),combinedArrangementEndTime:wr.union([wr.string(),wr.number()]).optional(),startTime:wr.number().optional(),endTime:wr.number().optional(),weekdays:wr.array(wr.number()).optional()}).passthrough()).nullable().optional(),fixedTime:wr.object({goToWorkStartTime:wr.union([wr.string(),wr.number()]).nullable().optional(),goToWorkEndTime:wr.union([wr.string(),wr.number()]).nullable().optional(),goOffWorkStartTime:wr.union([wr.string(),wr.number()]).nullable().optional(),goOffWorkEndTime:wr.union([wr.string(),wr.number()]).nullable().optional()}).passthrough().nullable().optional()}).passthrough().nullable().optional(),temporaryEmployment:wr.object({temporaryEmploymentStartTime:wr.string().nullable().optional(),temporaryEmploymentEndTime:wr.string().nullable().optional()}).passthrough().nullable().optional()}).passthrough(),qr=wr.object({basicInfo:Ur,jobSalary:$r,welfare:jr,hiringRequirement:Br,workTime:Gr}).passthrough();function Hr(e){const n=qr.safeParse(e);if(!n.success)return null;const t=n.data,r=t.basicInfo,a=r.storeInfo,o=t.jobSalary,i=t.hiringRequirement,s=o.salary??o.salaryScenarioList?.find(e=>"正式"===e.salaryType)?.basicSalary?.basicSalary??o.salaryScenarioList?.[0]?.basicSalary?.basicSalary??null,l=o.salaryUnitStr??o.salaryScenarioList?.find(e=>"正式"===e.salaryType)?.basicSalary?.basicSalaryUnit??o.salaryScenarioList?.[0]?.basicSalary?.basicSalaryUnit??null;let u=a?.storeId;if(null==u){const e=`${a?.storeName??""}|${a?.storeAddress??""}`;u=Array.from(e).reduce((e,n)=>31*e+n.charCodeAt(0)>>>0,7)}return{jobId:r.jobId,jobName:r.jobName,jobNickName:r.jobNickName??null,jobCategoryName:r.jobCategoryName??null,jobContent:r.jobContent??null,laborForm:r.laborForm??null,employmentForm:t.workTime.employmentForm,trainingRequired:r.needTraining??null,probationRequired:r.needProbationWork??null,brandId:void 0!==r.brandId?String(r.brandId):void 0!==r.projectId?String(r.projectId):void 0,brandName:r.brandName,projectId:r.projectId,projectName:r.projectName,storeId:u,storeName:a?.storeName??"未知门店",storeCityName:a?.storeCityName??"",storeRegionName:a?.storeRegionName,storeAddress:a?.storeAddress??"",longitude:a?.longitude,latitude:a?.latitude,salary:s,salaryUnitStr:l,salaryScenarioList:o.salaryScenarioList??null,welfare:t.welfare,requirementNum:i.requirementNum??0,signUpNum:i.signUpNum??null,basicPersonalRequirements:i.basicPersonalRequirements?{minAge:i.basicPersonalRequirements.minAge??null,maxAge:i.basicPersonalRequirements.maxAge??null,genderRequirement:i.basicPersonalRequirements.genderRequirement??null}:null,certificate:i.certificate?{education:i.certificate.education??null,healthCertificate:i.certificate.healthCertificate??null}:null,languages:i.language?.languages??null,certificatesRaw:i.certificate?.certificates??null,recruitmentRemark:i.remark??null,socialIdentity:i.figure??null,workTime:t.workTime,perMonthMinWorkTime:t.workTime.monthWorkTime?.perMonthMinWorkTime??null,perMonthMinWorkTimeUnit:t.workTime.monthWorkTime?.perMonthMinWorkTimeUnit??null}}function Kr(e,n,t){const r=new Map;let a;for(let o=0;o<e.length;o++){const i=Hr(e[o]);if(!i)continue;const s=i.brandName??n??"未知品牌",l=i.brandId??`name:${s}`;void 0!==a||void 0!==n&&s!==n||(a=l);let u=r.get(l);u||(u={id:l,name:s,stores:[]},r.set(l,u));const c=`store_${i.storeId}`;let d=u.stores.find(e=>e.id===c);d||(d=Vr(i,l,t),u.stores.push(d));const m=zr(i);d.positions.push(m)}return{meta:{...a??r.values().next().value?.id?{defaultBrandId:a??r.values().next().value?.id}:{},syncedAt:(new Date).toISOString(),source:"duliday"},brands:Array.from(r.values())}}function Vr(e,n,t){return{id:`store_${e.storeId}`,brandId:n,name:e.storeName,city:e.storeCityName||t,location:e.storeAddress,district:sa(e.storeAddress,e.storeRegionName),subarea:la(e.storeName),coordinates:"number"==typeof e.latitude&&"number"==typeof e.longitude?{lat:e.latitude,lng:e.longitude}:{lat:0,lng:0},positions:[]}}function zr(e){const n=Yr(e.workTime);let t=[];return n.combinedArrangementTimes?.length?t=ia(n.combinedArrangementTimes):n.fixedArrangementTimes?.length&&(t=ia(n.fixedArrangementTimes.map(e=>({...e,weekdays:[]})))),{id:`pos_${e.jobId}`,name:e.jobNickName??ua(e.jobName),sourceJobName:e.jobName,jobCategory:e.jobCategoryName,brandId:e.brandId,brandName:e.brandName,projectId:void 0!==e.projectId?String(e.projectId):void 0,projectName:e.projectName,description:e.jobContent||null,laborForm:e.laborForm,employmentForm:e.employmentForm,trainingRequired:e.trainingRequired,probationRequired:e.probationRequired,salary:{...Jr(e.salary,e.salaryUnitStr,e.welfare),scenarioSummary:Qr(e.salaryScenarioList),settlementCycle:Zr(e.salaryScenarioList)},timeSlots:t,workHours:null!=n.perDayMinWorkHours?String(n.perDayMinWorkHours):null,minHoursPerWeek:ta(n),maxHoursPerWeek:ra(n),perMonthMinWorkTime:e.perMonthMinWorkTime,perMonthMinWorkTimeUnit:e.perMonthMinWorkTimeUnit,attendanceRequirement:aa(n),availableSlots:na(e,n),benefits:Xr(e.welfare),hiringRequirements:ea(e)}}function Yr(e){const n=e.weekWorkTime,t=e.dayWorkTime,r=e.dailyShiftSchedule,a=Number(r?.arrangementType)||({"固定排班制":1,"组合排班制":3}[String(r?.arrangementType)]??0),o=null!=t?.perDayMinWorkHours?Number(t.perDayMinWorkHours):null,i=null!==o&&Number.isFinite(o)?o:null,s=n?.customnWorkTimeList?.map(e=>({weekdays:Array.isArray(e.customWorkWeekdays)?e.customWorkWeekdays.map(e=>Number(e)).filter(e=>Number.isFinite(e)):[],minWorkDays:e.customMinWorkDays??null,maxWorkDays:e.customMaxWorkDays??null}))??null,l=r?.fixedScheduleList?.map(e=>({startTime:e.startTime??oa(e.fixedShiftStartTime),endTime:e.endTime??oa(e.fixedShiftEndTime)}))??null,u=r?.combinedArrangement?.map(e=>{const n=null!=e.combinedArrangementStartTime?oa(e.combinedArrangementStartTime):void 0,t=null!=e.combinedArrangementEndTime?oa(e.combinedArrangementEndTime):void 0,r=(e.weekdays??("string"==typeof e.CombinedArrangementWeekdays?[Number(e.CombinedArrangementWeekdays)]:Array.isArray(e.CombinedArrangementWeekdays)?e.CombinedArrangementWeekdays:[])).map(e=>"number"==typeof e?e:Number(e)).filter(e=>Number.isFinite(e));return{startTime:e.startTime??e.CombinedArrangementStartTime??n??0,endTime:e.endTime??e.CombinedArrangementEndTime??t??0,weekdays:r}})??null;return{perDayMinWorkHours:i,perWeekWorkDays:n?.perWeekWorkDays??null,perWeekNeedWorkDays:null!=n?.perWeekNeedWorkDays?Number(n.perWeekNeedWorkDays):null,perWeekRestDays:n?.perWeekRestDays??null,arrangementType:a,maxWorkTakingTime:e.maxWorkTakingTime??0,workTimeRemark:e.workTimeRemark??null,fixedArrangementTimes:l,combinedArrangementTimes:u,customWorkTimes:s}}function Jr(e,n,t){const r=t.memo??null,a=r?.match(/(\d+元?-\d+元?)/),o=a?a[1]:void 0,i=r?.match(/(奖金[\d~\-~元]+)/);return{base:e,unit:n,range:o,bonus:i?i[1]:void 0,memo:r}}function Qr(e){if(!e||0===e.length)return;const n=[];for(const t of e){if("培训期"===t.salaryType)continue;if(t.stairSalaries?.length){const e=t.stairSalaries.filter(e=>null!=e.salary).map(e=>{const n=e.salaryUnit??"元/时";return`满${e.fullWorkTime??"?"}${e.fullWorkTimeUnit??"小时"}后${e.salary}${n}`}).join(",");e&&n.push(e)}const e=t.comprehensiveSalary;null!=e?.minComprehensiveSalary&&null!=e?.maxComprehensiveSalary&&n.push(`综合${e.minComprehensiveSalary}-${e.maxComprehensiveSalary}${e.comprehensiveSalaryUnit??"元/月"}`);const r=t.holidaySalary;r&&(r.holidaySalaryMultiple?n.push(`节假日${r.holidaySalaryMultiple}倍`):null!=r.holidayFixedSalary&&n.push(`节假日${r.holidayFixedSalary}${r.holidayFixedSalaryUnit??"元/时"}`))}return n.length>0?n.join(";"):void 0}function Zr(e){if(!e||0===e.length)return;const n=e.find(e=>"正式"===e.salaryType)??e[0];return{"日结算":"日结","周结算":"周结","月结算":"月结","完结算":"完结","半月结算":"半月结"}[n?.salaryPeriod??""]??void 0}function Xr(e){const n=e.moreWelfares&&Array.isArray(e.moreWelfares)&&e.moreWelfares.length>0?e.moreWelfares.map(e=>e.content):null;return{insurance:e.haveInsurance||null,accommodation:e.accommodation||null,catering:e.catering??null,moreWelfares:n,memo:e.memo??null,promotion:e.promotionWelfare??null}}function ea(e){const n=e.basicPersonalRequirements,t=e.certificate;if(n||t||e.languages||e.certificatesRaw||e.recruitmentRemark||e.socialIdentity)return{minAge:n?.minAge??null,maxAge:n?.maxAge??null,genderRequirement:n?.genderRequirement??null,education:t?.education??null,healthCertificate:t?.healthCertificate??null,languages:e.languages,certificatesRaw:e.certificatesRaw,recruitmentRemark:e.recruitmentRemark,socialIdentity:e.socialIdentity}}function na(e,n){const t=[];let r=[];n.combinedArrangementTimes?.length?r=ia(n.combinedArrangementTimes):n.fixedArrangementTimes?.length&&(r=ia(n.fixedArrangementTimes.map(e=>({...e,weekdays:[]}))));for(const n of r)t.push({slot:n,maxCapacity:e.requirementNum,currentBooked:e.signUpNum||0,isAvailable:(e.signUpNum||0)<e.requirementNum,priority:e.requirementNum>3?"high":"medium"});return t}function ta(e){const n=e.perDayMinWorkHours;if(null==n)return null;let t=null;if(null!=e.perWeekWorkDays&&(t=e.perWeekWorkDays),null===t&&e.customWorkTimes?.length){const n=e.customWorkTimes.map(e=>e.minWorkDays).filter(e=>null!=e);n.length>0&&(t=Math.min(...n))}return null===t&&null!=e.perWeekNeedWorkDays&&(t=e.perWeekNeedWorkDays),null===t?null:n*t}function ra(e){const n=e.perDayMinWorkHours;if(null==n||null==e.perWeekWorkDays)return null;return n*e.perWeekWorkDays}function aa(e){let n=[];if(e.combinedArrangementTimes?.length){const t=new Set;for(const n of e.combinedArrangementTimes)for(const e of n.weekdays)null!=e&&Number.isFinite(e)&&t.add(e);n=Array.from(t).sort()}else if(e.customWorkTimes?.length){const t=new Set;for(const n of e.customWorkTimes)for(const e of n.weekdays)null!=e&&Number.isFinite(e)&&t.add(e);n=Array.from(t).sort()}let t=null;if(null!=e.perWeekWorkDays&&(t=e.perWeekWorkDays),null===t&&e.customWorkTimes?.length){const n=e.customWorkTimes.map(e=>e.minWorkDays).filter(e=>null!=e);n.length>0&&(t=Math.min(...n))}return null===t&&null!=e.perWeekNeedWorkDays&&(t=e.perWeekNeedWorkDays),{minimumDays:t,requiredDays:ca(n),description:e.workTimeRemark??null}}function oa(e){if("number"==typeof e)return e;if("string"!=typeof e||!e)return 0;const n=e.match(/^(\d{1,2}):(\d{2})$/);return n?3600*Number(n[1])+60*Number(n[2]):Number(e)||0}function ia(e){return e.map(e=>{const n=Math.floor(e.startTime/3600),t=Math.floor(e.startTime%3600/60),r=Math.floor(e.endTime/3600),a=Math.floor(e.endTime%3600/60);return`${n.toString().padStart(2,"0")}:${t.toString().padStart(2,"0")}~${r.toString().padStart(2,"0")}:${a.toString().padStart(2,"0")}`})}function sa(e,n){if(n)return n;return e.split("-")[1]||null}function la(e){const n=e.match(/(.+?)(附近|周边|旁边|店)/);return n?.[1]??null}function ua(e){const n=e.split("-");return n[n.length-2]||e}function ca(e){return e.filter(e=>Number.isFinite(e)).map(e=>0===e?7:e)}var da=Mr({name:"sync_brand_data",description:"从 Duliday API 拉取并同步品牌配置数据(门店、岗位、薪资等)到本地。可选传入品牌别名和城市名称作为过滤条件。",input:vr.object({brandAlias:vr.string().optional().describe("品牌别名(可选,配合 cityName 使用可按品牌过滤)"),cityName:vr.string().describe('城市名称(必填,Duliday API 要求至少提供城市作为筛选条件,如 "上海市")')}),output:vr.object({success:vr.boolean(),brandsCount:vr.number(),storesCount:vr.number(),positionsCount:vr.number(),updatedAt:vr.string(),error:vr.string().optional()}),execute:async(e,n)=>{const t=je(),r=$e();if(!t||!r)return{success:!1,brandsCount:0,storesCount:0,positionsCount:0,updatedAt:(new Date).toISOString(),error:`缺少环境变量: ${[!t&&"DULIDAY_TOKEN",!r&&"DULIDAY_JOB_LIST_URL"].filter(Boolean).join(", ")}`};if(!e.cityName)return{success:!1,brandsCount:0,storesCount:0,positionsCount:0,updatedAt:(new Date).toISOString(),error:'cityName 为必填项,Duliday API 要求至少提供城市作为筛选条件(如 "上海市")'};try{n.logger.info("Fetching all job list pages from Duliday API...");const{items:a}=await Ve(t,r,{brandAlias:e.brandAlias??null,cityName:e.cityName??null,include:qe});let o=pa(a);!o&&e.brandAlias&&(o=await ga(e.brandAlias,t)),!o&&e.brandAlias&&(o=e.brandAlias),n.logger.info(`Resolved default brand: ${o??"自动推断"}, converting ${a.length} positions...`);const i=Kr(a,o,e.cityName);ne(i),n.logger.info(`Brand config saved: ${i.brands.length} brands, ${i.brands.reduce((e,n)=>e+n.stores.length,0)} stores`);const s=i.brands.reduce((e,n)=>e+n.stores.length,0),l=i.brands.reduce((e,n)=>e+n.stores.reduce((e,n)=>e+n.positions.length,0),0);return{success:!0,brandsCount:i.brands.length,storesCount:s,positionsCount:l,updatedAt:(new Date).toISOString()}}catch(e){return{success:!1,brandsCount:0,storesCount:0,positionsCount:0,updatedAt:(new Date).toISOString(),error:e instanceof Error?e.message:String(e)}}}});function ma(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function pa(e){for(const n of e){if(!ma(n))continue;const e=ma(n.basicInfo)?n.basicInfo:null;if(e&&"string"==typeof e.brandName&&e.brandName)return e.brandName}}async function ga(e,n){try{const t=await pt(n),r=e.trim().toLowerCase().replace(/[\s._-]+/g,"");return t.get(r)}catch{return}}var fa=e({name:"smart-reply-agent",tools:[kr,da]});fa.listen().catch(e=>{console.error("Fatal error:",e),process.exit(1)});
1
+ import{defineAgent as e}from"@roll-agent/sdk";import{defineTool as n}from"@roll-agent/sdk";import{z as t}from"zod";import{z as r}from"zod";import{z as a}from"zod";var o=a.object({lat:a.number(),lng:a.number()}),i=r.object({name:r.string().optional(),position:r.string().optional(),expectedPosition:r.string().optional(),communicationPosition:r.string().optional(),age:r.string().optional(),gender:r.string().optional(),experience:r.string().optional(),education:r.string().optional(),expectedSalary:r.string().optional(),expectedLocation:r.string().optional(),jobAddress:r.string().optional(),height:r.string().optional(),weight:r.string().optional(),healthCertificate:r.boolean().optional(),activeTime:r.string().optional(),info:r.array(r.string()).optional(),fullText:r.string().optional()}),s=r.object({base:r.number().nullable(),unit:r.string().nullable(),range:r.string().optional(),bonus:r.string().optional(),memo:r.string().nullable(),scenarioSummary:r.string().optional(),settlementCycle:r.string().optional()}),l=r.object({insurance:r.string().nullable(),accommodation:r.string().nullable(),catering:r.string().nullable(),moreWelfares:r.array(r.string()).nullable(),memo:r.string().nullable(),promotion:r.string().nullable()}),u=r.object({requiredDays:r.array(r.number().min(1).max(7)).optional(),minimumDays:r.number().min(0).nullable(),description:r.string().nullable()}),c=r.object({slot:r.string(),maxCapacity:r.number().min(0),currentBooked:r.number().min(0),isAvailable:r.boolean(),priority:r.enum(["high","medium","low"])}),d=r.object({minAge:r.number().nullable().optional(),maxAge:r.number().nullable().optional(),genderRequirement:r.string().nullable().optional(),education:r.string().nullable().optional(),healthCertificate:r.string().nullable().optional(),languages:r.string().nullable().optional(),certificatesRaw:r.string().nullable().optional(),recruitmentRemark:r.string().nullable().optional(),socialIdentity:r.string().nullable().optional()}),m=r.object({id:r.string(),name:r.string(),sourceJobName:r.string(),jobCategory:r.string().nullable(),brandId:r.string().optional(),brandName:r.string().optional(),projectId:r.string().optional(),projectName:r.string().optional(),description:r.string().nullable(),laborForm:r.string().nullable(),employmentForm:r.string().nullable(),trainingRequired:r.string().nullable(),probationRequired:r.string().nullable(),salary:s,timeSlots:r.array(r.string()),workHours:r.string().nullable(),minHoursPerWeek:r.number().min(0).nullable(),maxHoursPerWeek:r.number().min(0).nullable(),perMonthMinWorkTime:r.number().nullable(),perMonthMinWorkTimeUnit:r.union([r.string(),r.number()]).nullable(),attendanceRequirement:u.optional(),availableSlots:r.array(c),benefits:l,hiringRequirements:d.optional()}),p=r.object({id:r.string(),brandId:r.string(),name:r.string(),city:r.string().optional(),location:r.string(),district:r.string().nullable(),subarea:r.string().nullable(),coordinates:o,positions:r.array(m)}),g=r.object({defaultBrandId:r.string().optional(),syncedAt:r.string().optional(),source:r.string().optional()}),f=r.object({id:r.string(),name:r.string(),aliases:r.array(r.string()).optional(),stores:r.array(p)}),y=r.object({meta:g,brands:r.array(f)});import{existsSync as b,readFileSync as h,writeFileSync as N}from"node:fs";import{dirname as S,join as T}from"node:path";import{z as A}from"zod";var I=A.enum(["trust_building","private_channel","qualify_candidate","job_consultation","interview_scheduling","onboard_followup"]),_=A.enum(["public","private"]),E=A.enum(["minimal","focused"]),R=A.enum(["salary","schedule","location","policy","requirements","availability"]),L={trust_building:{description:"初次接触,建立信任并了解求职意向",transitionSignal:"候选人表达明确兴趣或开始询问具体岗位信息",applicableChannels:["public","private"]},private_channel:{description:"引导用户从公域平台(如BOSS直聘/鱼泡)转入微信私聊",transitionSignal:"候选人有继续深入了解的意愿,适合引导到私域",applicableChannels:["public"]},qualify_candidate:{description:"轻量确认候选人的关键匹配信息,避免审查式盘问",transitionSignal:"候选人表达求职意向后,需要核实基本资格",applicableChannels:["public","private"]},job_consultation:{description:"回答岗位相关问题(薪资、排班、地点等)并提升兴趣",transitionSignal:"候选人主动询问岗位细节",applicableChannels:["public","private"]},interview_scheduling:{description:"推动面试预约,确认时间和到店安排",transitionSignal:"候选人核心问题已解答,准备推进面试",applicableChannels:["public","private"]},onboard_followup:{description:"促进到岗并保持回访",transitionSignal:"候选人确认上岗安排",applicableChannels:["public","private"]}},O=A.enum(["stores","location","salary","schedule","policy","availability","requirements","interview","wechat","none"]),k=A.enum(["insurance_promise_risk","age_sensitive","confrontation_emotion","urgency_high","qualification_mismatch"]),v={stores:["location"],location:["location"],salary:["salary"],schedule:["schedule"],policy:["policy"],availability:["availability"],requirements:["requirements"],interview:[],wechat:[],none:[]},M=A.object({mentionedBrand:A.string().nullable(),city:A.string().nullable(),mentionedLocations:A.array(A.object({location:A.string(),confidence:A.number().min(0).max(1)})).nullable(),mentionedDistricts:A.array(A.object({district:A.string(),confidence:A.number().min(0).max(1)})).max(10).nullable(),specificAge:A.number().nullable(),hasUrgency:A.boolean().nullable(),preferredSchedule:A.string().nullable()}),w=A.object({stage:I,subGoals:A.array(A.string()).max(2),needs:A.array(O).max(8),primaryNeed:O,riskFlags:A.array(k).max(6),confidence:A.number().min(0).max(1),extractedInfo:M,reasoningText:A.string()}),D=A.object({description:A.string().optional(),primaryGoal:A.string(),successCriteria:A.array(A.string()),ctaStrategy:A.preprocess(e=>Array.isArray(e)?e.join("\n"):e,A.string()),disallowedActions:A.array(A.string()).optional()}),C=A.object({tone:A.string(),warmth:A.string(),humor:A.string(),length:A.enum(["short","medium","long"]),questionStyle:A.string(),empathyStrategy:A.string(),addressStyle:A.string(),professionalIdentity:A.string(),companyBackground:A.string()}),U=A.object({name:A.string(),industryBackground:A.string(),jargon:A.array(A.string()),styleKeywords:A.array(A.string()),tabooPhrases:A.array(A.string()),guidance:A.array(A.string())}),x=A.object({id:A.string(),rule:A.string(),severity:A.enum(["high","medium","low"])}),$=A.object({rules:A.array(x)}),j=A.object({mode:A.enum(["strict","balanced","open"]),verifiableClaimTypes:A.array(A.string()),fallbackBehavior:A.enum(["generic_answer","ask_followup","handoff"]),forbiddenWhenMissingFacts:A.array(A.string())}),W={maxQuestionsByMode:{minimal:1,focused:2},blockedAuditPhrases:["是否满足","是否符合","基本入职要求","先确认资格","年龄是否符合"],blockFirstTurnSpecificFacts:!0},F=A.object({maxQuestionsByMode:A.object({minimal:A.number().int().min(0),focused:A.number().int().min(0)}),blockedAuditPhrases:A.array(A.string()),blockFirstTurnSpecificFacts:A.boolean()}),P=A.object({enabled:A.boolean().default(!0),revealRange:A.boolean().default(!1),failStrategy:A.string().default("礼貌说明不匹配,避免承诺"),unknownStrategy:A.string().default("先核实年龄或资格条件"),passStrategy:A.string().default("确认匹配后推进下一步"),allowRedirect:A.boolean().default(!0),redirectPriority:A.enum(["low","medium","high"]).default("medium")}),B=A.object({age:P.default({enabled:!0,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!0,redirectPriority:"medium"})}).default({age:{enabled:!0,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!0,redirectPriority:"medium"}}),G=A.object({trust_building:D,private_channel:D.optional(),qualify_candidate:D,job_consultation:D,interview_scheduling:D,onboard_followup:D}).transform(e=>({...e,private_channel:e.private_channel??e.trust_building})),q=A.object({stageGoals:G,persona:C,industryVoices:A.record(A.string(),U),defaultIndustryVoiceId:A.string(),hardConstraints:$,factGate:j,qualificationPolicy:B,outputGuards:F.default(W)}),H={stageGoals:{trust_building:{description:"初次接触,建立信任并了解求职意向",primaryGoal:"建立信任并了解求职意向",successCriteria:["候选人愿意继续沟通"],ctaStrategy:"用轻量提问引导需求细化",disallowedActions:["过早承诺具体待遇"]},private_channel:{description:"引导用户从公域平台(如BOSS直聘/鱼泡)转入微信私聊",primaryGoal:"推动进入私域沟通",successCriteria:["候选人愿意交换联系方式"],ctaStrategy:"说明后续沟通效率与资料同步价值",disallowedActions:["强迫式要微信"]},qualify_candidate:{description:"轻量确认候选人的关键匹配信息,避免审查式盘问",primaryGoal:"确认一个关键匹配信息并保持继续沟通意愿",successCriteria:["明确一个关键匹配信息","候选人愿意继续沟通"],ctaStrategy:"先回应关切,再顺带确认一个最关键条件",disallowedActions:["连续盘问多个资格条件","直接否定候选人"]},job_consultation:{description:"回答岗位相关问题(薪资、排班、地点等)并提升兴趣",primaryGoal:"回答岗位问题并提升兴趣",successCriteria:["候选人对岗位保持兴趣"],ctaStrategy:"先答核心问题,再给下一步建议",disallowedActions:["编造数字或政策"]},interview_scheduling:{description:"推动面试预约,确认时间和到店安排",primaryGoal:"推动面试预约",successCriteria:["候选人给出可面试时间"],ctaStrategy:"给出明确时间选项并确认",disallowedActions:["不确认候选人可到店性"]},onboard_followup:{description:"促进到岗并保持回访",primaryGoal:"促进到岗并保持回访",successCriteria:["候选人确认上岗安排"],ctaStrategy:"明确下一步动作与提醒",disallowedActions:["承诺不确定资源"]}},persona:{tone:"口语化",warmth:"高",humor:"低",length:"short",questionStyle:"单轮一个关键问题",empathyStrategy:"先认可关切再给建议",addressStyle:"使用你",professionalIdentity:"资深招聘专员",companyBackground:"连锁餐饮招聘"},industryVoices:{default:{name:"餐饮连锁招聘",industryBackground:"门店密集、排班灵活、强调稳定出勤",jargon:["排班","到岗","门店","班次"],styleKeywords:["直接","清晰","可信"],tabooPhrases:["包过","绝对","随便都行"],guidance:["先解决顾虑,再推动下一步"]}},defaultIndustryVoiceId:"default",hardConstraints:{rules:[{id:"no-fabrication",rule:"不得编造门店、薪资、排班、福利等事实信息",severity:"high"},{id:"no-insurance-promise",rule:"兼职场景不得承诺五险一金",severity:"high"},{id:"age-sensitive",rule:"年龄敏感问题使用合规话术,不暴露内部筛选线",severity:"high"}]},factGate:{mode:"strict",verifiableClaimTypes:["salary","location","schedule","policy","availability"],fallbackBehavior:"generic_answer",forbiddenWhenMissingFacts:["具体数字","具体门店承诺","明确福利承诺"]},qualificationPolicy:{age:{enabled:!0,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!0,redirectPriority:"medium"}},outputGuards:W};function K(e){let n=e;for(;;){if(b(T(n,"package.json")))return n;const t=S(n);if(t===n)throw new Error(`Could not locate package root from ${e}`);n=t}}var V=T(K(import.meta.dirname),"data"),z=T(V,"brand-config.json"),Y=T(V,"reply-policy.json"),J=3e5,Q=null,Z=null;function X(e){return Date.now()-e<J}function ee(){if(Q&&X(Q.loadedAt))return Q.data;const e=h(z,"utf-8"),n=y.parse(JSON.parse(e));return Q={data:n,loadedAt:Date.now()},n}function ne(e){N(z,JSON.stringify(e,null,2),"utf-8"),Q={data:e,loadedAt:Date.now()}}var te="default";function re(){if(Z&&X(Z.loadedAt))return{policy:Z.data,source:te};try{const e=h(Y,"utf-8"),n=q.parse(JSON.parse(e));return Z={data:n,loadedAt:Date.now()},te="file",{policy:n,source:"file"}}catch{return te="default",{policy:H,source:"default"}}}import{createAnthropic as ae}from"@ai-sdk/anthropic";import{createAlibaba as oe}from"@ai-sdk/alibaba";import{createProviderRegistry as ie}from"ai";import{createOpenAICompatible as se}from"@ai-sdk/openai-compatible";import{createDeepSeek as le}from"@ai-sdk/deepseek";import{createGoogleGenerativeAI as ue}from"@ai-sdk/google";import{createOpenAI as ce}from"@ai-sdk/openai";var de=!1;function me(e){de=e}function pe(...e){de||console.error(...e)}var ge=process.env.SMART_REPLY_PROXY_BASE_URL,fe="https://apic1.ohmycdn.com/v1",ye=ge||fe,be={anthropic:process.env.ANTHROPIC_BASE_URL||ye,openai:process.env.OPENAI_BASE_URL||ye,ohmygpt:process.env.OHMYGPT_BASE_URL||ye,moonshotai:process.env.MOONSHOT_BASE_URL||"https://api.moonshot.cn/v1",deepseek:process.env.DEEPSEEK_BASE_URL||"https://api.deepseek.com",qwen:process.env.QWEN_BASE_URL||"https://dashscope.aliyuncs.com/compatible-mode/v1",google:process.env.GOOGLE_BASE_URL||"https://generativelanguage.googleapis.com/v1beta"},he={anthropic:{name:"Anthropic",baseURL:be.anthropic,description:"Anthropic Claude"},openai:{name:"OpenAI",baseURL:be.openai,description:"OpenAI GPT"},ohmygpt:{name:"OhMyGPT",baseURL:be.ohmygpt,description:"OhMyGPT"},moonshotai:{name:"MoonshotAI",baseURL:be.moonshotai,description:"MoonshotAI"},deepseek:{name:"DeepSeek",baseURL:be.deepseek,description:"DeepSeek"},qwen:{name:"Qwen",baseURL:be.qwen,description:"Qwen"},google:{name:"Google",baseURL:be.google,description:"Google Gemini"}},Ne={chatModel:"anthropic/claude-haiku-4-5",classifyModel:process.env.SMART_REPLY_CLASSIFY_MODEL||"openai/gpt-5-mini",replyModel:process.env.SMART_REPLY_REPLY_MODEL||"openai/gpt-5.4"};function Se(){return process.env.ANTHROPIC_API_KEY||process.env.OPENAI_API_KEY||""}function Te(e){const n=ce({apiKey:e.apiKey||"",...void 0!==e.baseURL?{baseURL:e.baseURL}:{}});return new Proxy(n,{get(e,t){if("languageModel"===t)return e=>n.chat(e);if("chat"===t||"completion"===t)return n[t];if("embeddingModel"===t||"imageModel"===t){return n[t]||void 0}return n[t]}})}function Ae(e){const n=Se();return ie({anthropic:ae({apiKey:n,baseURL:e.anthropic?.baseURL||be.anthropic}),openai:Te({apiKey:n,baseURL:e.openai?.baseURL||be.openai}),ohmygpt:se({name:"ohmygpt",baseURL:e.ohmygpt?.baseURL||be.ohmygpt,apiKey:n}),moonshotai:se({name:"moonshotai",baseURL:e.moonshotai?.baseURL||be.moonshotai,apiKey:process.env.MOONSHOT_API_KEY||""}),deepseek:le({baseURL:e.deepseek?.baseURL||be.deepseek,apiKey:process.env.DEEPSEEK_API_KEY||""}),google:ue({apiKey:process.env.GEMINI_API_KEY||"",baseURL:e.google?.baseURL||be.google}),qwen:oe({apiKey:process.env.DASHSCOPE_API_KEY||process.env.ALIBABA_API_KEY||"",baseURL:e.qwen?.baseURL||be.qwen})},{separator:"/"})}var Ie=null,_e=null;function Ee(e){const n=JSON.stringify(e);return Ie&&_e===n||(Ie=Ae(e),_e=n,pe("[DYNAMIC REGISTRY] 创建新的动态registry,配置哈希:",n.substring(0,16)+"...")),Ie}function Re(e){return e.brands.flatMap(e=>e.stores)}function Le(e){return e.brands.map(e=>e.name)}function Oe(e,n){if(n)return e.brands.find(e=>e.name===n)}function ke(e){if(e.meta.defaultBrandId){const n=e.brands.find(n=>n.id===e.meta.defaultBrandId);if(n)return n}return e.brands[0]}function ve(e){return ke(e)?.name??""}function Me(e,n){const t=n?Oe(e,n)?.stores??[]:Re(e);return t.find(e=>"string"==typeof e.city&&e.city.trim().length>0)?.city}import{z as we}from"zod";var De=6e4,Ce=200,Ue=2e4,xe=null,$e=null;function je(){const e=process.env.DULIDAY_JOB_LIST_URL;return"string"==typeof e&&e.trim().length>0?e:void 0}function We(){const e=process.env.DULIDAY_TOKEN;return"string"==typeof e&&e.trim().length>0?e:void 0}function Fe(e){return(e??"").trim()}function Pe(e){const n=Fe(e);if(!n)return[];const t=new Set([n]);return n.endsWith("市")?t.add(n.slice(0,-1)):t.add(`${n}市`),Array.from(t).filter(Boolean)}function Be(e,n){const t=Fe(e);if(!t)return[];const r=new Set([t]),a=Pe(n);for(const e of a)if(t.startsWith(e)){const n=t.slice(e.length).trim();n&&r.add(n)}return Array.from(r).filter(Boolean)}var Ge=we.object({data:we.object({result:we.array(we.unknown()).optional(),list:we.array(we.unknown()).optional(),total:we.number().optional()}).nullable().optional(),result:we.array(we.unknown()).optional()});function qe(e){const n=Ge.safeParse(e);if(!n.success)return{items:[],total:0};const t=n.data,r=t.data?.result??t.data?.list??(Array.isArray(t.result)?t.result:[]),a=t.data?.total??(Array.isArray(r)?r.length:0);return{items:Array.isArray(r)?r:[],total:"number"==typeof a?a:0}}var He={includeBasicInfo:!0,includeJobSalary:!0,includeWelfare:!0,includeHiringRequirement:!0,includeWorkTime:!0},Ke={includeBasicInfo:!0,includeHiringRequirement:!0};async function Ve(e,n,t,r,a){const o="test"!==process.env.NODE_ENV,i=Be(a?.brandAlias,a?.cityName),s=Pe(a?.cityName),l=a?.include??Ke,u=JSON.stringify({token:e,brandCandidates:i,cityCandidates:s,pageNum:t,includeOpts:l}),c=Date.now();if(o&&xe&&xe.cacheKey===u&&c-xe.fetchedAt<De)return xe.payload;if(o&&$e?.cacheKey===u)return $e.promise;const d=(async()=>{const a=new AbortController,o=setTimeout(()=>a.abort(),Ue),c={};i.length>0&&(c.brandAliasList=i),s.length>0&&(c.cityNameList=s);const d={pageNum:t,pageSize:r,queryParam:c,options:l};try{const t=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json","Duliday-Token":e},body:JSON.stringify(d),signal:a.signal});if(!t.ok)throw new Error(`Duliday job list fetch failed: ${t.status}`);const r=await t.json();return xe={cacheKey:u,payload:r,fetchedAt:Date.now()},r}finally{clearTimeout(o),$e=null}})();return o&&($e={cacheKey:u,promise:d}),d}async function ze(e,n,t){const r=[];let a=1,o=0;for(;;){const i=qe(await Ve(e,n,a,Ce,t));if(1===a&&(o=i.total),r.push(...i.items),i.items.length<Ce||r.length>=o)break;a+=1}return{items:r,total:o}}import{z as Ye}from"zod";import{setTimeout as Je,clearTimeout as Qe}from"node:timers";import{performance as Ze}from"node:perf_hooks";import{asSchema as Xe,generateText as en,jsonSchema as nn,NoObjectGeneratedError as tn,Output as rn}from"ai";import"zod";var an={CONFIG:"CONFIG",AUTH:"AUTH",NETWORK:"NETWORK",LLM:"LLM",VALIDATION:"VALIDATION",BUSINESS:"BUSINESS",SYSTEM:"SYSTEM"},on={LLM_UNAUTHORIZED:"LLM_UNAUTHORIZED",LLM_MODEL_NOT_FOUND:"LLM_MODEL_NOT_FOUND",LLM_RATE_LIMITED:"LLM_RATE_LIMITED",LLM_TIMEOUT:"LLM_TIMEOUT",LLM_GENERATION_FAILED:"LLM_GENERATION_FAILED",LLM_RESPONSE_PARSE_ERROR:"LLM_RESPONSE_PARSE_ERROR",CONFIG_NOT_FOUND:"CONFIG_NOT_FOUND",CONFIG_INVALID:"CONFIG_INVALID",CONFIG_MISSING_FIELD:"CONFIG_MISSING_FIELD",CONFIG_LOAD_FAILED:"CONFIG_LOAD_FAILED",NETWORK_TIMEOUT:"NETWORK_TIMEOUT",NETWORK_CONNECTION_FAILED:"NETWORK_CONNECTION_FAILED",NETWORK_HTTP_ERROR:"NETWORK_HTTP_ERROR",NETWORK_DNS_FAILED:"NETWORK_DNS_FAILED",AUTH_UNAUTHORIZED:"AUTH_UNAUTHORIZED",AUTH_FORBIDDEN:"AUTH_FORBIDDEN",AUTH_TOKEN_EXPIRED:"AUTH_TOKEN_EXPIRED",AUTH_TOKEN_INVALID:"AUTH_TOKEN_INVALID",VALIDATION_INVALID_INPUT:"VALIDATION_INVALID_INPUT",VALIDATION_MISSING_REQUIRED:"VALIDATION_MISSING_REQUIRED",VALIDATION_FORMAT_ERROR:"VALIDATION_FORMAT_ERROR",VALIDATION_SCHEMA_ERROR:"VALIDATION_SCHEMA_ERROR",BUSINESS_RULE_VIOLATION:"BUSINESS_RULE_VIOLATION",BUSINESS_RESOURCE_NOT_FOUND:"BUSINESS_RESOURCE_NOT_FOUND",BUSINESS_RESOURCE_EXISTS:"BUSINESS_RESOURCE_EXISTS",BUSINESS_OPERATION_NOT_ALLOWED:"BUSINESS_OPERATION_NOT_ALLOWED",SYSTEM_INTERNAL:"SYSTEM_INTERNAL",SYSTEM_DEPENDENCY_FAILED:"SYSTEM_DEPENDENCY_FAILED",SYSTEM_RESOURCE_UNAVAILABLE:"SYSTEM_RESOURCE_UNAVAILABLE",SYSTEM_UNKNOWN:"SYSTEM_UNKNOWN"},sn={[on.LLM_UNAUTHORIZED]:an.LLM,[on.LLM_MODEL_NOT_FOUND]:an.LLM,[on.LLM_RATE_LIMITED]:an.LLM,[on.LLM_TIMEOUT]:an.LLM,[on.LLM_GENERATION_FAILED]:an.LLM,[on.LLM_RESPONSE_PARSE_ERROR]:an.LLM,[on.CONFIG_NOT_FOUND]:an.CONFIG,[on.CONFIG_INVALID]:an.CONFIG,[on.CONFIG_MISSING_FIELD]:an.CONFIG,[on.CONFIG_LOAD_FAILED]:an.CONFIG,[on.NETWORK_TIMEOUT]:an.NETWORK,[on.NETWORK_CONNECTION_FAILED]:an.NETWORK,[on.NETWORK_HTTP_ERROR]:an.NETWORK,[on.NETWORK_DNS_FAILED]:an.NETWORK,[on.AUTH_UNAUTHORIZED]:an.AUTH,[on.AUTH_FORBIDDEN]:an.AUTH,[on.AUTH_TOKEN_EXPIRED]:an.AUTH,[on.AUTH_TOKEN_INVALID]:an.AUTH,[on.VALIDATION_INVALID_INPUT]:an.VALIDATION,[on.VALIDATION_MISSING_REQUIRED]:an.VALIDATION,[on.VALIDATION_FORMAT_ERROR]:an.VALIDATION,[on.VALIDATION_SCHEMA_ERROR]:an.VALIDATION,[on.BUSINESS_RULE_VIOLATION]:an.BUSINESS,[on.BUSINESS_RESOURCE_NOT_FOUND]:an.BUSINESS,[on.BUSINESS_RESOURCE_EXISTS]:an.BUSINESS,[on.BUSINESS_OPERATION_NOT_ALLOWED]:an.BUSINESS,[on.SYSTEM_INTERNAL]:an.SYSTEM,[on.SYSTEM_DEPENDENCY_FAILED]:an.SYSTEM,[on.SYSTEM_RESOURCE_UNAVAILABLE]:an.SYSTEM,[on.SYSTEM_UNKNOWN]:an.SYSTEM},ln={[on.LLM_UNAUTHORIZED]:"AI 服务认证失败,请检查配置",[on.LLM_MODEL_NOT_FOUND]:"所选模型暂时不可用,请尝试其他模型",[on.LLM_RATE_LIMITED]:"请求过于频繁,请稍后重试",[on.LLM_TIMEOUT]:"AI 响应超时,请稍后重试",[on.LLM_GENERATION_FAILED]:"内容生成失败,请稍后重试",[on.LLM_RESPONSE_PARSE_ERROR]:"AI 响应格式异常,请重试",[on.CONFIG_NOT_FOUND]:"配置数据未找到,请先进行初始化",[on.CONFIG_INVALID]:"配置格式无效,请检查配置",[on.CONFIG_MISSING_FIELD]:"配置缺少必需字段",[on.CONFIG_LOAD_FAILED]:"配置加载失败,请重试",[on.NETWORK_TIMEOUT]:"网络请求超时,请检查网络连接",[on.NETWORK_CONNECTION_FAILED]:"网络连接失败,请检查网络",[on.NETWORK_HTTP_ERROR]:"服务器返回错误,请稍后重试",[on.NETWORK_DNS_FAILED]:"域名解析失败,请检查网络",[on.AUTH_UNAUTHORIZED]:"请先登录",[on.AUTH_FORBIDDEN]:"您没有权限执行此操作",[on.AUTH_TOKEN_EXPIRED]:"登录已过期,请重新登录",[on.AUTH_TOKEN_INVALID]:"认证信息无效,请重新登录",[on.VALIDATION_INVALID_INPUT]:"输入参数无效",[on.VALIDATION_MISSING_REQUIRED]:"缺少必需参数",[on.VALIDATION_FORMAT_ERROR]:"数据格式错误",[on.VALIDATION_SCHEMA_ERROR]:"数据验证失败",[on.BUSINESS_RULE_VIOLATION]:"操作违反业务规则",[on.BUSINESS_RESOURCE_NOT_FOUND]:"请求的资源不存在",[on.BUSINESS_RESOURCE_EXISTS]:"资源已存在",[on.BUSINESS_OPERATION_NOT_ALLOWED]:"当前操作不被允许",[on.SYSTEM_INTERNAL]:"系统内部错误,请稍后重试",[on.SYSTEM_DEPENDENCY_FAILED]:"依赖服务异常,请稍后重试",[on.SYSTEM_RESOURCE_UNAVAILABLE]:"系统资源不可用,请稍后重试",[on.SYSTEM_UNKNOWN]:"发生未知错误,请稍后重试"};function un(e){return sn[e]}function cn(e){return ln[e]}var dn=class _AppError extends Error{code;category;userMessage;details;cause;timestamp;constructor(e){super(e.message),this.name="AppError",this.code=e.code,this.category=un(e.code),this.userMessage=e.userMessage||cn(e.code),this.details=e.details,this.cause=e.cause,this.timestamp=(new Date).toISOString(),Error.captureStackTrace&&Error.captureStackTrace(this,_AppError)}toJSON(){const e={code:this.code,category:this.category,message:this.message,userMessage:this.userMessage,timestamp:this.timestamp};return void 0!==this.details&&(e.details=this.details),this.cause&&(this.cause instanceof _AppError?e.cause=this.cause.toJSON():e.cause={message:this.cause.message,stack:this.cause.stack}),e}getErrorChain(){const e=[this];let n=this.cause;for(;n;)e.push(n),n=n instanceof _AppError?n.cause:void 0;return e}getRootCause(){const e=this.getErrorChain();return e[e.length-1]}hasErrorCode(e){return this.getErrorChain().some(n=>n instanceof _AppError&&n.code===e)}hasErrorCategory(e){return this.getErrorChain().some(n=>n instanceof _AppError&&n.category===e)}toLogString(){const e=[`[${this.code}]`,this.message];return this.details&&e.push(`Details: ${JSON.stringify(this.details)}`),this.cause&&e.push(`Caused by: ${this.cause.message}`),e.join(" | ")}};function mn(e){return e instanceof dn}function pn(e,n,t){const r=t?.model?` (model: ${t.model})`:"",a=t?.provider?` [${t.provider}]`:"",o={[on.LLM_UNAUTHORIZED]:`LLM API authentication failed${a}${r}`,[on.LLM_MODEL_NOT_FOUND]:`Model not found or unavailable${r}${a}`,[on.LLM_RATE_LIMITED]:`LLM API rate limited${a}`,[on.LLM_TIMEOUT]:`LLM API request timeout${a}${r}`,[on.LLM_GENERATION_FAILED]:`LLM generation failed${a}${r}`,[on.LLM_RESPONSE_PARSE_ERROR]:`Failed to parse LLM response${a}`};return new dn({code:e,message:o[e]||`LLM error: ${n.message}`,cause:n,details:t})}function gn(e,n,t){const r=t?.url?` (${t.url})`:"",a=t?.statusCode?` [${t.statusCode}]`:"",o={[on.NETWORK_TIMEOUT]:`Network request timeout${r}`,[on.NETWORK_CONNECTION_FAILED]:`Failed to connect${r}`,[on.NETWORK_HTTP_ERROR]:`HTTP error${a}${r}`,[on.NETWORK_DNS_FAILED]:`DNS resolution failed${r}`};return new dn({code:e,message:o[e]||`Network error: ${n.message}`,cause:n,details:t})}function fn(e,n,t){const r=t.isMarkdownFormat?" (detected markdown format)":"",a=t.schemaName?` for schema "${t.schemaName}"`:"";return new dn({code:e,message:`Failed to parse structured output${a}${r}`,cause:n,details:{rawText:t.rawText,isMarkdownFormat:t.isMarkdownFormat,parseErrorMessage:t.parseErrorMessage,model:t.model,provider:t.provider,schemaName:t.schemaName,usage:t.usage}})}import{NoObjectGeneratedError as yn}from"ai";function bn(e){if(!e||"object"!=typeof e)return null;const n=e;if(!("AI_APICallError"===n.name||"APICallError"===n.name||"string"==typeof n.url&&"number"==typeof n.statusCode))return null;const t="number"==typeof n.statusCode?n.statusCode:void 0,r="string"==typeof n.responseBody?n.responseBody:void 0,a="string"==typeof n.url?n.url:void 0,o=n.message;let i,s;if(a&&(a.includes("openai.com")?i="openai":a.includes("anthropic.com")?i="anthropic":a.includes("dashscope.aliyuncs.com")?i="qwen":a.includes("openrouter.ai")?i="openrouter":a.includes("deepseek.com")?i="deepseek":a.includes("moonshot.cn")?i="moonshotai":a.includes("googleapis.com")&&(i="google")),r){const e=r.match(/model[`'":\s]+([^`'"}\s,]+)/i);e&&(s=e[1])}return{isAuthError:401===t||403===t,isModelNotFound:r?.includes("model")&&r?.includes("not exist")||r?.includes("not authorized to access this model")||!1,isRateLimited:429===t,isTimeout:408===t||504===t||o?.toLowerCase().includes("timeout")||!1,statusCode:t,provider:i,model:s,originalMessage:o,responseBody:r}}function hn(e){return[/^```/m,/^#{1,6}\s/m,/^\s*[-*+]\s/m,/^\s*\d+\.\s/m,/\[.+\]\(.+\)/,/^\s*>/m].some(n=>n.test(e))}function Nn(e){try{if(void 0===yn||"function"!=typeof yn.isInstance)return null;if(!yn.isInstance(e))return null}catch{return null}const n=e.text,t=!!n&&hn(n),r=e.response?{id:e.response.id,timestamp:e.response.timestamp,modelId:e.response.modelId}:void 0,a=e.usage??void 0,o={isNoObjectGeneratedError:!0,isMarkdownFormat:t};return void 0!==n&&(o.rawText=n),e.cause instanceof Error&&(o.cause=e.cause),void 0!==r&&(o.response=r),void 0!==a&&(o.usage=a),o}function Sn(e,n=on.SYSTEM_UNKNOWN,t){if(mn(e))return t&&t!==e.userMessage?new dn({code:e.code,message:e.message,userMessage:t,cause:e.cause,details:e.details}):e;const r=Tn(e),a=bn(e);if(a){const e={model:a.model,provider:a.provider,statusCode:a.statusCode,responseBody:a.responseBody};return a.isModelNotFound?pn(on.LLM_MODEL_NOT_FOUND,r,e):a.isAuthError?pn(on.LLM_UNAUTHORIZED,r,e):a.isRateLimited?pn(on.LLM_RATE_LIMITED,r,e):a.isTimeout?pn(on.LLM_TIMEOUT,r,e):pn(on.LLM_GENERATION_FAILED,r,e)}const o=Nn(e);if(o)return fn(on.LLM_RESPONSE_PARSE_ERROR,r,{rawText:o.rawText,isMarkdownFormat:o.isMarkdownFormat,parseErrorMessage:o.cause?.message,usage:o.usage});const i=r.message.toLowerCase();return i.includes("timeout")||i.includes("econnrefused")||i.includes("network")||i.includes("fetch failed")?i.includes("timeout")?gn(on.NETWORK_TIMEOUT,r):gn(on.NETWORK_CONNECTION_FAILED,r):new dn({code:n,message:r.message,cause:r})}function Tn(e){if(e instanceof Error)return e;if("string"==typeof e)return new Error(e);if("object"==typeof e&&null!==e){const n=e.message||e.error||JSON.stringify(e);return new Error(String(n))}return new Error(String(e))}function An(e,n){console.error(`[${n.code}] ${e}:`,n.toLogString()),n.cause&&console.error("Original error:",n.cause)}function In(e){return"object"==typeof e&&null!==e}function _n(e,n){n&&In(e.details)&&(e.details.schemaName=n)}function En(e){const n=e.type;return"string"==typeof n?[n]:Array.isArray(n)?n.filter(e=>"string"==typeof e):[]}function Rn(e,n){let t=null;for(const r of e){const e=n.get(r);if(void 0!==e&&e.size>0){t??=new Set;for(const n of e)t.add(n)}}return t}function Ln(e,n){if(Array.isArray(e))return e.map(e=>Ln(e,n));if(null===e||"object"!=typeof e)return e;const t=e,r=Rn(En(t),n),a={};for(const[e,o]of Object.entries(t))null!==r&&r.has(e)||(a[e]=Ln(o,n));return a}function On(e){const n=e.unsupportedKeywordsByType;if(void 0===n)return new Map;const t=new Map;for(const[e,r]of Object.entries(n)){if(0===r.length)continue;const n=t.get(e);if(void 0!==n)for(const e of r)n.add(e);else t.set(e,new Set(r))}const r=t.get("number");if(void 0!==r&&r.size>0){const e=t.get("integer");if(void 0!==e)for(const n of r)e.add(n);else t.set("integer",new Set(r))}return t}function kn(e,n={}){const t=On(n);if(0===t.size)return e;const r=Xe(e);return nn(async()=>Ln(await r.jsonSchema,t),{validate:e=>({success:!0,value:e})})}async function vn(e){const{model:n,schema:t,outputSchema:r,schemaName:a,system:o,prompt:i,transformOutput:s,onError:l}=e;try{const e=await en({model:n,...void 0!==o?{system:o}:{},prompt:i,output:rn.object({schema:r??t,...void 0!==a?{name:a}:{}})});if(void 0===r&&void 0===s)return{success:!0,data:e.output,usage:e.usage};const u=void 0!==s?await s(e.output):e.output,c=await t.safeParseAsync(u);if(!c.success){const n=Sn(c.error,on.LLM_RESPONSE_PARSE_ERROR);return _n(n,a),An(`Structured output validation (${a||"unknown"})`,n),l&&l(n,e.text),{success:!1,error:n,rawText:e.text}}return{success:!0,data:c.data,usage:e.usage}}catch(e){const n=Sn(e,on.LLM_RESPONSE_PARSE_ERROR);let t;return tn.isInstance(e)&&(t=e.text),_n(n,a),An(`Structured output generation (${a||"unknown"})`,n),l&&l(n,t),{success:!1,error:n,rawText:t}}}var Mn=3e4,wn=2e3;async function Dn(e){const{model:n,system:t,prompt:r,timeoutMs:a=Mn,maxOutputTokens:o=wn,context:i="generateText",onError:s}=e,l=Ze.now();try{const e=new AbortController,s=Je(()=>e.abort(),a),u=await en({model:n,...void 0!==t?{system:t}:{},prompt:r,maxOutputTokens:o,abortSignal:e.signal});Qe(s);const c=Math.round(Ze.now()-l),d=u.usage,m=void 0!==d?.inputTokens&&void 0!==d?.outputTokens?d.inputTokens+d.outputTokens:void 0,p={inputTokens:d?.inputTokens,outputTokens:d?.outputTokens,totalTokens:m};return pe(`[${i}] 生成成功 | 耗时: ${c}ms | Tokens: ${m??"N/A"} (input: ${p.inputTokens??"?"}, output: ${p.outputTokens??"?"})`),{success:!0,text:u.text,usage:p,latencyMs:c}}catch(e){const n=Math.round(Ze.now()-l),t=e instanceof Error&&("AbortError"===e.name||e.message.includes("aborted")),r=Sn(e,t?on.LLM_TIMEOUT:on.LLM_GENERATION_FAILED);return In(r.details)&&(r.details.context=i,r.details.latencyMs=n),An(`${i} (${n}ms)`,r),s&&s(r),{success:!1,error:r}}}import{z as Cn}from"zod";var Un=Cn.object({name:Cn.string(),baseURL:Cn.string(),description:Cn.string()}),xn=Cn.record(Cn.string(),Un),$n=Cn.object({chatModel:Cn.string().optional(),classifyModel:Cn.string().optional(),replyModel:Cn.string().optional(),providerConfigs:xn.optional()}),jn=Cn.object({city:Cn.string().optional(),defaultBrand:Cn.string(),availableBrands:Cn.array(Cn.string()),storeCount:Cn.number()}),Wn=Cn.object({modelConfig:$n,candidateMessage:Cn.string(),conversationHistory:Cn.array(Cn.string()).default([]),brandData:jn.optional(),channelType:_.optional()});function Fn(e){const n=_.safeParse(e);return n.success?n.data:"public"}function Pn(e="public"){const n=Fn(e),t=I.options.filter(e=>L[e].applicableChannels.includes(n));return t.length>0?t:[...I.options]}function Bn(e){return Ye.object({stage:Ye.enum(e),subGoals:w.shape.subGoals,needs:w.shape.needs,primaryNeed:w.shape.primaryNeed,riskFlags:w.shape.riskFlags,confidence:w.shape.confidence,extractedInfo:w.shape.extractedInfo,reasoningText:w.shape.reasoningText})}var Gn={subGoals:2,needs:8,riskFlags:6,mentionedDistricts:10};function qn(e){return e.startsWith("anthropic/")}function Hn(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function Kn(e){if(!Hn(e))return e;const n={...e};if(Array.isArray(n.subGoals)&&(n.subGoals=n.subGoals.slice(0,Gn.subGoals)),Array.isArray(n.needs)&&(n.needs=n.needs.slice(0,Gn.needs)),Array.isArray(n.riskFlags)&&(n.riskFlags=n.riskFlags.slice(0,Gn.riskFlags)),Hn(n.extractedInfo)){const e={...n.extractedInfo};Array.isArray(e.mentionedDistricts)&&(e.mentionedDistricts=e.mentionedDistricts.slice(0,Gn.mentionedDistricts)),n.extractedInfo=e}return n}var Vn=[{need:"salary",patterns:[/薪资|工资|时薪|底薪|提成|奖金|补贴|多少钱|收入/i]},{need:"schedule",patterns:[/排班|班次|几点|上班|下班|工时|周末|节假日|做几天/i]},{need:"policy",patterns:[/五险一金|社保|保险|合同|考勤|迟到|补班|试用期/i]},{need:"availability",patterns:[/还有名额|空位|可用时段|什么时候能上|明天能面/i]},{need:"location",patterns:[/在哪|位置|地址|附近|地铁|门店|哪个区|多远/i]},{need:"stores",patterns:[/门店|哪家店|哪些店|有店吗/i]},{need:"requirements",patterns:[/要求|条件|年龄|经验|学历|健康证|身高|体重/i]},{need:"interview",patterns:[/面试|到店|约时间|约面/i]},{need:"wechat",patterns:[/微信|vx|私聊|联系方式|加你/i]}],zn=["salary","schedule","location","stores","policy","requirements","availability","interview","wechat","none"];function Yn(e){const n=new Set;for(const t of Vn)t.patterns.some(n=>n.test(e))&&n.add(t.need);return 0===n.size?n.add("none"):n.delete("none"),n}function Jn(e,n){return Yn(`${n.slice(-4).join(" ")} ${e}`)}function Qn(e){return Yn(e)}function Zn(e,n,t,r=1){const a=new Set(n);a.size>1&&a.has("none")&&a.delete("none");const o=Qn(t);o.delete("none");const i=[];"none"!==e&&a.has(e)&&i.push(e);for(const n of zn){if(i.length>=r)break;"none"!==n&&n!==e&&(o.has(n)&&a.has(n)&&i.push(n))}return i.length>0?i:"none"===e?["none"]:a.has(e)?[e]:["none"]}function Xn(e,n,t){const r=new Set(n);if(r.size>1&&r.has("none")&&r.delete("none"),e&&r.has(e))return e;const a=Qn(t);a.delete("none");for(const e of zn)if(a.has(e)&&r.has(e))return e;for(const e of zn)if(r.has(e))return e;return"none"}function et(e,n,t){const r=new Set([...e.needs,...Array.from(n)]);return r.size>1&&r.has("none")&&r.delete("none"),{...e,subGoals:e.subGoals.slice(0,2),needs:Array.from(r),primaryNeed:Xn(e.primaryNeed,r,t),confidence:Number.isFinite(e.confidence)?Math.max(0,Math.min(1,e.confidence)):.5}}function nt(e,n,t,r="public",a,o){const i=["你是招聘对话回合规划器,不直接回复候选人。","你只输出结构化规划结果,用于后续回复生成。","规划目标:确定阶段目标(stage)、子目标(subGoals)、事实需求(needs)、主回答轴(primaryNeed)、风险标记(riskFlags)。"].join("\n"),s=Fn(r);return{system:i,prompt:["[阶段枚举与定义]",...Pn(s).map(e=>{const n=L[e];return`- ${e}: ${a?.stageGoals[e]?.description||n.description} (转入条件: ${n.transitionSignal})`}),"","[needs枚举]","private"===s?"- stores, location, salary, schedule, policy, availability, requirements, interview, none":"- stores, location, salary, schedule, policy, availability, requirements, interview, wechat, none","","[riskFlags枚举]","- insurance_promise_risk, age_sensitive, confrontation_emotion, urgency_high, qualification_mismatch","","[规则]","- 优先判断本轮主阶段(stage);subGoals 最多 2 项,只保留最关键的。","- 候选人追问事实时,必须打开对应 needs。","- primaryNeed 必须从 needs 中选择一个最主的 need;如果没有明确事实轴则填 none。","- 不确定时 confidence 降低,不要臆断。","- 根据转入条件判断阶段转化,不要停留在不匹配的阶段。",...o&&o.length>0?[`- 候选人资料中已有:${o.join("、")}。不要生成追问这些字段的 subGoal。`]:[],"","[品牌数据]",JSON.stringify(t||{}),"","[历史对话]",n.slice(-8).join("\n")||"无","","[候选人消息]",e].join("\n")}}async function tt(e,n){const{providerConfigs:t=he,modelConfig:r,conversationHistory:a=[],brandData:o,channelType:i,replyPolicy:s,knownCandidateFields:l}=n,u=Ee(t),c=r?.classifyModel||Ne.classifyModel,d=Fn(i),m=Bn(Pn(d)),p=qn(c),g=nt(e,a,o,d,s,l),f=await vn({model:u.languageModel(c),schema:m,...p?{outputSchema:kn(m,{unsupportedKeywordsByType:{array:["maxItems","minItems"],number:["maximum","minimum","exclusiveMaximum","exclusiveMinimum"]}}),transformOutput:Kn}:{},schemaName:"TurnPlanningOutput",system:g.system,prompt:g.prompt}),y=Jn(e,a),b=Xn(void 0,y,e);return f.success?et(f.data,y,e):{stage:"trust_building",subGoals:["保持对话并澄清需求"],needs:Array.from(y),primaryNeed:b,riskFlags:[],confidence:.35,extractedInfo:{mentionedBrand:null,city:o?.city||null,mentionedLocations:null,mentionedDistricts:null,specificAge:null,hasUrgency:null,preferredSchedule:null},reasoningText:"规划模型失败,使用规则降级策略"}}import{z as rt}from"zod";var at=rt.object({id:rt.number(),name:rt.string(),aliases:rt.array(rt.string()),projectIdList:rt.array(rt.number())}),ot=rt.object({code:rt.number(),message:rt.string().optional(),data:rt.object({result:rt.array(at),total:rt.number()})}),it=3e5,st=null;function lt(){return null!==st&&Date.now()-st.timestamp<it}var ut=3e4;function ct(){const e=process.env.DULIDAY_BRAND_LIST_URL;return"string"==typeof e&&e.trim().length>0?e:void 0}async function dt(e){const n=e||process.env.DULIDAY_TOKEN,t=ct();if(!n)throw new dn({code:on.CONFIG_MISSING_FIELD,message:"DULIDAY_TOKEN 未配置,无法获取品牌别名数据",userMessage:"品牌别名数据加载失败:缺少 Duliday Token 配置"});if(!t)throw new dn({code:on.CONFIG_MISSING_FIELD,message:"DULIDAY_BRAND_LIST_URL 未配置,无法获取品牌别名数据",userMessage:"品牌别名数据加载失败:缺少 Duliday 品牌接口配置"});const r=new AbortController,a=setTimeout(()=>r.abort(),ut);try{const e=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json","Duliday-Token":n},body:JSON.stringify({pageNum:1,pageSize:1e3}),signal:r.signal});if(!e.ok)throw new dn({code:on.NETWORK_HTTP_ERROR,message:`Duliday 品牌列表 API 返回 HTTP ${e.status}: ${e.statusText}`,userMessage:`品牌别名数据加载失败:服务端返回 ${e.status}`});const a=await e.json(),o=ot.safeParse(a);if(!o.success)throw new dn({code:on.VALIDATION_SCHEMA_ERROR,message:`Duliday 品牌列表响应格式校验失败: ${o.error.message}`,userMessage:"品牌别名数据加载失败:响应格式异常"});return o.data.data.result}catch(e){if(e instanceof dn)throw e;if(e instanceof Error&&"AbortError"===e.name)throw new dn({code:on.NETWORK_TIMEOUT,message:`Duliday 品牌列表 API 请求超时 (${ut}ms)`,userMessage:"品牌别名数据加载超时,请稍后重试",cause:e});throw new dn({code:on.SYSTEM_DEPENDENCY_FAILED,message:`获取品牌别名数据失败: ${e instanceof Error?e.message:String(e)}`,userMessage:"品牌别名数据加载失败,请检查网络连接",...e instanceof Error?{cause:e}:{}})}finally{clearTimeout(a)}}function mt(e,n,t){const r={},a=new Map,o=e=>e.trim(),i=(e,n)=>{const t=o(e).toLowerCase().replace(/[\s._-]+/g,"");if(!t)return;const r=a.get(t);(!r||n.length>r.length)&&a.set(t,n)},s=[...e].sort((e,n)=>n.name.length-e.name.length);for(const e of s){const n=o(e.name);if(!n)continue;const a=Array.from(new Set([n,...e.aliases.map(o).filter(Boolean)].filter(e=>e!==n)));a.unshift(n),r[n]=a;for(const e of a)i(e,n);if(t&&e.projectIdList.length>0)for(const o of e.projectIdList){const e=t[String(o)];if(!e||e===n)continue;if(!e.includes(n))continue;const s=e.replace(n,"");if(!s)continue;const l=[e];for(const e of a)e!==n&&l.push(`${s}${e}`);if(r[e]){const n=new Set(r[e]);for(const t of l)n.has(t)||r[e].push(t)}else r[e]=l;for(const n of l)i(n,e)}}for(const e of n)r[e]||(r[e]=[e],i(e,e));return{dictionary:r,aliasMap:a}}async function pt(e){if(lt())return;const n=await dt(e),t=new Set,{dictionary:r,aliasMap:a}=mt(n,t);st={aliasMap:a,dictionary:r,timestamp:Date.now()}}async function gt(e){return await pt(e),st.aliasMap}function ft(e){const{base:n,unit:t,range:r,memo:a}=e,o=a?.replace(/\n/g," ").trim()??"";if(null==n)return e.scenarioSummary&&o?`${o}(${e.scenarioSummary})`:e.scenarioSummary?e.scenarioSummary:o;let i="";return n<10&&a?i=`${n}${t??""}(${o})`:(i=`${n}${t??""}`,r&&r!==`${n}-${n}`&&r!==`${n}元-${n}元`&&(i+=`,范围${r}`),o&&o.length<50&&(i+=`(${o})`)),e.scenarioSummary&&(i+=`(${e.scenarioSummary})`),i}function yt(e,n,t){if(!e)return null;const r=e=>e.toLowerCase().replace(/[\s._-]+/g,"");if(t){const a=t.get(r(e))||t.get(e.toLowerCase());if(a&&n.includes(a))return a}const a=e.toLowerCase(),o=r(e),i=n.find(e=>e.toLowerCase()===a);if(i)return i;const s=n.find(e=>r(e)===o);if(s)return s;const l=n.filter(e=>{const n=e.toLowerCase();if(n.includes(a)||a.includes(n))return!0;const t=r(e);return t.includes(o)||o.includes(t)});if(l.length>0)return l.sort((e,n)=>n.length-e.length)[0]??null;if(a.includes("山姆")||a.includes("sam")){const e=n.find(e=>{const n=e.toLowerCase();return n.includes("山姆")||n.includes("sam")});if(e)return e}return null}function bt(e){const{uiSelectedBrand:n,configDefaultBrand:t,conversationBrand:r,availableBrands:a,strategy:o="smart",aliasMap:i}=e,s=(e,n)=>{if(e)return yt(e,a,i)??void 0};switch(o){case"user-selected":{const e=s(n);if(e)return{resolvedBrand:e,matchType:e===n?"exact":"fuzzy",source:"ui",reason:"用户选择策略",originalInput:n};const r=s(t);return r?{resolvedBrand:r,matchType:r===t?"exact":"fuzzy",source:"config",reason:"配置默认",originalInput:t}:{resolvedBrand:a[0]??"",matchType:"fallback",source:"default",reason:"系统默认"}}case"conversation-extracted":{const e=s(r);if(e)return{resolvedBrand:e,matchType:e===r?"exact":"fuzzy",source:"conversation",reason:"对话提取",originalInput:r};const o=s(n);if(o)return{resolvedBrand:o,matchType:o===n?"exact":"fuzzy",source:"ui",reason:"UI选择",originalInput:n};const i=s(t);return i?{resolvedBrand:i,matchType:i===t?"exact":"fuzzy",source:"config",reason:"配置默认",originalInput:t}:{resolvedBrand:a[0]??"",matchType:"fallback",source:"default",reason:"系统默认"}}default:{const e=s(r),o=s(n);if(e)return{resolvedBrand:e,matchType:e===r?"exact":"fuzzy",source:"conversation",reason:"智能策略: 对话提取",originalInput:r};if(o)return{resolvedBrand:o,matchType:o===n?"exact":"fuzzy",source:"ui",reason:"智能策略: UI选择",originalInput:n};const i=s(t);return i?{resolvedBrand:i,matchType:i===t?"exact":"fuzzy",source:"config",reason:"智能策略: 配置默认",originalInput:t}:{resolvedBrand:a[0]??"",matchType:"fallback",source:"default",reason:"智能策略: 系统默认"}}}}function ht(e,n){const{mentionedLocations:t,mentionedDistricts:r}=n;return e.map(e=>{let n=0,a=0,o=0,i=0;if(t&&t.length>0){const r=t.find(n=>e.name.includes(n.location)||e.location.includes(n.location)||(e.subarea??"").includes(n.location));r&&(n=40*r.confidence)}if(r&&r.length>0){const n=r.find(n=>(e.district??"").includes(n.district)||(e.subarea??"").includes(n.district));n&&(a=30*n.confidence)}const s=new Set(e.positions.map(e=>e.name));o=Math.min(5*s.size,20);const l=e.positions.filter(e=>e.availableSlots?.some(e=>e.isAvailable));return i=Math.min(2*l.length,10),{store:e,score:n+a+o+i,breakdown:{locationMatch:n,districtMatch:a,positionDiversity:o,availability:i}}}).sort((e,n)=>n.score-e.score).map(e=>({store:e.store,distance:void 0}))}function Nt(e){return v[e].length>0}function St(e,n){return e.has(n)}function Tt(e,n,t){return"minimal"===n||(1===e||"trust_building"===t||"private_channel"===t)}async function At(e,n,t,r,a,o,i,s,l=1,u="minimal",c=[n.primaryNeed]){const d=n.extractedInfo,m=n.primaryNeed,p=c.length>0?Array.from(new Set(c.filter(e=>"none"!==e))):"none"===m?[]:[m],g=new Set(p.flatMap(e=>v[e])),f=Tt(l,u,n.stage),y=!f&&Nt(m);let b,h;try{b=await gt()}catch(e){const n="object"==typeof e&&null!==e&&"userMessage"in e&&"string"==typeof e.userMessage?e.userMessage:e instanceof Error?e.message:String(e);h=n,pe(`[buildContextInfoByNeeds] 品牌别名服务不可用,回退 fuzzy 解析: ${n}`)}const N=bt({uiSelectedBrand:t,configDefaultBrand:ve(e),conversationBrand:r||void 0,availableBrands:Le(e),strategy:a||"smart",aliasMap:b}),S=N.resolvedBrand;pe(`[品牌解析] 工具传参: ${r??"(未指定)"} → 结果: ${S} (${N.matchType}, ${N.source})`);const T=Oe(e,S),A=T?.stores??[];let I=A;if(I.length>0){const e=d.mentionedLocations||[];if(e.length>0){const n=e[0]?.location?.trim();if(n){const e=I.filter(e=>e.name.includes(n)||e.location.includes(n)||(e.district??"").includes(n)||(e.subarea??"").includes(n));e.length>0&&(I=e)}}const n=d.mentionedDistricts||[];if(n.length>0){const e=I.filter(e=>n.some(n=>(e.district??"").includes(n.district)||(e.subarea??"").includes(n.district)));e.length>0&&(I=e)}if(I.length===A.length&&o?.jobAddress&&St(g,"location")){const e=I.filter(e=>e.name.includes(o.jobAddress||"")||e.location.includes(o.jobAddress||"")||(e.district??"").includes(o.jobAddress||"")||(e.subarea??"").includes(o.jobAddress||""));e.length>0&&(I=e)}}let _=[];I.length>0&&(_=ht(I,d));const E=y?Math.min(1,_.length):0,R=y?"focused":"minimal";let L=`阶段目标:${n.stage}\n默认推荐品牌:${S}\n`;if(h&&(L+=`系统状态:品牌别名服务暂不可用,已回退为规则匹配(${h})。\n`),i){const e=i.stageGoals[n.stage],t=s||i.defaultIndustryVoiceId,r=i.industryVoices[t];L+=`策略目标:${e.primaryGoal}\n`,L+=`推进方式:${e.ctaStrategy}\n`,L+=`主回答轴:${m}\n`,r&&(L+=`行业指纹:${r.name} | 风格:${r.styleKeywords.join("、")}\n`),L+=`红线:${i.hardConstraints.rules.map(e=>e.rule).join(";")}\n`}return y?0===E?L+="暂无可用的门店事实信息,请使用泛化回答,避免任何具体承诺。\n":(L+="匹配到的门店信息:\n",_.slice(0,E).forEach(({store:e})=>{const n=St(g,"location"),t=Array.from(g).some(e=>"location"!==e),r=[e.district,e.subarea].filter(e=>Boolean(e)).join("");L+=n?r?`• ${e.name}(${r}):${e.location}\n`:`• ${e.name}:${e.location}\n`:`• ${e.name}\n`,t&&e.positions.slice(0,3).forEach(e=>{if(L+=` 职位:${e.name}\n`,St(g,"salary")){const n=ft(e.salary);n&&(L+=` 薪资:${n}\n`)}if(St(g,"schedule")){if(e.laborForm){const n=[e.laborForm];e.employmentForm&&"长期用工"!==e.employmentForm&&n.push(e.employmentForm),L+=` 用工形式:${n.join(",")}\n`}if(e.timeSlots.length>0&&(L+=` 时间:${e.timeSlots.slice(0,3).join("、")}\n`),(e.minHoursPerWeek||e.maxHoursPerWeek)&&(L+=` 每周工时:${e.minHoursPerWeek||0}-${e.maxHoursPerWeek||"不限"}小时\n`),null!=e.perMonthMinWorkTime){const n=null!=e.perMonthMinWorkTimeUnit?String(e.perMonthMinWorkTimeUnit):"";L+=` 月最低工时:${e.perMonthMinWorkTime}${n}\n`}}if(St(g,"policy")&&(e.attendanceRequirement?.description&&(L+=` 出勤要求:${e.attendanceRequirement.description}\n`),e.trainingRequired&&"不需要"!==e.trainingRequired&&(L+=` 培训要求:${e.trainingRequired}\n`),e.probationRequired&&"不需要"!==e.probationRequired&&(L+=` 试岗要求:${e.probationRequired}\n`)),St(g,"availability")){const n=e.availableSlots?.filter(e=>e.isAvailable).slice(0,3)||[];n.length>0&&(L+=` 可用时段:${n.map(e=>e.slot).join("、")}\n`)}if(St(g,"requirements")&&e.hiringRequirements){const n=e.hiringRequirements,t=[];null==n.minAge&&null==n.maxAge||t.push(`年龄${n.minAge??"不限"}-${n.maxAge??"不限"}岁`),n.genderRequirement&&"0"!==n.genderRequirement&&t.push(`性别:${n.genderRequirement}`),n.education&&"不限"!==n.education&&t.push(`学历:${n.education}`),n.healthCertificate&&t.push(n.healthCertificate),n.languages&&t.push(`语言:${n.languages}`),n.socialIdentity&&"不限"!==n.socialIdentity&&t.push(`社会身份:${n.socialIdentity}`),t.length>0&&(L+=` 要求:${t.join("、")}\n`),n.recruitmentRemark&&(L+=` 招聘备注:${n.recruitmentRemark.slice(0,200)}\n`)}})})):L+=f?"当前处于首轮或浅层沟通,优先泛化回答,不主动展开具体门店、数字或筛选条件。\n":"本轮以推进沟通为主,无需展开岗位细节,请保持回答聚焦且克制。\n",{contextInfo:L,resolvedBrand:S,debugInfo:{relevantStores:_.length>0?_:I.map(e=>({store:e,distance:void 0})),storeCount:E,detailLevel:R,primaryNeed:m,turnPlan:n,aliasLookupError:h}}}var It=["too_many_questions","audit_tone","premature_numeric_disclosure","off_axis_fact_disclosure","reply_overpacked"],_t=/[^。!?!?]*[??]/g,Et={salary:{mention:[/\d+(?:\.\d+)?\s*元(?:\/时|\/小时)?/i,/时薪|薪资|工资|底薪|收入/i],concrete:[/\d+(?:\.\d+)?\s*元(?:\/时|\/小时)?/i]},schedule:{mention:[/\d{1,2}:\d{2}\s*[~-]\s*\d{1,2}:\d{2}/,/班次|轮班|白班|晚班|工时|排班/i],concrete:[/\d{1,2}:\d{2}\s*[~-]\s*\d{1,2}:\d{2}/,/轮班|白班|晚班|早班|中班|夜班/i]},location:{mention:[/地址|地铁|附近|位于|门店|在.+(?:路|街|广场|商场|大厦)/i],concrete:[/地址|位于|地铁\S*站|在.+(?:路|街|广场|商场|大厦)/i]},policy:{mention:[/考勤|试用期|社保|五险一金|迟到|补班/i],concrete:[/考勤|试用期|社保|五险一金|迟到|补班/i]},requirements:{mention:[/年龄|学历|经验|健康证|要求/i],concrete:[/年龄|学历|经验|健康证/i]},availability:{mention:[/名额|空位|可用时段|可安排/i],concrete:[/名额|空位|可用时段/i]}};function Rt(e){return e?.outputGuards??W}function Lt(e){const n=e.match(_t)??[],t=new Set(n.map(e=>e.replace(/[??]/g,"").trim()).filter(Boolean)),r=e.split(/[。!?!?]/).map(e=>e.trim()).filter(Boolean).filter(e=>/[吗呢么]$/.test(e)&&!t.has(e)).length;return n.length+r}function Ot(e){return e.split(/[。!?!?]/).map(e=>e.trim()).filter(Boolean).length}function kt(e){return/(?:^|\s)(?:\d+\.\s|- |•)/m.test(e)}function vt(e,n="mention"){return Object.entries(Et).filter(([,t])=>t[n].some(n=>n.test(e))).map(([e])=>e)}function Mt(e,n){return n.some(n=>n&&e.includes(n))}function wt(e){return/\d+(?:\.\d+)?\s*元(?:\/时|\/小时)?/i.test(e)||/\d{1,2}:\d{2}\s*[~-]\s*\d{1,2}:\d{2}/.test(e)||/年龄\s*\d{1,2}\s*[-~到]\s*\d{1,2}\s*岁/i.test(e)||/\d{1,2}\s*[-~到]\s*\d{1,2}\s*岁/i.test(e)||/地址在|门店在|位于|在.+(?:路|街|广场|商场|大厦|地铁)/i.test(e)}function Dt(e,n,t){let r=0;return Ot(e)>=4&&(r+=1),kt(e)&&(r+=1),n>=3&&(r+=1),t.length>=2&&(r+=1),r>=2}function Ct(e){return vt(e,"concrete")}function Ut(e){const n=[];return/薪资:/.test(e)&&n.push("salary"),/排班:|时间:|每周工时:/.test(e)&&n.push("schedule"),/匹配到的门店信息:[\s\S]*• .*:/.test(e)&&n.push("location"),/考勤:|出勤要求:/.test(e)&&n.push("policy"),/要求:/.test(e)&&n.push("requirements"),/可用时段:/.test(e)&&n.push("availability"),n}function xt(e,n){const t=new Set(e.flatMap(e=>v[e]));return 0===t.size?n.length>0:n.some(e=>!t.has(e))}function $t(e){const{text:n,turnIndex:t,mode:r,policy:a}=e,o=Rt(a),i=Lt(n),s=o.maxQuestionsByMode[r],l=Ct(n),u=e.allowedNeeds?.length?e.allowedNeeds:[e.primaryNeed],c=[];return i>s&&c.push("too_many_questions"),Mt(n,o.blockedAuditPhrases)&&c.push("audit_tone"),o.blockFirstTurnSpecificFacts&&1===t&&wt(n)&&c.push("premature_numeric_disclosure"),xt(u,l)&&c.push("off_axis_fact_disclosure"),Dt(n,i,l)&&c.push("reply_overpacked"),{violations:c,questionCount:i,factFamilies:l}}import jt from"ora";function Wt(){let e=null;return{update(n){e?e.text=n:e=jt({text:n,stream:process.stderr}).start()},succeed(n){e?(e.succeed(n),e=null):console.error(`✓ ${n}`)},fail(n){e?(e.fail(n),e=null):console.error(`✗ ${n}`)}}}import{z as Ft}from"zod";var Pt=["pass","fail","unknown"],Bt=Ft.object({minAge:Ft.number().nullable(),maxAge:Ft.number().nullable()}),Gt=Ft.object({evidence:Ft.array(Bt),matchedCount:Ft.number().int().min(0),total:Ft.number().int().min(0),isComplete:Ft.boolean()}),qt={enabled:!1,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!1,redirectPriority:"low"},Ht=200;function Kt(e){return(e??"").trim().toLowerCase()}function Vt(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function zt(e){if("string"==typeof e)return e;if(Array.isArray(e)){const n=e.find(e=>"string"==typeof e);return"string"==typeof n?n:""}return""}function Yt(e,n){for(const t of n){if(!(t in e))continue;const n=zt(e[t]);if(n)return n}return""}function Jt(e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e&&""!==e.trim()){const n=Number(e);if(Number.isFinite(n))return n}return null}function Qt(e){return e.map(e=>Kt(e)).filter(Boolean)}function Zt(e,n){if(0===n.length)return!0;const t=Kt(e);return!!t&&n.some(e=>t.includes(e)||e.includes(t))}function Xt(e,n){return 0===n.length||e.some(e=>Zt(e,n))}function er(e,n){return!n||e.some(e=>Kt(e).includes(n))}function nr(e){return e.some(e=>null!==e.minAge||null!==e.maxAge)}function tr(e,n){const t=n??qt;let r=t.unknownStrategy;return"pass"===e?r=t.passStrategy:"fail"===e&&(r=t.failStrategy),{...t,status:e,strategy:r}}function rr(){return{evidence:[],matchedCount:0,total:0,isComplete:!0}}function ar(e){if(Array.isArray(e)){const n=e.map(e=>Bt.safeParse(e)).filter(e=>e.success).map(e=>e.data);return{evidence:n,matchedCount:n.length,total:n.length,isComplete:!0}}const n=Gt.safeParse(e);if(!n.success)return rr();return{evidence:n.data.evidence.map(e=>Bt.safeParse(e)).filter(e=>e.success).map(e=>e.data),matchedCount:n.data.matchedCount,total:n.data.total,isComplete:n.data.isComplete}}function or(e){return{name:"config-data",async collect(n){const t=Qt(Be(n.brandAlias,n.cityName)),r=Qt(Pe(n.cityName)),a=Kt(n.regionName),o=[];let i=0,s=0;for(const n of e.brands){if(Xt([n.name,...n.aliases??[]],t))for(const e of n.stores)if(Xt([e.city],r)&&(i+=e.positions.length,er([e.district,e.subarea,e.location,e.name],a))){s+=e.positions.length;for(const n of e.positions)o.push({minAge:n.hiringRequirements?.minAge??null,maxAge:n.hiringRequirements?.maxAge??null})}}return{evidence:o,matchedCount:s,total:i,isComplete:!0}}}}function ir({token:e,jobListUrl:n}){return{name:"duliday-api",async collect(t){try{const r=await Ve(e,n,1,Ht,{brandAlias:t.brandAlias??null,cityName:t.cityName??null}),{items:a,total:o}=qe(r),i=o>a.length&&a.length>=Ht,s=Qt(Be(t.brandAlias,t.cityName)),l=Qt(Pe(t.cityName)),u=Kt(t.regionName),c=[];let d=0;for(const e of a){if(!Vt(e))continue;const n=e,t=Vt(n.basicInfo)?n.basicInfo:null,r=t&&Vt(t.storeInfo)?t.storeInfo:null,a=Yt(n,["brandAlias","brandName","brand","organizationName"])||(t?Yt(t,["brandAlias","brandName","brand"]):""),o=Yt(n,["cityName","storeCityName","jobCityName"])||(r?Yt(r,["storeCityName","cityName"]):""),i=Yt(n,["regionName","storeRegionName","districtName"])||(r?Yt(r,["storeRegionName","regionName","districtName"]):""),m=Yt(n,["storeAddress","jobAddress","address","storeExactAddress"])||(r?Yt(r,["storeAddress","storeExactAddress","address"]):"");if(!Zt(a,s))continue;if(!Zt(o,l))continue;if(!er([i,m],u))continue;d+=1;const p=Vt(n.hiringRequirement)?n.hiringRequirement:void 0,g=Vt(p?.basicPersonalRequirements)?p.basicPersonalRequirements:void 0;c.push({minAge:Jt(g?.minAge??n.minAge),maxAge:Jt(g?.maxAge??n.maxAge)})}return{evidence:c,matchedCount:d,total:o,isComplete:!i}}catch{return rr()}}}}function sr({configData:e,token:n,jobListUrl:t}){const r=[or(e)];return n&&t&&r.push(ir({token:n,jobListUrl:t})),r}async function lr({sources:e,...n}){let t=rr();for(const r of e??[])try{const e=ar(await r.collect(n));if(0===e.total&&0===e.matchedCount&&0===e.evidence.length)continue;if(e.isComplete&&nr(e.evidence))return e;0===t.total&&0===t.matchedCount&&0===t.evidence.length&&(t=e)}catch{continue}return t}function ur({age:e,evidence:n,matchedCount:t,total:r,isComplete:a=!0,strategy:o}){const i=n.map(e=>Bt.safeParse(e)).filter(e=>e.success).map(e=>e.data),s={minAgeObserved:null,maxAgeObserved:null,matchedCount:t??i.length,total:r??i.length};if("number"!=typeof e||!Number.isFinite(e)||0===i.length||!a)return{status:"unknown",summary:s,appliedStrategy:tr("unknown",o)};let l=!1,u=!1;for(const n of i){const{minAge:t,maxAge:r}=n;null!==t&&(l=!0,s.minAgeObserved=null===s.minAgeObserved?t:Math.min(s.minAgeObserved,t)),null!==r&&(l=!0,s.maxAgeObserved=null===s.maxAgeObserved?r:Math.max(s.maxAgeObserved,r));null!==t&&e<t||null!==r&&e>r||(u=!0)}if(!l)return{status:"unknown",summary:s,appliedStrategy:tr("unknown",o)};const c=u?"pass":"fail";return{status:c,summary:s,appliedStrategy:tr(c,o)}}function cr(e){if(!e)return;const n=e.match(/(\d+)/);return n?n[1]:e}function dr(e,n){if("number"==typeof n?.age)return n.age;const t=cr(n?.age);if(t){const e=Number(t);if(Number.isFinite(e))return e}return"number"==typeof e.extractedInfo.specificAge?e.extractedInfo.specificAge:void 0}function mr(e,n){const t=e.extractedInfo.mentionedDistricts?.[0]?.district;if(t)return t;const r=e.extractedInfo.mentionedLocations?.[0]?.location;return r||(n?.jobAddress?n.jobAddress:void 0)}var pr=[{key:"age",label:"年龄"},{key:"gender",label:"性别"},{key:"education",label:"学历"},{key:"experience",label:"工作经验"},{key:"expectedSalary",label:"期望薪资"},{key:"expectedLocation",label:"期望位置"},{key:"jobAddress",label:"工作地址"},{key:"healthCertificate",label:"健康证"}];function gr(e){if(!e)return{factsText:"",knownFieldNames:[]};const n=[];for(const{key:t,label:r}of pr){const a=e[t];"string"==typeof a&&a.trim()?n.push({label:r,value:a.trim()}):"boolean"==typeof a&&n.push({label:r,value:a?"是":"否"})}return 0===n.length?{factsText:"",knownFieldNames:[]}:{factsText:n.map(e=>`${e.label}:${e.value}`).join("\n"),knownFieldNames:n.map(e=>e.label)}}function fr(e){if(null===e.minAgeObserved&&null===e.maxAgeObserved)return null;return`${e.minAgeObserved??"?"}-${e.maxAgeObserved??"?"}`}function yr(e,n,t){const r=n?.qualificationPolicy?.age;if(!e||!r||!r.enabled)return[];if("unknown"===e.status&&!t.riskFlags.includes("age_sensitive"))return[];const a=["[QualificationPolicy:Age]"],o=fr(e.summary);return a.push(`- gateStatus: ${e.status}`),a.push(`- expressionStrategy: ${e.appliedStrategy.strategy}`),a.push("- redirect: "+(r.allowRedirect?`allowed priority=${r.redirectPriority}`:"not allowed")),a.push("- revealRange: "+(r.revealRange?"allowed":"not allowed")),r.revealRange&&o&&a.push(`- rangeObserved: ${o}`),"pass"===e.status?a.push(`- writingConstraint: ${e.appliedStrategy.strategy};匹配通过后推进下一步,避免强调年龄筛选`):"fail"===e.status?(a.push(`- writingConstraint: ${e.appliedStrategy.strategy};礼貌说明不匹配,避免承诺或争辩`),r.allowRedirect&&a.push("- writingConstraint: 可提示其他岗位或门店选项")):a.push("- writingConstraint: 如确需涉及年龄或资格,用合规、轻量的方式核实,不要审查式逐条盘问"),a}function br(e){return"minimal"===e?["4. 当前为浅层沟通,优先泛化回答,不主动抛具体数字、时间、地址或筛选条件。","5. 若候选人追问具体事实,承接需求并引导进一步沟通,不编造细节。"]:["4. 围绕 primaryNeed 回答,上下文中有的事实可以正常引用,不要刻意回避。","5. 不主动展开其他事实轴;若候选人同时问两个点,只在上下文支持时简要带上次要问题。"]}function hr(e,n,t,r,a,o,i,s,l,u,c,d){if(!e)return{system:"你是招聘助手。遵循事实,不夸大承诺,回复简洁自然。",prompt:`候选人消息:${a}\n\n上下文:\n${r}\n\n请直接回复候选人。`};const m=e.stageGoals[n.stage],p=e.industryVoices[u||e.defaultIndustryVoiceId],g=e.outputGuards.maxQuestionsByMode[s];return{system:["你是政策驱动的招聘助手。",`当前阶段:${n.stage}`,`当前轮次:${i}`,`当前披露模式:${s}`,`主回答轴:${n.primaryNeed}`,`阶段目标:${m.primaryGoal}`,`阶段成功标准:${m.successCriteria.join(";")}`,`推进策略:${m.ctaStrategy}`,m.disallowedActions?.length?`阶段禁止:${m.disallowedActions.join(";")}`:"",`人格设定:语气=${e.persona.tone},亲和度=${e.persona.warmth},长度=${e.persona.length},称呼=${e.persona.addressStyle},提问风格=${e.persona.questionStyle}`,`共情策略:${e.persona.empathyStrategy}`,p?`行业指纹:${p.name};背景=${p.industryBackground};行业词=${p.jargon.join("、")};避免=${p.tabooPhrases.join("、")}`:"",`红线规则:${e.hardConstraints.rules.map(e=>e.rule).join(";")}`,`FactGate模式:${e.factGate.mode};缺事实回退=${e.factGate.fallbackBehavior}`,`禁止审查措辞:${e.outputGuards.blockedAuditPhrases.join("、")}`,...l.knownFieldNames.length>0?[`候选人资料已确认:${l.knownFieldNames.join("、")}。这些信息不得重复追问;如需引用,自然带过即可,不要像念资料一样复述。`]:[],...yr(d,e,n),c?`如涉及换微信,优先引导平台交换,必要时可提供默认微信号:${c}`:"如涉及换微信,优先引导平台交换,不编造联系方式。","必须口语化、简洁,不输出解释。"].filter(Boolean).join("\n"),prompt:["[回合规划]",`stage=${n.stage}`,`subGoals=${n.subGoals.join("、")||"无"}`,`contextNeeds=${t.join("、")||"none"}`,`primaryNeed=${n.primaryNeed}`,`riskFlags=${n.riskFlags.join("、")||"无"}`,`confidence=${n.confidence.toFixed(2)}`,"","[对话历史]",o.slice(-6).join("\n")||"无","","[业务上下文]",r,"",...l.factsText?["[候选人已知信息]",l.factsText,""]:[],"[候选人消息]",a,"","[输出要求]","1. 直接给候选人的单条回复,不得输出多段解释或元信息。",`2. 最多追问 ${g} 个关键问题。`,"3. 禁止使用“是否满足”“是否符合”“基本入职要求”等审查措辞。",...br(s)].join("\n")}}function Nr(e,n,t){const r=Ct(e);if(0===r.length)return!1;const a=new Set(Ut(n)),o=new Set(t.flatMap(e=>v[e]));return r.some(e=>!o.has(e)||!a.has(e))}function Sr(e){return"private_channel"===e||"interview_scheduling"===e}function Tr(e,n){return Number.isInteger(n)&&void 0!==n&&n>=1?n:0===e.length?1:2}function Ar(e,n){return 1===e||"trust_building"===n||"private_channel"===n?"minimal":"focused"}function Ir(e,n){const t=["- 只修正命中的违规点,没有命中的部分不要过度改写。"];return e.includes("too_many_questions")&&t.push(`- 删除多余追问,只保留最关键的 ${n} 个问题。`),e.includes("audit_tone")&&t.push("- 保留原意,但把审查式措辞改成自然口语,不要像筛选候选人。"),e.includes("premature_numeric_disclosure")&&t.push("- 把具体数字、时间和地址细节改成泛化表达,例如“细节我帮你确认”或“以门店安排为准”。"),e.includes("off_axis_fact_disclosure")&&t.push("- 删除不属于主回答轴的具体事实;如果要提到次要问题,只能做不带细节的承接。"),e.includes("reply_overpacked")&&t.push("- 压缩成最多两句,不要列表、不要枚举、不要一口气展开太多信息。"),t}async function _r(e,n,t){const r=["请重写下面这条招聘回复。","要求:","- 不新增任何具体数字、地址、福利承诺。","- 仅保留泛化表达,强调可进一步沟通确认细节。","- 口语化、单行、简洁。","","[原回复]",e,"","[可用上下文]",t].join("\n"),a=await Dn({model:n,prompt:r,context:"SmartReplyFactGateRewrite",timeoutMs:2e4,maxOutputTokens:500});return a.success?{text:a.text,usage:a.usage,latencyMs:a.latencyMs}:{text:e}}async function Er(e,n,t,r){const{turnIndex:a,effectiveDisclosureMode:o,primaryNeed:i,allowedNeeds:s,violations:l,policy:u}=r,c=u?.outputGuards.maxQuestionsByMode[o]??1,d=u?.outputGuards.blockedAuditPhrases.join("、")??"",m=Ir(l,c),p=(s??[]).filter(e=>e!==i&&"none"!==e),g=["请重写下面这条招聘回复。","要求:",`- 当前轮次=${a},披露模式=${o},主回答轴=${i}。`,p.length>0?`- 允许顺带覆盖的次要轴:${p.join("、")}。`:"",`- 当前违规点:${l.join("、")}。`,...m,"- 只保留单条口语化回复,不输出解释。",`- 问题数最多 ${c} 个。`,"- 围绕主回答轴回答,不主动展开其他事实轴。","- 首轮时不要主动报具体数字、时间、地址或筛选条件。",d?`- 禁止使用这些措辞:${d}。`:"","","[原回复]",e,"","[可用上下文]",t].filter(Boolean).join("\n"),f=await Dn({model:n,prompt:g,context:"SmartReplyReplyGateRewrite",timeoutMs:2e4,maxOutputTokens:500});return f.success?{text:f.text,usage:f.usage,latencyMs:f.latencyMs}:{text:e}}async function Rr(e){const n=Wt();me(!0);try{return await Lr(e,n)}catch(e){throw n.fail("回复生成失败"),e}finally{me(!1)}}async function Lr(e,n){const{modelConfig:t,preferredBrand:r,toolBrand:a,brandPriorityStrategy:o,conversationHistory:i=[],candidateMessage:s,configData:l,replyPolicy:u,candidateInfo:c,defaultWechatId:d,industryVoiceId:m,channelType:p,turnIndex:g,ageEligibilitySources:f}=e,y=t?.providerConfigs||he,b=Me(l),h={...b?{city:b}:{},defaultBrand:ve(l),availableBrands:Le(l),storeCount:Re(l).length},N=gr(c);n.update("分析对话意图...");const S=await tt(s,{modelConfig:t||{},conversationHistory:i,brandData:h,providerConfigs:y,...void 0!==p?{channelType:p}:{},...void 0!==u?{replyPolicy:u}:{},...N.knownFieldNames.length>0?{knownCandidateFields:N.knownFieldNames}:{}}),T=Tr(i,g),A=Ar(T,S.stage),I="focused"===A?Zn(S.primaryNeed,S.needs,s,2):[S.primaryNeed],_=a||S.extractedInfo.mentionedBrand||void 0;n.update("构建业务上下文...");const{contextInfo:E,debugInfo:R,resolvedBrand:L}=await At(l,S,r,_,o,c,u,m,T,A,I);n.update("校验候选人资格...");const O=dr(S,c),k=mr(S,c),v=S.extractedInfo.city??Me(l,L),M=f??sr({configData:l,token:We(),jobListUrl:je()}),w=await lr({sources:M,brandAlias:L,..."string"==typeof v?{cityName:v}:{},...void 0!==k?{regionName:k}:{}}),D=ur({...void 0!==O?{age:O}:{},evidence:w.evidence,matchedCount:w.matchedCount,total:w.total,isComplete:w.isComplete,...void 0!==u?.qualificationPolicy?.age?{strategy:u.qualificationPolicy.age}:{}}),C=Ee(y),U=t?.replyModel||Ne.replyModel,x=C.languageModel(U),$=hr(u,S,I,E,s,i,T,A,N,m,d,D);n.update("生成回复...");const j=await Dn({model:x,system:$.system,prompt:$.prompt,context:"SmartReply",timeoutMs:3e4,maxOutputTokens:2e3});if(!j.success)return n.fail("回复生成失败"),An("SmartReply 生成失败",j.error),{turnPlan:S,suggestedReply:"",confidence:0,shouldExchangeWechat:Sr(S.stage),factGateRewritten:!1,replyGateRewritten:!1,gateViolations:[],contextInfo:E,debugInfo:{...R,resolvedBrand:L,turnIndex:T,effectiveDisclosureMode:A,primaryNeed:S.primaryNeed,replyGateRewritten:!1,gateViolations:[],gateStatus:D.status,appliedStrategy:D.appliedStrategy,ageRangeSummary:D.summary},usage:void 0,error:j.error};let W=j.text,F=j.usage,P=j.latencyMs,B=!1,G=!1,q=[];if(n.update("检查回复质量..."),"strict"===u?.factGate.mode){if(Nr(W,E,I)){B=!0;const e=await _r(W,x,E);W=e.text,e.usage&&(F=e.usage),void 0!==e.latencyMs&&(P=(P??0)+e.latencyMs)}}if(q=$t({text:W,turnIndex:T,mode:A,primaryNeed:S.primaryNeed,allowedNeeds:I,policy:u}).violations,q.length>0){n.update("优化回复..."),G=!0;const e=await Er(W,x,E,{turnIndex:T,effectiveDisclosureMode:A,primaryNeed:S.primaryNeed,allowedNeeds:I,violations:q,policy:u});W=e.text,e.usage&&(F=e.usage),void 0!==e.latencyMs&&(P=(P??0)+e.latencyMs),q=$t({text:W,turnIndex:T,mode:A,primaryNeed:S.primaryNeed,allowedNeeds:I,policy:u}).violations}const H=P??0,K=F?.totalTokens??0;return n.succeed(`回复已生成 | ${S.stage} | ${H}ms | ${K} tokens${G?" | 已优化":""}`),{turnPlan:S,suggestedReply:W,confidence:Math.max(0,Math.min(1,S.confidence)),shouldExchangeWechat:Sr(S.stage),factGateRewritten:B,replyGateRewritten:G,gateViolations:q,contextInfo:`${E}\n当前品牌:${L}`,debugInfo:{...R,resolvedBrand:L,turnIndex:T,effectiveDisclosureMode:A,primaryNeed:S.primaryNeed,replyGateRewritten:G,gateViolations:q,gateStatus:D.status,appliedStrategy:D.appliedStrategy,ageRangeSummary:D.summary},usage:F,latencyMs:P}}var Or=t.enum(It),kr=t.enum(Pt),vr=n({name:"generate_reply",description:"根据候选人消息、对话历史和品牌数据生成智能招聘回复。内部流程:回合规划 → primaryNeed 驱动上下文构建 → 年龄资格校验 → 策略化回复生成 → FactGate/ReplyGate 校验。",input:t.object({candidateMessage:t.string().describe("候选人发送的消息"),conversationHistory:t.array(t.string()).optional().describe("对话历史(最近几轮)"),candidateInfo:i.optional().describe("候选人基本信息"),preferredBrand:t.string().optional().describe("偏好品牌"),channelType:_.optional().describe("渠道类型: public(BOSS直聘) 或 private(微信)"),defaultWechatId:t.string().optional().describe("默认微信号"),industryVoiceId:t.string().optional().describe("行业语调ID"),turnIndex:t.number().int().min(1).optional().describe("当前会话回复轮次"),modelConfig:$n.optional().describe("模型配置覆盖")}),output:t.object({suggestedReply:t.string(),confidence:t.number(),stage:I,replyPolicySource:t.enum(["file","default"]).describe("回复策略来源: file=自定义配置文件, default=内置默认策略"),latencyMs:t.number().optional(),shouldExchangeWechat:t.boolean().optional(),error:t.string().optional(),diagnostics:t.object({subGoals:t.array(t.string()),needs:t.array(O),primaryNeed:O,riskFlags:t.array(k),reasoningText:t.string(),extractedInfo:t.object({mentionedBrand:t.string().nullable(),city:t.string().nullable(),specificAge:t.number().nullable(),hasUrgency:t.boolean().nullable(),preferredSchedule:t.string().nullable()}),ageGate:t.object({enabled:t.boolean(),status:kr,strategy:t.string()}),resolvedBrand:t.string(),storeCount:t.number(),detailLevel:E,turnIndex:t.number(),effectiveDisclosureMode:E,replyGateRewritten:t.boolean(),gateViolations:t.array(Or),factGateRewritten:t.boolean()}).optional()}),execute:async(e,n)=>{n.logger.info(`Processing message: ${e.candidateMessage.slice(0,50)}...`);const{policy:t,source:r}=re();let a;try{a=ee()}catch{return{suggestedReply:"",confidence:0,stage:"trust_building",replyPolicySource:r,error:"品牌数据未配置,请先调用 sync_brand_data 写入数据"}}const o=await Rr({candidateMessage:e.candidateMessage,conversationHistory:e.conversationHistory,candidateInfo:e.candidateInfo,preferredBrand:e.preferredBrand,channelType:e.channelType,defaultWechatId:e.defaultWechatId,industryVoiceId:e.industryVoiceId,turnIndex:e.turnIndex,modelConfig:e.modelConfig,configData:a,replyPolicy:t});n.logger.info(`Reply generated. Stage: ${o.turnPlan.stage}, Confidence: ${o.confidence}`);const i=o.debugInfo;return{suggestedReply:o.suggestedReply,confidence:o.confidence,stage:o.turnPlan.stage,replyPolicySource:r,latencyMs:o.latencyMs,shouldExchangeWechat:o.shouldExchangeWechat,error:o.error?.userMessage,diagnostics:i?{subGoals:o.turnPlan.subGoals,needs:o.turnPlan.needs,primaryNeed:o.turnPlan.primaryNeed,riskFlags:o.turnPlan.riskFlags,reasoningText:o.turnPlan.reasoningText,extractedInfo:{mentionedBrand:o.turnPlan.extractedInfo.mentionedBrand??null,city:o.turnPlan.extractedInfo.city??null,specificAge:o.turnPlan.extractedInfo.specificAge??null,hasUrgency:o.turnPlan.extractedInfo.hasUrgency??null,preferredSchedule:o.turnPlan.extractedInfo.preferredSchedule??null},ageGate:{enabled:i.appliedStrategy.enabled,status:i.gateStatus,strategy:i.appliedStrategy.strategy},resolvedBrand:i.resolvedBrand,storeCount:i.storeCount,detailLevel:i.detailLevel,turnIndex:i.turnIndex,effectiveDisclosureMode:i.effectiveDisclosureMode,replyGateRewritten:o.replyGateRewritten,gateViolations:o.gateViolations,factGateRewritten:o.factGateRewritten}:void 0}}});import{defineTool as Mr}from"@roll-agent/sdk";import{z as wr}from"zod";import{z as Dr}from"zod";var Cr=Dr.object({content:Dr.string(),image:Dr.string().nullable().optional()}).passthrough(),Ur=Dr.object({storeId:Dr.number().optional(),storeName:Dr.string(),storeCityName:Dr.string().optional(),storeRegionName:Dr.string().optional(),storeAddress:Dr.string().optional(),longitude:Dr.number().optional(),latitude:Dr.number().optional()}).passthrough(),xr=Dr.object({jobId:Dr.number(),jobName:Dr.string(),jobNickName:Dr.string().nullable().optional(),jobCategoryName:Dr.string().nullable().optional(),jobContent:Dr.string().nullable().optional(),laborForm:Dr.string().nullable().optional(),needTraining:Dr.string().nullable().optional(),needProbationWork:Dr.string().nullable().optional(),brandId:Dr.number().optional(),brandName:Dr.string().optional(),projectId:Dr.number().optional(),projectName:Dr.string().optional(),storeInfo:Ur.optional()}).passthrough(),$r=Dr.object({salaryType:Dr.string().nullable().optional(),salaryPeriod:Dr.string().nullable().optional(),hasStairSalary:Dr.string().nullable().optional(),basicSalary:Dr.object({basicSalary:Dr.number().nullable().optional(),basicSalaryUnit:Dr.string().nullable().optional()}).passthrough().nullable().optional(),stairSalaries:Dr.array(Dr.object({fullWorkTime:Dr.number().nullable().optional(),fullWorkTimeUnit:Dr.string().nullable().optional(),salary:Dr.number().nullable().optional(),salaryUnit:Dr.string().nullable().optional()}).passthrough()).nullable().optional(),comprehensiveSalary:Dr.object({minComprehensiveSalary:Dr.number().nullable().optional(),maxComprehensiveSalary:Dr.number().nullable().optional(),comprehensiveSalaryUnit:Dr.string().nullable().optional()}).passthrough().nullable().optional(),holidaySalary:Dr.object({holidaySalaryType:Dr.string().nullable().optional(),holidaySalaryMultiple:Dr.number().nullable().optional(),holidayFixedSalary:Dr.number().nullable().optional(),holidayFixedSalaryUnit:Dr.string().nullable().optional()}).passthrough().nullable().optional()}).passthrough(),jr=Dr.object({salary:Dr.number().optional(),salaryUnitStr:Dr.string().optional(),salaryScenarioList:Dr.array($r).nullable().optional()}).passthrough(),Wr=Dr.object({haveInsurance:Dr.string(),accommodation:Dr.string(),catering:Dr.string().optional(),otherWelfare:Dr.array(Dr.string()).nullable().optional(),accommodationAllowance:Dr.number().nullable().optional(),accommodationAllowanceUnit:Dr.string().nullable().optional(),cateringSalary:Dr.number().nullable().optional(),cateringSalaryUnit:Dr.string().nullable().optional(),trafficAllowanceSalary:Dr.number().nullable().optional(),trafficAllowanceSalaryUnit:Dr.string().nullable().optional(),memo:Dr.string().nullable().optional(),promotionWelfare:Dr.string().nullable().optional(),moreWelfares:Dr.array(Cr).nullable().optional()}).passthrough(),Fr=Dr.object({minAge:Dr.number().nullable().optional(),maxAge:Dr.number().nullable().optional(),genderRequirement:Dr.string().nullable().optional()}).passthrough(),Pr=Dr.object({education:Dr.string().nullable().optional(),healthCertificate:Dr.string().nullable().optional(),certificates:Dr.string().nullable().optional()}).passthrough(),Br=Dr.object({languages:Dr.string().nullable().optional(),languageRemark:Dr.string().nullable().optional()}).passthrough(),Gr=Dr.object({cooperationMode:Dr.number().optional(),requirementNum:Dr.number().optional(),thresholdNum:Dr.number().optional(),signUpNum:Dr.number().nullable().optional(),basicPersonalRequirements:Fr.nullable().optional(),certificate:Pr.nullable().optional(),language:Br.nullable().optional(),figure:Dr.string().nullable().optional(),remark:Dr.string().nullable().optional()}).passthrough(),qr=Dr.object({employmentForm:Dr.string(),minWorkMonths:Dr.number().nullable().optional(),maxWorkTakingTime:Dr.number().nullable().optional(),restTimeDesc:Dr.string().nullable().optional(),workTimeRemark:Dr.string().nullable().optional(),employmentDescription:Dr.string().nullable().optional(),weekWorkTime:Dr.object({weekWorkTimeRequirement:Dr.string().nullable().optional(),perWeekWorkDays:Dr.number().nullable().optional(),perWeekRestDays:Dr.number().nullable().optional(),perWeekNeedWorkDays:Dr.union([Dr.string(),Dr.number()]).nullable().optional(),workSingleDouble:Dr.string().nullable().optional(),customnWorkTimeList:Dr.array(Dr.object({customMinWorkDays:Dr.number().nullable().optional(),customMaxWorkDays:Dr.number().nullable().optional(),customWorkWeekdays:Dr.array(Dr.union([Dr.string(),Dr.number()])).nullable().optional()}).passthrough()).nullable().optional()}).passthrough().nullable().optional(),monthWorkTime:Dr.object({perMonthMinWorkTime:Dr.number().nullable().optional(),perMonthMinWorkTimeUnit:Dr.union([Dr.string(),Dr.number()]).nullable().optional(),monthWorkTimeRequirement:Dr.string().nullable().optional(),perMonthMaxRestTime:Dr.number().nullable().optional(),perMonthMaxRestTimeUnit:Dr.number().nullable().optional()}).passthrough().nullable().optional(),dayWorkTime:Dr.object({perDayMinWorkHours:Dr.union([Dr.string(),Dr.number()]).nullable().optional(),dayWorkTimeRequirement:Dr.string().nullable().optional()}).passthrough().nullable().optional(),dailyShiftSchedule:Dr.object({arrangementType:Dr.string().nullable().optional(),fixedScheduleList:Dr.array(Dr.object({fixedShiftStartTime:Dr.union([Dr.string(),Dr.number()]).optional(),fixedShiftEndTime:Dr.union([Dr.string(),Dr.number()]).optional(),startTime:Dr.number().optional(),endTime:Dr.number().optional()}).passthrough()).nullable().optional(),combinedArrangement:Dr.array(Dr.object({CombinedArrangementWeekdays:Dr.union([Dr.string(),Dr.array(Dr.number())]).optional(),CombinedArrangementStartTime:Dr.number().optional(),CombinedArrangementEndTime:Dr.number().optional(),combinedArrangementStartTime:Dr.union([Dr.string(),Dr.number()]).optional(),combinedArrangementEndTime:Dr.union([Dr.string(),Dr.number()]).optional(),startTime:Dr.number().optional(),endTime:Dr.number().optional(),weekdays:Dr.array(Dr.number()).optional()}).passthrough()).nullable().optional(),fixedTime:Dr.object({goToWorkStartTime:Dr.union([Dr.string(),Dr.number()]).nullable().optional(),goToWorkEndTime:Dr.union([Dr.string(),Dr.number()]).nullable().optional(),goOffWorkStartTime:Dr.union([Dr.string(),Dr.number()]).nullable().optional(),goOffWorkEndTime:Dr.union([Dr.string(),Dr.number()]).nullable().optional()}).passthrough().nullable().optional()}).passthrough().nullable().optional(),temporaryEmployment:Dr.object({temporaryEmploymentStartTime:Dr.string().nullable().optional(),temporaryEmploymentEndTime:Dr.string().nullable().optional()}).passthrough().nullable().optional()}).passthrough(),Hr=Dr.object({basicInfo:xr,jobSalary:jr,welfare:Wr,hiringRequirement:Gr,workTime:qr}).passthrough();function Kr(e){const n=Hr.safeParse(e);if(!n.success)return null;const t=n.data,r=t.basicInfo,a=r.storeInfo,o=t.jobSalary,i=t.hiringRequirement,s=o.salary??o.salaryScenarioList?.find(e=>"正式"===e.salaryType)?.basicSalary?.basicSalary??o.salaryScenarioList?.[0]?.basicSalary?.basicSalary??null,l=o.salaryUnitStr??o.salaryScenarioList?.find(e=>"正式"===e.salaryType)?.basicSalary?.basicSalaryUnit??o.salaryScenarioList?.[0]?.basicSalary?.basicSalaryUnit??null;let u=a?.storeId;if(null==u){const e=`${a?.storeName??""}|${a?.storeAddress??""}`;u=Array.from(e).reduce((e,n)=>31*e+n.charCodeAt(0)>>>0,7)}return{jobId:r.jobId,jobName:r.jobName,jobNickName:r.jobNickName??null,jobCategoryName:r.jobCategoryName??null,jobContent:r.jobContent??null,laborForm:r.laborForm??null,employmentForm:t.workTime.employmentForm,trainingRequired:r.needTraining??null,probationRequired:r.needProbationWork??null,brandId:void 0!==r.brandId?String(r.brandId):void 0!==r.projectId?String(r.projectId):void 0,brandName:r.brandName,projectId:r.projectId,projectName:r.projectName,storeId:u,storeName:a?.storeName??"未知门店",storeCityName:a?.storeCityName??"",storeRegionName:a?.storeRegionName,storeAddress:a?.storeAddress??"",longitude:a?.longitude,latitude:a?.latitude,salary:s,salaryUnitStr:l,salaryScenarioList:o.salaryScenarioList??null,welfare:t.welfare,requirementNum:i.requirementNum??0,signUpNum:i.signUpNum??null,basicPersonalRequirements:i.basicPersonalRequirements?{minAge:i.basicPersonalRequirements.minAge??null,maxAge:i.basicPersonalRequirements.maxAge??null,genderRequirement:i.basicPersonalRequirements.genderRequirement??null}:null,certificate:i.certificate?{education:i.certificate.education??null,healthCertificate:i.certificate.healthCertificate??null}:null,languages:i.language?.languages??null,certificatesRaw:i.certificate?.certificates??null,recruitmentRemark:i.remark??null,socialIdentity:i.figure??null,workTime:t.workTime,perMonthMinWorkTime:t.workTime.monthWorkTime?.perMonthMinWorkTime??null,perMonthMinWorkTimeUnit:t.workTime.monthWorkTime?.perMonthMinWorkTimeUnit??null}}function Vr(e,n,t){const r=new Map;let a;for(let o=0;o<e.length;o++){const i=Kr(e[o]);if(!i)continue;const s=i.brandName??n??"未知品牌",l=i.brandId??`name:${s}`;void 0!==a||void 0!==n&&s!==n||(a=l);let u=r.get(l);u||(u={id:l,name:s,stores:[]},r.set(l,u));const c=`store_${i.storeId}`;let d=u.stores.find(e=>e.id===c);d||(d=zr(i,l,t),u.stores.push(d));const m=Yr(i);d.positions.push(m)}return{meta:{...a??r.values().next().value?.id?{defaultBrandId:a??r.values().next().value?.id}:{},syncedAt:(new Date).toISOString(),source:"duliday"},brands:Array.from(r.values())}}function zr(e,n,t){return{id:`store_${e.storeId}`,brandId:n,name:e.storeName,city:e.storeCityName||t,location:e.storeAddress,district:la(e.storeAddress,e.storeRegionName),subarea:ua(e.storeName),coordinates:"number"==typeof e.latitude&&"number"==typeof e.longitude?{lat:e.latitude,lng:e.longitude}:{lat:0,lng:0},positions:[]}}function Yr(e){const n=Jr(e.workTime);let t=[];return n.combinedArrangementTimes?.length?t=sa(n.combinedArrangementTimes):n.fixedArrangementTimes?.length&&(t=sa(n.fixedArrangementTimes.map(e=>({...e,weekdays:[]})))),{id:`pos_${e.jobId}`,name:e.jobNickName??ca(e.jobName),sourceJobName:e.jobName,jobCategory:e.jobCategoryName,brandId:e.brandId,brandName:e.brandName,projectId:void 0!==e.projectId?String(e.projectId):void 0,projectName:e.projectName,description:e.jobContent||null,laborForm:e.laborForm,employmentForm:e.employmentForm,trainingRequired:e.trainingRequired,probationRequired:e.probationRequired,salary:{...Qr(e.salary,e.salaryUnitStr,e.welfare),scenarioSummary:Zr(e.salaryScenarioList),settlementCycle:Xr(e.salaryScenarioList)},timeSlots:t,workHours:null!=n.perDayMinWorkHours?String(n.perDayMinWorkHours):null,minHoursPerWeek:ra(n),maxHoursPerWeek:aa(n),perMonthMinWorkTime:e.perMonthMinWorkTime,perMonthMinWorkTimeUnit:e.perMonthMinWorkTimeUnit,attendanceRequirement:oa(n),availableSlots:ta(e,n),benefits:ea(e.welfare),hiringRequirements:na(e)}}function Jr(e){const n=e.weekWorkTime,t=e.dayWorkTime,r=e.dailyShiftSchedule,a=Number(r?.arrangementType)||({"固定排班制":1,"组合排班制":3}[String(r?.arrangementType)]??0),o=null!=t?.perDayMinWorkHours?Number(t.perDayMinWorkHours):null,i=null!==o&&Number.isFinite(o)?o:null,s=n?.customnWorkTimeList?.map(e=>({weekdays:Array.isArray(e.customWorkWeekdays)?e.customWorkWeekdays.map(e=>Number(e)).filter(e=>Number.isFinite(e)):[],minWorkDays:e.customMinWorkDays??null,maxWorkDays:e.customMaxWorkDays??null}))??null,l=r?.fixedScheduleList?.map(e=>({startTime:e.startTime??ia(e.fixedShiftStartTime),endTime:e.endTime??ia(e.fixedShiftEndTime)}))??null,u=r?.combinedArrangement?.map(e=>{const n=null!=e.combinedArrangementStartTime?ia(e.combinedArrangementStartTime):void 0,t=null!=e.combinedArrangementEndTime?ia(e.combinedArrangementEndTime):void 0,r=(e.weekdays??("string"==typeof e.CombinedArrangementWeekdays?[Number(e.CombinedArrangementWeekdays)]:Array.isArray(e.CombinedArrangementWeekdays)?e.CombinedArrangementWeekdays:[])).map(e=>"number"==typeof e?e:Number(e)).filter(e=>Number.isFinite(e));return{startTime:e.startTime??e.CombinedArrangementStartTime??n??0,endTime:e.endTime??e.CombinedArrangementEndTime??t??0,weekdays:r}})??null;return{perDayMinWorkHours:i,perWeekWorkDays:n?.perWeekWorkDays??null,perWeekNeedWorkDays:null!=n?.perWeekNeedWorkDays?Number(n.perWeekNeedWorkDays):null,perWeekRestDays:n?.perWeekRestDays??null,arrangementType:a,maxWorkTakingTime:e.maxWorkTakingTime??0,workTimeRemark:e.workTimeRemark??null,fixedArrangementTimes:l,combinedArrangementTimes:u,customWorkTimes:s}}function Qr(e,n,t){const r=t.memo??null,a=r?.match(/(\d+元?-\d+元?)/),o=a?a[1]:void 0,i=r?.match(/(奖金[\d~\-~元]+)/);return{base:e,unit:n,range:o,bonus:i?i[1]:void 0,memo:r}}function Zr(e){if(!e||0===e.length)return;const n=[];for(const t of e){if("培训期"===t.salaryType)continue;if(t.stairSalaries?.length){const e=t.stairSalaries.filter(e=>null!=e.salary).map(e=>{const n=e.salaryUnit??"元/时";return`满${e.fullWorkTime??"?"}${e.fullWorkTimeUnit??"小时"}后${e.salary}${n}`}).join(",");e&&n.push(e)}const e=t.comprehensiveSalary;null!=e?.minComprehensiveSalary&&null!=e?.maxComprehensiveSalary&&n.push(`综合${e.minComprehensiveSalary}-${e.maxComprehensiveSalary}${e.comprehensiveSalaryUnit??"元/月"}`);const r=t.holidaySalary;r&&(r.holidaySalaryMultiple?n.push(`节假日${r.holidaySalaryMultiple}倍`):null!=r.holidayFixedSalary&&n.push(`节假日${r.holidayFixedSalary}${r.holidayFixedSalaryUnit??"元/时"}`))}return n.length>0?n.join(";"):void 0}function Xr(e){if(!e||0===e.length)return;const n=e.find(e=>"正式"===e.salaryType)??e[0];return{"日结算":"日结","周结算":"周结","月结算":"月结","完结算":"完结","半月结算":"半月结"}[n?.salaryPeriod??""]??void 0}function ea(e){const n=e.moreWelfares&&Array.isArray(e.moreWelfares)&&e.moreWelfares.length>0?e.moreWelfares.map(e=>e.content):null;return{insurance:e.haveInsurance||null,accommodation:e.accommodation||null,catering:e.catering??null,moreWelfares:n,memo:e.memo??null,promotion:e.promotionWelfare??null}}function na(e){const n=e.basicPersonalRequirements,t=e.certificate;if(n||t||e.languages||e.certificatesRaw||e.recruitmentRemark||e.socialIdentity)return{minAge:n?.minAge??null,maxAge:n?.maxAge??null,genderRequirement:n?.genderRequirement??null,education:t?.education??null,healthCertificate:t?.healthCertificate??null,languages:e.languages,certificatesRaw:e.certificatesRaw,recruitmentRemark:e.recruitmentRemark,socialIdentity:e.socialIdentity}}function ta(e,n){const t=[];let r=[];n.combinedArrangementTimes?.length?r=sa(n.combinedArrangementTimes):n.fixedArrangementTimes?.length&&(r=sa(n.fixedArrangementTimes.map(e=>({...e,weekdays:[]}))));for(const n of r)t.push({slot:n,maxCapacity:e.requirementNum,currentBooked:e.signUpNum||0,isAvailable:(e.signUpNum||0)<e.requirementNum,priority:e.requirementNum>3?"high":"medium"});return t}function ra(e){const n=e.perDayMinWorkHours;if(null==n)return null;let t=null;if(null!=e.perWeekWorkDays&&(t=e.perWeekWorkDays),null===t&&e.customWorkTimes?.length){const n=e.customWorkTimes.map(e=>e.minWorkDays).filter(e=>null!=e);n.length>0&&(t=Math.min(...n))}return null===t&&null!=e.perWeekNeedWorkDays&&(t=e.perWeekNeedWorkDays),null===t?null:n*t}function aa(e){const n=e.perDayMinWorkHours;if(null==n||null==e.perWeekWorkDays)return null;return n*e.perWeekWorkDays}function oa(e){let n=[];if(e.combinedArrangementTimes?.length){const t=new Set;for(const n of e.combinedArrangementTimes)for(const e of n.weekdays)null!=e&&Number.isFinite(e)&&t.add(e);n=Array.from(t).sort()}else if(e.customWorkTimes?.length){const t=new Set;for(const n of e.customWorkTimes)for(const e of n.weekdays)null!=e&&Number.isFinite(e)&&t.add(e);n=Array.from(t).sort()}let t=null;if(null!=e.perWeekWorkDays&&(t=e.perWeekWorkDays),null===t&&e.customWorkTimes?.length){const n=e.customWorkTimes.map(e=>e.minWorkDays).filter(e=>null!=e);n.length>0&&(t=Math.min(...n))}return null===t&&null!=e.perWeekNeedWorkDays&&(t=e.perWeekNeedWorkDays),{minimumDays:t,requiredDays:da(n),description:e.workTimeRemark??null}}function ia(e){if("number"==typeof e)return e;if("string"!=typeof e||!e)return 0;const n=e.match(/^(\d{1,2}):(\d{2})$/);return n?3600*Number(n[1])+60*Number(n[2]):Number(e)||0}function sa(e){return e.map(e=>{const n=Math.floor(e.startTime/3600),t=Math.floor(e.startTime%3600/60),r=Math.floor(e.endTime/3600),a=Math.floor(e.endTime%3600/60);return`${n.toString().padStart(2,"0")}:${t.toString().padStart(2,"0")}~${r.toString().padStart(2,"0")}:${a.toString().padStart(2,"0")}`})}function la(e,n){if(n)return n;return e.split("-")[1]||null}function ua(e){const n=e.match(/(.+?)(附近|周边|旁边|店)/);return n?.[1]??null}function ca(e){const n=e.split("-");return n[n.length-2]||e}function da(e){return e.filter(e=>Number.isFinite(e)).map(e=>0===e?7:e)}var ma=Mr({name:"sync_brand_data",description:"从 Duliday API 拉取并同步品牌配置数据(门店、岗位、薪资等)到本地。可选传入品牌别名和城市名称作为过滤条件。",input:wr.object({brandAlias:wr.string().optional().describe("品牌别名(可选,配合 cityName 使用可按品牌过滤)"),cityName:wr.string().describe('城市名称(必填,Duliday API 要求至少提供城市作为筛选条件,如 "上海市")')}),output:wr.object({success:wr.boolean(),brandsCount:wr.number(),storesCount:wr.number(),positionsCount:wr.number(),updatedAt:wr.string(),error:wr.string().optional()}),execute:async(e,n)=>{const t=We(),r=je();if(!t||!r)return{success:!1,brandsCount:0,storesCount:0,positionsCount:0,updatedAt:(new Date).toISOString(),error:`缺少环境变量: ${[!t&&"DULIDAY_TOKEN",!r&&"DULIDAY_JOB_LIST_URL"].filter(Boolean).join(", ")}`};if(!e.cityName)return{success:!1,brandsCount:0,storesCount:0,positionsCount:0,updatedAt:(new Date).toISOString(),error:'cityName 为必填项,Duliday API 要求至少提供城市作为筛选条件(如 "上海市")'};try{n.logger.info("Fetching all job list pages from Duliday API...");const{items:a}=await ze(t,r,{brandAlias:e.brandAlias??null,cityName:e.cityName??null,include:He});let o=ga(a);!o&&e.brandAlias&&(o=await fa(e.brandAlias,t)),!o&&e.brandAlias&&(o=e.brandAlias),n.logger.info(`Resolved default brand: ${o??"自动推断"}, converting ${a.length} positions...`);const i=Vr(a,o,e.cityName);ne(i),n.logger.info(`Brand config saved: ${i.brands.length} brands, ${i.brands.reduce((e,n)=>e+n.stores.length,0)} stores`);const s=i.brands.reduce((e,n)=>e+n.stores.length,0),l=i.brands.reduce((e,n)=>e+n.stores.reduce((e,n)=>e+n.positions.length,0),0);return{success:!0,brandsCount:i.brands.length,storesCount:s,positionsCount:l,updatedAt:(new Date).toISOString()}}catch(e){return{success:!1,brandsCount:0,storesCount:0,positionsCount:0,updatedAt:(new Date).toISOString(),error:e instanceof Error?e.message:String(e)}}}});function pa(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function ga(e){for(const n of e){if(!pa(n))continue;const e=pa(n.basicInfo)?n.basicInfo:null;if(e&&"string"==typeof e.brandName&&e.brandName)return e.brandName}}async function fa(e,n){try{const t=await gt(n),r=e.trim().toLowerCase().replace(/[\s._-]+/g,"");return t.get(r)}catch{return}}var ya=e({name:"smart-reply-agent",tools:[vr,ma]});ya.listen().catch(e=>{console.error("Fatal error:",e),process.exit(1)});
@@ -2,5 +2,10 @@ import type { ZhipinData } from "../types/zhipin.ts";
2
2
  import type { ReplyPolicyConfig } from "../types/reply-policy.ts";
3
3
  export declare function loadBrandConfig(): ZhipinData;
4
4
  export declare function saveBrandConfig(data: ZhipinData): void;
5
- export declare function loadReplyPolicy(): ReplyPolicyConfig;
5
+ export type ReplyPolicySource = "file" | "default";
6
+ export interface ReplyPolicyLoadResult {
7
+ readonly policy: ReplyPolicyConfig;
8
+ readonly source: ReplyPolicySource;
9
+ }
10
+ export declare function loadReplyPolicy(): ReplyPolicyLoadResult;
6
11
  export declare function saveReplyPolicy(policy: ReplyPolicyConfig): void;
@@ -39,6 +39,7 @@ export declare const generateReply: import("@roll-agent/sdk").ToolDefinition<{
39
39
  confidence: number;
40
40
  stage: "trust_building" | "private_channel" | "qualify_candidate" | "job_consultation" | "interview_scheduling" | "onboard_followup";
41
41
  suggestedReply: string;
42
+ replyPolicySource: "default" | "file";
42
43
  error?: string | undefined;
43
44
  latencyMs?: number | undefined;
44
45
  shouldExchangeWechat?: boolean | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roll-agent/smart-reply-agent",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -46,13 +46,13 @@
46
46
  }
47
47
  },
48
48
  "dependencies": {
49
- "@ai-sdk/alibaba": "^1.0.13",
50
- "@ai-sdk/anthropic": "^3.0.53",
51
- "@ai-sdk/deepseek": "^2.0.22",
52
- "@ai-sdk/google": "^3.0.36",
53
- "@ai-sdk/openai": "^3.0.39",
54
- "@ai-sdk/openai-compatible": "^2.0.33",
55
- "ai": "^6.0.108",
49
+ "@ai-sdk/alibaba": "^1.0.17",
50
+ "@ai-sdk/anthropic": "^3.0.68",
51
+ "@ai-sdk/deepseek": "^2.0.29",
52
+ "@ai-sdk/google": "^3.0.60",
53
+ "@ai-sdk/openai": "^3.0.52",
54
+ "@ai-sdk/openai-compatible": "^2.0.41",
55
+ "ai": "^6.0.154",
56
56
  "ora": "^8.2.0",
57
57
  "zod": "^3.25.76",
58
58
  "@roll-agent/sdk": "0.1.5"