@roll-agent/smart-reply-agent 0.4.0 → 1.1.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 +25 -37
- package/dist/index.js +1 -1
- package/dist/services/reply-authority-client.d.ts +2 -0
- package/dist/tools/generate-reply.d.ts +31 -43
- package/dist/types/candidate-info.d.ts +57 -0
- package/dist/types/funnel-stage.d.ts +4 -0
- package/dist/types/model-config.d.ts +66 -0
- package/dist/types/reply-authority.d.ts +785 -0
- package/package.json +2 -16
- package/references/env.yaml +6 -26
- package/data/brand-config.sample.json +0 -83
- package/dist/ai/model-registry.d.ts +0 -103
- package/dist/ai/structured-output.d.ts +0 -61
- package/dist/errors/app-error.d.ts +0 -42
- package/dist/errors/error-codes.d.ts +0 -48
- package/dist/errors/error-factory.d.ts +0 -30
- package/dist/errors/error-utils.d.ts +0 -39
- package/dist/errors/index.d.ts +0 -8
- package/dist/log-control.d.ts +0 -2
- package/dist/pipeline/age-eligibility.d.ts +0 -94
- package/dist/pipeline/candidate-context.d.ts +0 -8
- package/dist/pipeline/candidate-utils.d.ts +0 -5
- package/dist/pipeline/classification.d.ts +0 -13
- package/dist/pipeline/context-builder.d.ts +0 -21
- package/dist/pipeline/pipeline-progress.d.ts +0 -9
- package/dist/pipeline/reply-gate.d.ts +0 -19
- package/dist/pipeline/smart-reply.d.ts +0 -64
- package/dist/pipeline.d.ts +0 -21
- package/dist/pipeline.js +0 -1
- package/dist/services/brand-alias.d.ts +0 -4
- package/dist/services/brand-config-selectors.d.ts +0 -7
- package/dist/services/config-loader.d.ts +0 -11
- package/dist/services/duliday-api.d.ts +0 -30
- package/dist/services/duliday-mapper.d.ts +0 -8
- package/dist/tools/sync-brand-data.d.ts +0 -11
- package/dist/types/brand-resolution.d.ts +0 -83
- package/dist/types/classification.d.ts +0 -181
- package/dist/types/config.d.ts +0 -3
- package/dist/types/duliday-api.d.ts +0 -7197
- package/dist/types/geocoding.d.ts +0 -23
- package/dist/types/reply-policy.d.ts +0 -1390
- package/dist/types/zhipin.d.ts +0 -2196
- package/references/reply-policy-schema.md +0 -148
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface PipelineProgress {
|
|
2
|
-
/** 更新 spinner 文本,首次调用自动启动 */
|
|
3
|
-
update(text: string): void;
|
|
4
|
-
/** 停止 spinner,显示最终摘要行 */
|
|
5
|
-
succeed(text: string): void;
|
|
6
|
-
/** 停止 spinner,显示失败信息 */
|
|
7
|
-
fail(text: string): void;
|
|
8
|
-
}
|
|
9
|
-
export declare function createPipelineProgress(): PipelineProgress;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { type EffectiveDisclosureMode, type ReplyFactFamily, type ReplyNeed, type ReplyPolicyConfig } from "../types/reply-policy.ts";
|
|
2
|
-
export declare const REPLY_GATE_VIOLATION_CODES: readonly ["too_many_questions", "audit_tone", "premature_numeric_disclosure", "off_axis_fact_disclosure", "reply_overpacked"];
|
|
3
|
-
export type ReplyGateViolationCode = (typeof REPLY_GATE_VIOLATION_CODES)[number];
|
|
4
|
-
export interface ReplyGateValidationResult {
|
|
5
|
-
violations: ReplyGateViolationCode[];
|
|
6
|
-
questionCount: number;
|
|
7
|
-
factFamilies: ReplyFactFamily[];
|
|
8
|
-
}
|
|
9
|
-
export declare function countQuestions(text: string): number;
|
|
10
|
-
export declare function detectConcreteFactFamilies(text: string): ReplyFactFamily[];
|
|
11
|
-
export declare function detectContextFactFamilies(contextInfo: string): ReplyFactFamily[];
|
|
12
|
-
export declare function validateReply(options: {
|
|
13
|
-
text: string;
|
|
14
|
-
turnIndex: number;
|
|
15
|
-
mode: EffectiveDisclosureMode;
|
|
16
|
-
primaryNeed: ReplyNeed;
|
|
17
|
-
allowedNeeds?: ReplyNeed[] | undefined;
|
|
18
|
-
policy?: ReplyPolicyConfig | undefined;
|
|
19
|
-
}): ReplyGateValidationResult;
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { ZhipinData, CandidateInfo } from "../types/zhipin.ts";
|
|
2
|
-
import type { BrandPriorityStrategy } from "../types/config.ts";
|
|
3
|
-
import type { StoreWithDistance } from "../types/geocoding.ts";
|
|
4
|
-
import type { TurnPlan, ReplyNeed, FunnelStage, ChannelType, ReplyPolicyConfig, EffectiveDisclosureMode } from "../types/reply-policy.ts";
|
|
5
|
-
import type { ProviderConfigs } from "../types/classification.ts";
|
|
6
|
-
import { type ReplyGateViolationCode } from "./reply-gate.ts";
|
|
7
|
-
import type { SafeGenerateTextUsage } from "../ai/structured-output.ts";
|
|
8
|
-
import type { AppError } from "../errors/index.ts";
|
|
9
|
-
import type { AgeEligibilitySource, AgeEligibilityAppliedStrategy, AgeEligibilityStatus, AgeEligibilitySummary } from "./age-eligibility.ts";
|
|
10
|
-
export interface SmartReplyAgentOptions {
|
|
11
|
-
modelConfig?: {
|
|
12
|
-
chatModel?: string | undefined;
|
|
13
|
-
classifyModel?: string | undefined;
|
|
14
|
-
replyModel?: string | undefined;
|
|
15
|
-
providerConfigs?: ProviderConfigs | undefined;
|
|
16
|
-
} | undefined;
|
|
17
|
-
preferredBrand?: string | undefined;
|
|
18
|
-
toolBrand?: string | undefined;
|
|
19
|
-
brandPriorityStrategy?: BrandPriorityStrategy | undefined;
|
|
20
|
-
conversationHistory?: string[] | undefined;
|
|
21
|
-
candidateMessage: string;
|
|
22
|
-
configData: ZhipinData;
|
|
23
|
-
replyPolicy?: ReplyPolicyConfig | undefined;
|
|
24
|
-
candidateInfo?: CandidateInfo | undefined;
|
|
25
|
-
defaultWechatId?: string | undefined;
|
|
26
|
-
industryVoiceId?: string | undefined;
|
|
27
|
-
channelType?: ChannelType | undefined;
|
|
28
|
-
turnIndex?: number | undefined;
|
|
29
|
-
ageEligibilitySources?: AgeEligibilitySource[] | undefined;
|
|
30
|
-
}
|
|
31
|
-
export interface SmartReplyDebugInfo {
|
|
32
|
-
relevantStores: StoreWithDistance[];
|
|
33
|
-
storeCount: number;
|
|
34
|
-
detailLevel: EffectiveDisclosureMode;
|
|
35
|
-
resolvedBrand: string;
|
|
36
|
-
turnPlan: TurnPlan;
|
|
37
|
-
turnIndex: number;
|
|
38
|
-
effectiveDisclosureMode: EffectiveDisclosureMode;
|
|
39
|
-
primaryNeed: ReplyNeed;
|
|
40
|
-
replyGateRewritten: boolean;
|
|
41
|
-
gateViolations: ReplyGateViolationCode[];
|
|
42
|
-
aliasLookupError?: string | undefined;
|
|
43
|
-
gateStatus: AgeEligibilityStatus;
|
|
44
|
-
appliedStrategy: AgeEligibilityAppliedStrategy;
|
|
45
|
-
ageRangeSummary: AgeEligibilitySummary;
|
|
46
|
-
}
|
|
47
|
-
export interface SmartReplyAgentResult {
|
|
48
|
-
turnPlan: TurnPlan;
|
|
49
|
-
suggestedReply: string;
|
|
50
|
-
confidence: number;
|
|
51
|
-
shouldExchangeWechat?: boolean | undefined;
|
|
52
|
-
factGateRewritten: boolean;
|
|
53
|
-
replyGateRewritten: boolean;
|
|
54
|
-
gateViolations: ReplyGateViolationCode[];
|
|
55
|
-
contextInfo?: string | undefined;
|
|
56
|
-
debugInfo?: SmartReplyDebugInfo | undefined;
|
|
57
|
-
usage: SafeGenerateTextUsage | undefined;
|
|
58
|
-
latencyMs?: number | undefined;
|
|
59
|
-
error?: AppError | undefined;
|
|
60
|
-
}
|
|
61
|
-
export declare function hasUnsupportedFactClaims(text: string, contextInfo: string, allowedNeeds: ReplyNeed[]): boolean;
|
|
62
|
-
export declare function resolveTurnIndex(conversationHistory: string[], explicitTurnIndex?: number | undefined): number;
|
|
63
|
-
export declare function resolveEffectiveDisclosureMode(turnIndex: number, stage: FunnelStage): EffectiveDisclosureMode;
|
|
64
|
-
export declare function generateSmartReply(options: SmartReplyAgentOptions): Promise<SmartReplyAgentResult>;
|
package/dist/pipeline.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public pipeline API — 供外部项目直接 import 使用。
|
|
3
|
-
*
|
|
4
|
-
* @example
|
|
5
|
-
* ```ts
|
|
6
|
-
* import { generateSmartReply } from "@roll-agent/smart-reply-agent/pipeline";
|
|
7
|
-
* import type { SmartReplyAgentOptions, SmartReplyAgentResult } from "@roll-agent/smart-reply-agent/pipeline";
|
|
8
|
-
* ```
|
|
9
|
-
*/
|
|
10
|
-
export { generateSmartReply } from "./pipeline/smart-reply.ts";
|
|
11
|
-
export type { SmartReplyAgentOptions, SmartReplyAgentResult, SmartReplyDebugInfo, } from "./pipeline/smart-reply.ts";
|
|
12
|
-
export type { ZhipinData, CandidateInfo } from "./types/zhipin.ts";
|
|
13
|
-
export type { ReplyPolicyConfig, ChannelType, FunnelStage, TurnPlan, ReplyNeed, EffectiveDisclosureMode, } from "./types/reply-policy.ts";
|
|
14
|
-
export type { BrandPriorityStrategy } from "./types/config.ts";
|
|
15
|
-
export type { ProviderConfigs } from "./types/classification.ts";
|
|
16
|
-
export type { ReplyGateViolationCode } from "./pipeline/reply-gate.ts";
|
|
17
|
-
export type { SafeGenerateTextUsage } from "./ai/structured-output.ts";
|
|
18
|
-
export { collectAgeEvidenceFromSources, createConfigDataAgeSource, createDefaultAgeEligibilitySources, createDulidayApiAgeSource, evaluateAgeEligibility, } from "./pipeline/age-eligibility.ts";
|
|
19
|
-
export type { AgeEvidence, AgeEvidenceCollection, AgeEvidenceSourceResult, AgeEligibilityQuery, AgeEligibilityResult, AgeEligibilitySource, AgeEligibilityStatus, AgeEligibilityAppliedStrategy, AgeEligibilitySummary, } from "./pipeline/age-eligibility.ts";
|
|
20
|
-
export type { StoreWithDistance } from "./types/geocoding.ts";
|
|
21
|
-
export type { AppError } from "./errors/index.ts";
|
package/dist/pipeline.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createAnthropic as e}from"@ai-sdk/anthropic";import{createAlibaba as t}from"@ai-sdk/alibaba";import{createProviderRegistry as n}from"ai";import{createOpenAICompatible as r}from"@ai-sdk/openai-compatible";import{createDeepSeek as o}from"@ai-sdk/deepseek";import{createGoogleGenerativeAI as s}from"@ai-sdk/google";import{createOpenAI as a}from"@ai-sdk/openai";var i=!1;function c(e){i=e}function u(...e){i||console.error(...e)}var l=process.env.SMART_REPLY_PROXY_BASE_URL,d="https://apic1.ohmycdn.com/v1",m=l||d,p={anthropic:process.env.ANTHROPIC_BASE_URL||m,openai:process.env.OPENAI_BASE_URL||m,ohmygpt:process.env.OHMYGPT_BASE_URL||m,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"},f={anthropic:{name:"Anthropic",baseURL:p.anthropic,description:"Anthropic Claude"},openai:{name:"OpenAI",baseURL:p.openai,description:"OpenAI GPT"},ohmygpt:{name:"OhMyGPT",baseURL:p.ohmygpt,description:"OhMyGPT"},moonshotai:{name:"MoonshotAI",baseURL:p.moonshotai,description:"MoonshotAI"},deepseek:{name:"DeepSeek",baseURL:p.deepseek,description:"DeepSeek"},qwen:{name:"Qwen",baseURL:p.qwen,description:"Qwen"},google:{name:"Google",baseURL:p.google,description:"Google Gemini"}},g={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 y(){return process.env.ANTHROPIC_API_KEY||process.env.OPENAI_API_KEY||""}function h(e){const t=a({apiKey:e.apiKey||"",...void 0!==e.baseURL?{baseURL:e.baseURL}:{}});return new Proxy(t,{get(e,n){if("languageModel"===n)return e=>t.chat(e);if("chat"===n||"completion"===n)return t[n];if("embeddingModel"===n||"imageModel"===n){return t[n]||void 0}return t[n]}})}function E(a){const i=y();return n({anthropic:e({apiKey:i,baseURL:a.anthropic?.baseURL||p.anthropic}),openai:h({apiKey:i,baseURL:a.openai?.baseURL||p.openai}),ohmygpt:r({name:"ohmygpt",baseURL:a.ohmygpt?.baseURL||p.ohmygpt,apiKey:i}),moonshotai:r({name:"moonshotai",baseURL:a.moonshotai?.baseURL||p.moonshotai,apiKey:process.env.MOONSHOT_API_KEY||""}),deepseek:o({baseURL:a.deepseek?.baseURL||p.deepseek,apiKey:process.env.DEEPSEEK_API_KEY||""}),google:s({apiKey:process.env.GEMINI_API_KEY||"",baseURL:a.google?.baseURL||p.google}),qwen:t({apiKey:process.env.DASHSCOPE_API_KEY||process.env.ALIBABA_API_KEY||"",baseURL:a.qwen?.baseURL||p.qwen})},{separator:"/"})}var _=null,N=null;function I(e){const t=JSON.stringify(e);return _&&N===t||(_=E(e),N=t,u("[DYNAMIC REGISTRY] 创建新的动态registry,配置哈希:",t.substring(0,16)+"...")),_}function A(e){return e.brands.flatMap(e=>e.stores)}function S(e){return e.brands.map(e=>e.name)}function T(e,t){if(t)return e.brands.find(e=>e.name===t)}function b(e){if(e.meta.defaultBrandId){const t=e.brands.find(t=>t.id===e.meta.defaultBrandId);if(t)return t}return e.brands[0]}function O(e){return b(e)?.name??""}function L(e,t){const n=t?T(e,t)?.stores??[]:A(e);return n.find(e=>"string"==typeof e.city&&e.city.trim().length>0)?.city}import{z as R}from"zod";var M=6e4,v=2e4,w=null,D=null;function U(){const e=process.env.DULIDAY_JOB_LIST_URL;return"string"==typeof e&&e.trim().length>0?e:void 0}function $(){const e=process.env.DULIDAY_TOKEN;return"string"==typeof e&&e.trim().length>0?e:void 0}function C(e){return(e??"").trim()}function k(e){const t=C(e);if(!t)return[];const n=new Set([t]);return t.endsWith("市")?n.add(t.slice(0,-1)):n.add(`${t}市`),Array.from(n).filter(Boolean)}function x(e,t){const n=C(e);if(!n)return[];const r=new Set([n]),o=k(t);for(const e of o)if(n.startsWith(e)){const t=n.slice(e.length).trim();t&&r.add(t)}return Array.from(r).filter(Boolean)}var F=R.object({data:R.object({result:R.array(R.unknown()).optional(),list:R.array(R.unknown()).optional(),total:R.number().optional()}).nullable().optional(),result:R.array(R.unknown()).optional()});function P(e){const t=F.safeParse(e);if(!t.success)return{items:[],total:0};const n=t.data,r=n.data?.result??n.data?.list??(Array.isArray(n.result)?n.result:[]),o=n.data?.total??(Array.isArray(r)?r.length:0);return{items:Array.isArray(r)?r:[],total:"number"==typeof o?o:0}}var B={includeBasicInfo:!0,includeHiringRequirement:!0};async function j(e,t,n,r,o){const s="test"!==process.env.NODE_ENV,a=x(o?.brandAlias,o?.cityName),i=k(o?.cityName),c=o?.include??B,u=JSON.stringify({token:e,brandCandidates:a,cityCandidates:i,pageNum:n,includeOpts:c}),l=Date.now();if(s&&w&&w.cacheKey===u&&l-w.fetchedAt<M)return w.payload;if(s&&D?.cacheKey===u)return D.promise;const d=(async()=>{const o=new AbortController,s=setTimeout(()=>o.abort(),v),l={};a.length>0&&(l.brandAliasList=a),i.length>0&&(l.cityNameList=i);const d={pageNum:n,pageSize:r,queryParam:l,options:c};try{const n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json","Duliday-Token":e},body:JSON.stringify(d),signal:o.signal});if(!n.ok)throw new Error(`Duliday job list fetch failed: ${n.status}`);const r=await n.json();return w={cacheKey:u,payload:r,fetchedAt:Date.now()},r}finally{clearTimeout(s),D=null}})();return s&&(D={cacheKey:u,promise:d}),d}import{z as G}from"zod";var K=G.enum(["trust_building","private_channel","qualify_candidate","job_consultation","interview_scheduling","onboard_followup"]),H=G.enum(["public","private"]),q=G.enum(["minimal","focused"]),V=G.enum(["salary","schedule","location","policy","requirements","availability"]),W={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"]}},Y=G.enum(["stores","location","salary","schedule","policy","availability","requirements","interview","wechat","none"]),z=G.enum(["insurance_promise_risk","age_sensitive","confrontation_emotion","urgency_high","qualification_mismatch"]),Q={stores:["location"],location:["location"],salary:["salary"],schedule:["schedule"],policy:["policy"],availability:["availability"],requirements:["requirements"],interview:[],wechat:[],none:[]},J=G.object({mentionedBrand:G.string().nullable(),city:G.string().nullable(),mentionedLocations:G.array(G.object({location:G.string(),confidence:G.number().min(0).max(1)})).nullable(),mentionedDistricts:G.array(G.object({district:G.string(),confidence:G.number().min(0).max(1)})).max(10).nullable(),specificAge:G.number().nullable(),hasUrgency:G.boolean().nullable(),preferredSchedule:G.string().nullable()}),Z=G.object({stage:K,subGoals:G.array(G.string()).max(2),needs:G.array(Y).max(8),primaryNeed:Y,riskFlags:G.array(z).max(6),confidence:G.number().min(0).max(1),extractedInfo:J,reasoningText:G.string()}),X=G.object({description:G.string().optional(),primaryGoal:G.string(),successCriteria:G.array(G.string()),ctaStrategy:G.preprocess(e=>Array.isArray(e)?e.join("\n"):e,G.string()),disallowedActions:G.array(G.string()).optional()}),ee=G.object({tone:G.string(),warmth:G.string(),humor:G.string(),length:G.enum(["short","medium","long"]),questionStyle:G.string(),empathyStrategy:G.string(),addressStyle:G.string(),professionalIdentity:G.string(),companyBackground:G.string()}),te=G.object({name:G.string(),industryBackground:G.string(),jargon:G.array(G.string()),styleKeywords:G.array(G.string()),tabooPhrases:G.array(G.string()),guidance:G.array(G.string())}),ne=G.object({id:G.string(),rule:G.string(),severity:G.enum(["high","medium","low"])}),re=G.object({rules:G.array(ne)}),oe=G.object({mode:G.enum(["strict","balanced","open"]),verifiableClaimTypes:G.array(G.string()),fallbackBehavior:G.enum(["generic_answer","ask_followup","handoff"]),forbiddenWhenMissingFacts:G.array(G.string())}),se={maxQuestionsByMode:{minimal:1,focused:2},blockedAuditPhrases:["是否满足","是否符合","基本入职要求","先确认资格","年龄是否符合"],blockFirstTurnSpecificFacts:!0},ae=G.object({maxQuestionsByMode:G.object({minimal:G.number().int().min(0),focused:G.number().int().min(0)}),blockedAuditPhrases:G.array(G.string()),blockFirstTurnSpecificFacts:G.boolean()}),ie=G.object({enabled:G.boolean().default(!0),revealRange:G.boolean().default(!1),failStrategy:G.string().default("礼貌说明不匹配,避免承诺"),unknownStrategy:G.string().default("先核实年龄或资格条件"),passStrategy:G.string().default("确认匹配后推进下一步"),allowRedirect:G.boolean().default(!0),redirectPriority:G.enum(["low","medium","high"]).default("medium")}),ce=G.object({age:ie.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"}}),ue=G.object({trust_building:X,private_channel:X.optional(),qualify_candidate:X,job_consultation:X,interview_scheduling:X,onboard_followup:X}).transform(e=>({...e,private_channel:e.private_channel??e.trust_building})),le=G.object({stageGoals:ue,persona:ee,industryVoices:G.record(G.string(),te),defaultIndustryVoiceId:G.string(),hardConstraints:re,factGate:oe,qualificationPolicy:ce,outputGuards:ae.default(se)});import{z as de}from"zod";import{setTimeout as me,clearTimeout as pe}from"node:timers";import{performance as fe}from"node:perf_hooks";import{asSchema as ge,generateText as ye,jsonSchema as he,NoObjectGeneratedError as Ee,Output as _e}from"ai";import"zod";var Ne={CONFIG:"CONFIG",AUTH:"AUTH",NETWORK:"NETWORK",LLM:"LLM",VALIDATION:"VALIDATION",BUSINESS:"BUSINESS",SYSTEM:"SYSTEM"},Ie={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"},Ae={[Ie.LLM_UNAUTHORIZED]:Ne.LLM,[Ie.LLM_MODEL_NOT_FOUND]:Ne.LLM,[Ie.LLM_RATE_LIMITED]:Ne.LLM,[Ie.LLM_TIMEOUT]:Ne.LLM,[Ie.LLM_GENERATION_FAILED]:Ne.LLM,[Ie.LLM_RESPONSE_PARSE_ERROR]:Ne.LLM,[Ie.CONFIG_NOT_FOUND]:Ne.CONFIG,[Ie.CONFIG_INVALID]:Ne.CONFIG,[Ie.CONFIG_MISSING_FIELD]:Ne.CONFIG,[Ie.CONFIG_LOAD_FAILED]:Ne.CONFIG,[Ie.NETWORK_TIMEOUT]:Ne.NETWORK,[Ie.NETWORK_CONNECTION_FAILED]:Ne.NETWORK,[Ie.NETWORK_HTTP_ERROR]:Ne.NETWORK,[Ie.NETWORK_DNS_FAILED]:Ne.NETWORK,[Ie.AUTH_UNAUTHORIZED]:Ne.AUTH,[Ie.AUTH_FORBIDDEN]:Ne.AUTH,[Ie.AUTH_TOKEN_EXPIRED]:Ne.AUTH,[Ie.AUTH_TOKEN_INVALID]:Ne.AUTH,[Ie.VALIDATION_INVALID_INPUT]:Ne.VALIDATION,[Ie.VALIDATION_MISSING_REQUIRED]:Ne.VALIDATION,[Ie.VALIDATION_FORMAT_ERROR]:Ne.VALIDATION,[Ie.VALIDATION_SCHEMA_ERROR]:Ne.VALIDATION,[Ie.BUSINESS_RULE_VIOLATION]:Ne.BUSINESS,[Ie.BUSINESS_RESOURCE_NOT_FOUND]:Ne.BUSINESS,[Ie.BUSINESS_RESOURCE_EXISTS]:Ne.BUSINESS,[Ie.BUSINESS_OPERATION_NOT_ALLOWED]:Ne.BUSINESS,[Ie.SYSTEM_INTERNAL]:Ne.SYSTEM,[Ie.SYSTEM_DEPENDENCY_FAILED]:Ne.SYSTEM,[Ie.SYSTEM_RESOURCE_UNAVAILABLE]:Ne.SYSTEM,[Ie.SYSTEM_UNKNOWN]:Ne.SYSTEM},Se={[Ie.LLM_UNAUTHORIZED]:"AI 服务认证失败,请检查配置",[Ie.LLM_MODEL_NOT_FOUND]:"所选模型暂时不可用,请尝试其他模型",[Ie.LLM_RATE_LIMITED]:"请求过于频繁,请稍后重试",[Ie.LLM_TIMEOUT]:"AI 响应超时,请稍后重试",[Ie.LLM_GENERATION_FAILED]:"内容生成失败,请稍后重试",[Ie.LLM_RESPONSE_PARSE_ERROR]:"AI 响应格式异常,请重试",[Ie.CONFIG_NOT_FOUND]:"配置数据未找到,请先进行初始化",[Ie.CONFIG_INVALID]:"配置格式无效,请检查配置",[Ie.CONFIG_MISSING_FIELD]:"配置缺少必需字段",[Ie.CONFIG_LOAD_FAILED]:"配置加载失败,请重试",[Ie.NETWORK_TIMEOUT]:"网络请求超时,请检查网络连接",[Ie.NETWORK_CONNECTION_FAILED]:"网络连接失败,请检查网络",[Ie.NETWORK_HTTP_ERROR]:"服务器返回错误,请稍后重试",[Ie.NETWORK_DNS_FAILED]:"域名解析失败,请检查网络",[Ie.AUTH_UNAUTHORIZED]:"请先登录",[Ie.AUTH_FORBIDDEN]:"您没有权限执行此操作",[Ie.AUTH_TOKEN_EXPIRED]:"登录已过期,请重新登录",[Ie.AUTH_TOKEN_INVALID]:"认证信息无效,请重新登录",[Ie.VALIDATION_INVALID_INPUT]:"输入参数无效",[Ie.VALIDATION_MISSING_REQUIRED]:"缺少必需参数",[Ie.VALIDATION_FORMAT_ERROR]:"数据格式错误",[Ie.VALIDATION_SCHEMA_ERROR]:"数据验证失败",[Ie.BUSINESS_RULE_VIOLATION]:"操作违反业务规则",[Ie.BUSINESS_RESOURCE_NOT_FOUND]:"请求的资源不存在",[Ie.BUSINESS_RESOURCE_EXISTS]:"资源已存在",[Ie.BUSINESS_OPERATION_NOT_ALLOWED]:"当前操作不被允许",[Ie.SYSTEM_INTERNAL]:"系统内部错误,请稍后重试",[Ie.SYSTEM_DEPENDENCY_FAILED]:"依赖服务异常,请稍后重试",[Ie.SYSTEM_RESOURCE_UNAVAILABLE]:"系统资源不可用,请稍后重试",[Ie.SYSTEM_UNKNOWN]:"发生未知错误,请稍后重试"};function Te(e){return Ae[e]}function be(e){return Se[e]}var Oe=class _AppError extends Error{code;category;userMessage;details;cause;timestamp;constructor(e){super(e.message),this.name="AppError",this.code=e.code,this.category=Te(e.code),this.userMessage=e.userMessage||be(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 t=this.cause;for(;t;)e.push(t),t=t instanceof _AppError?t.cause:void 0;return e}getRootCause(){const e=this.getErrorChain();return e[e.length-1]}hasErrorCode(e){return this.getErrorChain().some(t=>t instanceof _AppError&&t.code===e)}hasErrorCategory(e){return this.getErrorChain().some(t=>t instanceof _AppError&&t.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 Le(e){return e instanceof Oe}function Re(e,t,n){const r=n?.model?` (model: ${n.model})`:"",o=n?.provider?` [${n.provider}]`:"",s={[Ie.LLM_UNAUTHORIZED]:`LLM API authentication failed${o}${r}`,[Ie.LLM_MODEL_NOT_FOUND]:`Model not found or unavailable${r}${o}`,[Ie.LLM_RATE_LIMITED]:`LLM API rate limited${o}`,[Ie.LLM_TIMEOUT]:`LLM API request timeout${o}${r}`,[Ie.LLM_GENERATION_FAILED]:`LLM generation failed${o}${r}`,[Ie.LLM_RESPONSE_PARSE_ERROR]:`Failed to parse LLM response${o}`};return new Oe({code:e,message:s[e]||`LLM error: ${t.message}`,cause:t,details:n})}function Me(e,t,n){const r=n?.url?` (${n.url})`:"",o=n?.statusCode?` [${n.statusCode}]`:"",s={[Ie.NETWORK_TIMEOUT]:`Network request timeout${r}`,[Ie.NETWORK_CONNECTION_FAILED]:`Failed to connect${r}`,[Ie.NETWORK_HTTP_ERROR]:`HTTP error${o}${r}`,[Ie.NETWORK_DNS_FAILED]:`DNS resolution failed${r}`};return new Oe({code:e,message:s[e]||`Network error: ${t.message}`,cause:t,details:n})}function ve(e,t,n){const r=n.isMarkdownFormat?" (detected markdown format)":"",o=n.schemaName?` for schema "${n.schemaName}"`:"";return new Oe({code:e,message:`Failed to parse structured output${o}${r}`,cause:t,details:{rawText:n.rawText,isMarkdownFormat:n.isMarkdownFormat,parseErrorMessage:n.parseErrorMessage,model:n.model,provider:n.provider,schemaName:n.schemaName,usage:n.usage}})}import{NoObjectGeneratedError as we}from"ai";function De(e){if(!e||"object"!=typeof e)return null;const t=e;if(!("AI_APICallError"===t.name||"APICallError"===t.name||"string"==typeof t.url&&"number"==typeof t.statusCode))return null;const n="number"==typeof t.statusCode?t.statusCode:void 0,r="string"==typeof t.responseBody?t.responseBody:void 0,o="string"==typeof t.url?t.url:void 0,s=t.message;let a,i;if(o&&(o.includes("openai.com")?a="openai":o.includes("anthropic.com")?a="anthropic":o.includes("dashscope.aliyuncs.com")?a="qwen":o.includes("openrouter.ai")?a="openrouter":o.includes("deepseek.com")?a="deepseek":o.includes("moonshot.cn")?a="moonshotai":o.includes("googleapis.com")&&(a="google")),r){const e=r.match(/model[`'":\s]+([^`'"}\s,]+)/i);e&&(i=e[1])}return{isAuthError:401===n||403===n,isModelNotFound:r?.includes("model")&&r?.includes("not exist")||r?.includes("not authorized to access this model")||!1,isRateLimited:429===n,isTimeout:408===n||504===n||s?.toLowerCase().includes("timeout")||!1,statusCode:n,provider:a,model:i,originalMessage:s,responseBody:r}}function Ue(e){return[/^```/m,/^#{1,6}\s/m,/^\s*[-*+]\s/m,/^\s*\d+\.\s/m,/\[.+\]\(.+\)/,/^\s*>/m].some(t=>t.test(e))}function $e(e){try{if(void 0===we||"function"!=typeof we.isInstance)return null;if(!we.isInstance(e))return null}catch{return null}const t=e.text,n=!!t&&Ue(t),r=e.response?{id:e.response.id,timestamp:e.response.timestamp,modelId:e.response.modelId}:void 0,o=e.usage??void 0,s={isNoObjectGeneratedError:!0,isMarkdownFormat:n};return void 0!==t&&(s.rawText=t),e.cause instanceof Error&&(s.cause=e.cause),void 0!==r&&(s.response=r),void 0!==o&&(s.usage=o),s}function Ce(e,t=Ie.SYSTEM_UNKNOWN,n){if(Le(e))return n&&n!==e.userMessage?new Oe({code:e.code,message:e.message,userMessage:n,cause:e.cause,details:e.details}):e;const r=ke(e),o=De(e);if(o){const e={model:o.model,provider:o.provider,statusCode:o.statusCode,responseBody:o.responseBody};return o.isModelNotFound?Re(Ie.LLM_MODEL_NOT_FOUND,r,e):o.isAuthError?Re(Ie.LLM_UNAUTHORIZED,r,e):o.isRateLimited?Re(Ie.LLM_RATE_LIMITED,r,e):o.isTimeout?Re(Ie.LLM_TIMEOUT,r,e):Re(Ie.LLM_GENERATION_FAILED,r,e)}const s=$e(e);if(s)return ve(Ie.LLM_RESPONSE_PARSE_ERROR,r,{rawText:s.rawText,isMarkdownFormat:s.isMarkdownFormat,parseErrorMessage:s.cause?.message,usage:s.usage});const a=r.message.toLowerCase();return a.includes("timeout")||a.includes("econnrefused")||a.includes("network")||a.includes("fetch failed")?a.includes("timeout")?Me(Ie.NETWORK_TIMEOUT,r):Me(Ie.NETWORK_CONNECTION_FAILED,r):new Oe({code:t,message:r.message,cause:r})}function ke(e){if(e instanceof Error)return e;if("string"==typeof e)return new Error(e);if("object"==typeof e&&null!==e){const t=e.message||e.error||JSON.stringify(e);return new Error(String(t))}return new Error(String(e))}function xe(e,t){console.error(`[${t.code}] ${e}:`,t.toLogString()),t.cause&&console.error("Original error:",t.cause)}function Fe(e){return"object"==typeof e&&null!==e}function Pe(e,t){t&&Fe(e.details)&&(e.details.schemaName=t)}function Be(e){const t=e.type;return"string"==typeof t?[t]:Array.isArray(t)?t.filter(e=>"string"==typeof e):[]}function je(e,t){let n=null;for(const r of e){const e=t.get(r);if(void 0!==e&&e.size>0){n??=new Set;for(const t of e)n.add(t)}}return n}function Ge(e,t){if(Array.isArray(e))return e.map(e=>Ge(e,t));if(null===e||"object"!=typeof e)return e;const n=e,r=je(Be(n),t),o={};for(const[e,s]of Object.entries(n))null!==r&&r.has(e)||(o[e]=Ge(s,t));return o}function Ke(e){const t=e.unsupportedKeywordsByType;if(void 0===t)return new Map;const n=new Map;for(const[e,r]of Object.entries(t)){if(0===r.length)continue;const t=n.get(e);if(void 0!==t)for(const e of r)t.add(e);else n.set(e,new Set(r))}const r=n.get("number");if(void 0!==r&&r.size>0){const e=n.get("integer");if(void 0!==e)for(const t of r)e.add(t);else n.set("integer",new Set(r))}return n}function He(e,t={}){const n=Ke(t);if(0===n.size)return e;const r=ge(e);return he(async()=>Ge(await r.jsonSchema,n),{validate:e=>({success:!0,value:e})})}async function qe(e){const{model:t,schema:n,outputSchema:r,schemaName:o,system:s,prompt:a,transformOutput:i,onError:c}=e;try{const e=await ye({model:t,...void 0!==s?{system:s}:{},prompt:a,output:_e.object({schema:r??n,...void 0!==o?{name:o}:{}})});if(void 0===r&&void 0===i)return{success:!0,data:e.output,usage:e.usage};const u=void 0!==i?await i(e.output):e.output,l=await n.safeParseAsync(u);if(!l.success){const t=Ce(l.error,Ie.LLM_RESPONSE_PARSE_ERROR);return Pe(t,o),xe(`Structured output validation (${o||"unknown"})`,t),c&&c(t,e.text),{success:!1,error:t,rawText:e.text}}return{success:!0,data:l.data,usage:e.usage}}catch(e){const t=Ce(e,Ie.LLM_RESPONSE_PARSE_ERROR);let n;return Ee.isInstance(e)&&(n=e.text),Pe(t,o),xe(`Structured output generation (${o||"unknown"})`,t),c&&c(t,n),{success:!1,error:t,rawText:n}}}var Ve=3e4,We=2e3;async function Ye(e){const{model:t,system:n,prompt:r,timeoutMs:o=Ve,maxOutputTokens:s=We,context:a="generateText",onError:i}=e,c=fe.now();try{const e=new AbortController,i=me(()=>e.abort(),o),l=await ye({model:t,...void 0!==n?{system:n}:{},prompt:r,maxOutputTokens:s,abortSignal:e.signal});pe(i);const d=Math.round(fe.now()-c),m=l.usage,p=void 0!==m?.inputTokens&&void 0!==m?.outputTokens?m.inputTokens+m.outputTokens:void 0,f={inputTokens:m?.inputTokens,outputTokens:m?.outputTokens,totalTokens:p};return u(`[${a}] 生成成功 | 耗时: ${d}ms | Tokens: ${p??"N/A"} (input: ${f.inputTokens??"?"}, output: ${f.outputTokens??"?"})`),{success:!0,text:l.text,usage:f,latencyMs:d}}catch(e){const t=Math.round(fe.now()-c),n=e instanceof Error&&("AbortError"===e.name||e.message.includes("aborted")),r=Ce(e,n?Ie.LLM_TIMEOUT:Ie.LLM_GENERATION_FAILED);return Fe(r.details)&&(r.details.context=a,r.details.latencyMs=t),xe(`${a} (${t}ms)`,r),i&&i(r),{success:!1,error:r}}}import{z as ze}from"zod";var Qe=ze.object({name:ze.string(),baseURL:ze.string(),description:ze.string()}),Je=ze.record(ze.string(),Qe),Ze=ze.object({chatModel:ze.string().optional(),classifyModel:ze.string().optional(),replyModel:ze.string().optional(),providerConfigs:Je.optional()}),Xe=ze.object({city:ze.string().optional(),defaultBrand:ze.string(),availableBrands:ze.array(ze.string()),storeCount:ze.number()}),et=ze.object({modelConfig:Ze,candidateMessage:ze.string(),conversationHistory:ze.array(ze.string()).default([]),brandData:Xe.optional(),channelType:H.optional()});function tt(e){const t=H.safeParse(e);return t.success?t.data:"public"}function nt(e="public"){const t=tt(e),n=K.options.filter(e=>W[e].applicableChannels.includes(t));return n.length>0?n:[...K.options]}function rt(e){return de.object({stage:de.enum(e),subGoals:Z.shape.subGoals,needs:Z.shape.needs,primaryNeed:Z.shape.primaryNeed,riskFlags:Z.shape.riskFlags,confidence:Z.shape.confidence,extractedInfo:Z.shape.extractedInfo,reasoningText:Z.shape.reasoningText})}var ot={subGoals:2,needs:8,riskFlags:6,mentionedDistricts:10};function st(e){return e.startsWith("anthropic/")}function at(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function it(e){if(!at(e))return e;const t={...e};if(Array.isArray(t.subGoals)&&(t.subGoals=t.subGoals.slice(0,ot.subGoals)),Array.isArray(t.needs)&&(t.needs=t.needs.slice(0,ot.needs)),Array.isArray(t.riskFlags)&&(t.riskFlags=t.riskFlags.slice(0,ot.riskFlags)),at(t.extractedInfo)){const e={...t.extractedInfo};Array.isArray(e.mentionedDistricts)&&(e.mentionedDistricts=e.mentionedDistricts.slice(0,ot.mentionedDistricts)),t.extractedInfo=e}return t}var ct=[{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]}],ut=["salary","schedule","location","stores","policy","requirements","availability","interview","wechat","none"];function lt(e){const t=new Set;for(const n of ct)n.patterns.some(t=>t.test(e))&&t.add(n.need);return 0===t.size?t.add("none"):t.delete("none"),t}function dt(e,t){return lt(`${t.slice(-4).join(" ")} ${e}`)}function mt(e){return lt(e)}function pt(e,t,n,r=1){const o=new Set(t);o.size>1&&o.has("none")&&o.delete("none");const s=mt(n);s.delete("none");const a=[];"none"!==e&&o.has(e)&&a.push(e);for(const t of ut){if(a.length>=r)break;"none"!==t&&t!==e&&(s.has(t)&&o.has(t)&&a.push(t))}return a.length>0?a:"none"===e?["none"]:o.has(e)?[e]:["none"]}function ft(e,t,n){const r=new Set(t);if(r.size>1&&r.has("none")&&r.delete("none"),e&&r.has(e))return e;const o=mt(n);o.delete("none");for(const e of ut)if(o.has(e)&&r.has(e))return e;for(const e of ut)if(r.has(e))return e;return"none"}function gt(e,t,n){const r=new Set([...e.needs,...Array.from(t)]);return r.size>1&&r.has("none")&&r.delete("none"),{...e,subGoals:e.subGoals.slice(0,2),needs:Array.from(r),primaryNeed:ft(e.primaryNeed,r,n),confidence:Number.isFinite(e.confidence)?Math.max(0,Math.min(1,e.confidence)):.5}}function yt(e,t,n,r="public",o,s){const a=["你是招聘对话回合规划器,不直接回复候选人。","你只输出结构化规划结果,用于后续回复生成。","规划目标:确定阶段目标(stage)、子目标(subGoals)、事实需求(needs)、主回答轴(primaryNeed)、风险标记(riskFlags)。"].join("\n"),i=tt(r);return{system:a,prompt:["[阶段枚举与定义]",...nt(i).map(e=>{const t=W[e];return`- ${e}: ${o?.stageGoals[e]?.description||t.description} (转入条件: ${t.transitionSignal})`}),"","[needs枚举]","private"===i?"- 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 降低,不要臆断。","- 根据转入条件判断阶段转化,不要停留在不匹配的阶段。",...s&&s.length>0?[`- 候选人资料中已有:${s.join("、")}。不要生成追问这些字段的 subGoal。`]:[],"","[品牌数据]",JSON.stringify(n||{}),"","[历史对话]",t.slice(-8).join("\n")||"无","","[候选人消息]",e].join("\n")}}async function ht(e,t){const{providerConfigs:n=f,modelConfig:r,conversationHistory:o=[],brandData:s,channelType:a,replyPolicy:i,knownCandidateFields:c}=t,u=I(n),l=r?.classifyModel||g.classifyModel,d=tt(a),m=rt(nt(d)),p=st(l),y=yt(e,o,s,d,i,c),h=await qe({model:u.languageModel(l),schema:m,...p?{outputSchema:He(m,{unsupportedKeywordsByType:{array:["maxItems","minItems"],number:["maximum","minimum","exclusiveMaximum","exclusiveMinimum"]}}),transformOutput:it}:{},schemaName:"TurnPlanningOutput",system:y.system,prompt:y.prompt}),E=dt(e,o),_=ft(void 0,E,e);return h.success?gt(h.data,E,e):{stage:"trust_building",subGoals:["保持对话并澄清需求"],needs:Array.from(E),primaryNeed:_,riskFlags:[],confidence:.35,extractedInfo:{mentionedBrand:null,city:s?.city||null,mentionedLocations:null,mentionedDistricts:null,specificAge:null,hasUrgency:null,preferredSchedule:null},reasoningText:"规划模型失败,使用规则降级策略"}}import{z as Et}from"zod";var _t=Et.object({id:Et.number(),name:Et.string(),aliases:Et.array(Et.string()),projectIdList:Et.array(Et.number())}),Nt=Et.object({code:Et.number(),message:Et.string().optional(),data:Et.object({result:Et.array(_t),total:Et.number()})}),It=3e5,At=null;function St(){return null!==At&&Date.now()-At.timestamp<It}var Tt=3e4;function bt(){const e=process.env.DULIDAY_BRAND_LIST_URL;return"string"==typeof e&&e.trim().length>0?e:void 0}async function Ot(e){const t=e||process.env.DULIDAY_TOKEN,n=bt();if(!t)throw new Oe({code:Ie.CONFIG_MISSING_FIELD,message:"DULIDAY_TOKEN 未配置,无法获取品牌别名数据",userMessage:"品牌别名数据加载失败:缺少 Duliday Token 配置"});if(!n)throw new Oe({code:Ie.CONFIG_MISSING_FIELD,message:"DULIDAY_BRAND_LIST_URL 未配置,无法获取品牌别名数据",userMessage:"品牌别名数据加载失败:缺少 Duliday 品牌接口配置"});const r=new AbortController,o=setTimeout(()=>r.abort(),Tt);try{const e=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json","Duliday-Token":t},body:JSON.stringify({pageNum:1,pageSize:1e3}),signal:r.signal});if(!e.ok)throw new Oe({code:Ie.NETWORK_HTTP_ERROR,message:`Duliday 品牌列表 API 返回 HTTP ${e.status}: ${e.statusText}`,userMessage:`品牌别名数据加载失败:服务端返回 ${e.status}`});const o=await e.json(),s=Nt.safeParse(o);if(!s.success)throw new Oe({code:Ie.VALIDATION_SCHEMA_ERROR,message:`Duliday 品牌列表响应格式校验失败: ${s.error.message}`,userMessage:"品牌别名数据加载失败:响应格式异常"});return s.data.data.result}catch(e){if(e instanceof Oe)throw e;if(e instanceof Error&&"AbortError"===e.name)throw new Oe({code:Ie.NETWORK_TIMEOUT,message:`Duliday 品牌列表 API 请求超时 (${Tt}ms)`,userMessage:"品牌别名数据加载超时,请稍后重试",cause:e});throw new Oe({code:Ie.SYSTEM_DEPENDENCY_FAILED,message:`获取品牌别名数据失败: ${e instanceof Error?e.message:String(e)}`,userMessage:"品牌别名数据加载失败,请检查网络连接",...e instanceof Error?{cause:e}:{}})}finally{clearTimeout(o)}}function Lt(e,t,n){const r={},o=new Map,s=e=>e.trim(),a=(e,t)=>{const n=s(e).toLowerCase().replace(/[\s._-]+/g,"");if(!n)return;const r=o.get(n);(!r||t.length>r.length)&&o.set(n,t)},i=[...e].sort((e,t)=>t.name.length-e.name.length);for(const e of i){const t=s(e.name);if(!t)continue;const o=Array.from(new Set([t,...e.aliases.map(s).filter(Boolean)].filter(e=>e!==t)));o.unshift(t),r[t]=o;for(const e of o)a(e,t);if(n&&e.projectIdList.length>0)for(const s of e.projectIdList){const e=n[String(s)];if(!e||e===t)continue;if(!e.includes(t))continue;const i=e.replace(t,"");if(!i)continue;const c=[e];for(const e of o)e!==t&&c.push(`${i}${e}`);if(r[e]){const t=new Set(r[e]);for(const n of c)t.has(n)||r[e].push(n)}else r[e]=c;for(const t of c)a(t,e)}}for(const e of t)r[e]||(r[e]=[e],a(e,e));return{dictionary:r,aliasMap:o}}async function Rt(e){if(St())return;const t=await Ot(e),n=new Set,{dictionary:r,aliasMap:o}=Lt(t,n);At={aliasMap:o,dictionary:r,timestamp:Date.now()}}async function Mt(e){return await Rt(e),At.aliasMap}function vt(e){const{base:t,unit:n,range:r,memo:o}=e,s=o?.replace(/\n/g," ").trim()??"";if(null==t)return e.scenarioSummary&&s?`${s}(${e.scenarioSummary})`:e.scenarioSummary?e.scenarioSummary:s;let a="";return t<10&&o?a=`${t}${n??""}(${s})`:(a=`${t}${n??""}`,r&&r!==`${t}-${t}`&&r!==`${t}元-${t}元`&&(a+=`,范围${r}`),s&&s.length<50&&(a+=`(${s})`)),e.scenarioSummary&&(a+=`(${e.scenarioSummary})`),a}function wt(e,t,n){if(!e)return null;const r=e=>e.toLowerCase().replace(/[\s._-]+/g,"");if(n){const o=n.get(r(e))||n.get(e.toLowerCase());if(o&&t.includes(o))return o}const o=e.toLowerCase(),s=r(e),a=t.find(e=>e.toLowerCase()===o);if(a)return a;const i=t.find(e=>r(e)===s);if(i)return i;const c=t.filter(e=>{const t=e.toLowerCase();if(t.includes(o)||o.includes(t))return!0;const n=r(e);return n.includes(s)||s.includes(n)});if(c.length>0)return c.sort((e,t)=>t.length-e.length)[0]??null;if(o.includes("山姆")||o.includes("sam")){const e=t.find(e=>{const t=e.toLowerCase();return t.includes("山姆")||t.includes("sam")});if(e)return e}return null}function Dt(e){const{uiSelectedBrand:t,configDefaultBrand:n,conversationBrand:r,availableBrands:o,strategy:s="smart",aliasMap:a}=e,i=(e,t)=>{if(e)return wt(e,o,a)??void 0};switch(s){case"user-selected":{const e=i(t);if(e)return{resolvedBrand:e,matchType:e===t?"exact":"fuzzy",source:"ui",reason:"用户选择策略",originalInput:t};const r=i(n);return r?{resolvedBrand:r,matchType:r===n?"exact":"fuzzy",source:"config",reason:"配置默认",originalInput:n}:{resolvedBrand:o[0]??"",matchType:"fallback",source:"default",reason:"系统默认"}}case"conversation-extracted":{const e=i(r);if(e)return{resolvedBrand:e,matchType:e===r?"exact":"fuzzy",source:"conversation",reason:"对话提取",originalInput:r};const s=i(t);if(s)return{resolvedBrand:s,matchType:s===t?"exact":"fuzzy",source:"ui",reason:"UI选择",originalInput:t};const a=i(n);return a?{resolvedBrand:a,matchType:a===n?"exact":"fuzzy",source:"config",reason:"配置默认",originalInput:n}:{resolvedBrand:o[0]??"",matchType:"fallback",source:"default",reason:"系统默认"}}default:{const e=i(r),s=i(t);if(e)return{resolvedBrand:e,matchType:e===r?"exact":"fuzzy",source:"conversation",reason:"智能策略: 对话提取",originalInput:r};if(s)return{resolvedBrand:s,matchType:s===t?"exact":"fuzzy",source:"ui",reason:"智能策略: UI选择",originalInput:t};const a=i(n);return a?{resolvedBrand:a,matchType:a===n?"exact":"fuzzy",source:"config",reason:"智能策略: 配置默认",originalInput:n}:{resolvedBrand:o[0]??"",matchType:"fallback",source:"default",reason:"智能策略: 系统默认"}}}}function Ut(e,t){const{mentionedLocations:n,mentionedDistricts:r}=t;return e.map(e=>{let t=0,o=0,s=0,a=0;if(n&&n.length>0){const r=n.find(t=>e.name.includes(t.location)||e.location.includes(t.location)||(e.subarea??"").includes(t.location));r&&(t=40*r.confidence)}if(r&&r.length>0){const t=r.find(t=>(e.district??"").includes(t.district)||(e.subarea??"").includes(t.district));t&&(o=30*t.confidence)}const i=new Set(e.positions.map(e=>e.name));s=Math.min(5*i.size,20);const c=e.positions.filter(e=>e.availableSlots?.some(e=>e.isAvailable));return a=Math.min(2*c.length,10),{store:e,score:t+o+s+a,breakdown:{locationMatch:t,districtMatch:o,positionDiversity:s,availability:a}}}).sort((e,t)=>t.score-e.score).map(e=>({store:e.store,distance:void 0}))}function $t(e){return Q[e].length>0}function Ct(e,t){return e.has(t)}function kt(e,t,n){return"minimal"===t||(1===e||"trust_building"===n||"private_channel"===n)}async function xt(e,t,n,r,o,s,a,i,c=1,l="minimal",d=[t.primaryNeed]){const m=t.extractedInfo,p=t.primaryNeed,f=d.length>0?Array.from(new Set(d.filter(e=>"none"!==e))):"none"===p?[]:[p],g=new Set(f.flatMap(e=>Q[e])),y=kt(c,l,t.stage),h=!y&&$t(p);let E,_;try{E=await Mt()}catch(e){const t="object"==typeof e&&null!==e&&"userMessage"in e&&"string"==typeof e.userMessage?e.userMessage:e instanceof Error?e.message:String(e);_=t,u(`[buildContextInfoByNeeds] 品牌别名服务不可用,回退 fuzzy 解析: ${t}`)}const N=Dt({uiSelectedBrand:n,configDefaultBrand:O(e),conversationBrand:r||void 0,availableBrands:S(e),strategy:o||"smart",aliasMap:E}),I=N.resolvedBrand;u(`[品牌解析] 工具传参: ${r??"(未指定)"} → 结果: ${I} (${N.matchType}, ${N.source})`);const A=T(e,I),b=A?.stores??[];let L=b;if(L.length>0){const e=m.mentionedLocations||[];if(e.length>0){const t=e[0]?.location?.trim();if(t){const e=L.filter(e=>e.name.includes(t)||e.location.includes(t)||(e.district??"").includes(t)||(e.subarea??"").includes(t));e.length>0&&(L=e)}}const t=m.mentionedDistricts||[];if(t.length>0){const e=L.filter(e=>t.some(t=>(e.district??"").includes(t.district)||(e.subarea??"").includes(t.district)));e.length>0&&(L=e)}if(L.length===b.length&&s?.jobAddress&&Ct(g,"location")){const e=L.filter(e=>e.name.includes(s.jobAddress||"")||e.location.includes(s.jobAddress||"")||(e.district??"").includes(s.jobAddress||"")||(e.subarea??"").includes(s.jobAddress||""));e.length>0&&(L=e)}}let R=[];L.length>0&&(R=Ut(L,m));const M=h?Math.min(1,R.length):0,v=h?"focused":"minimal";let w=`阶段目标:${t.stage}\n默认推荐品牌:${I}\n`;if(_&&(w+=`系统状态:品牌别名服务暂不可用,已回退为规则匹配(${_})。\n`),a){const e=a.stageGoals[t.stage],n=i||a.defaultIndustryVoiceId,r=a.industryVoices[n];w+=`策略目标:${e.primaryGoal}\n`,w+=`推进方式:${e.ctaStrategy}\n`,w+=`主回答轴:${p}\n`,r&&(w+=`行业指纹:${r.name} | 风格:${r.styleKeywords.join("、")}\n`),w+=`红线:${a.hardConstraints.rules.map(e=>e.rule).join(";")}\n`}return h?0===M?w+="暂无可用的门店事实信息,请使用泛化回答,避免任何具体承诺。\n":(w+="匹配到的门店信息:\n",R.slice(0,M).forEach(({store:e})=>{const t=Ct(g,"location"),n=Array.from(g).some(e=>"location"!==e),r=[e.district,e.subarea].filter(e=>Boolean(e)).join("");w+=t?r?`• ${e.name}(${r}):${e.location}\n`:`• ${e.name}:${e.location}\n`:`• ${e.name}\n`,n&&e.positions.slice(0,3).forEach(e=>{if(w+=` 职位:${e.name}\n`,Ct(g,"salary")){const t=vt(e.salary);t&&(w+=` 薪资:${t}\n`)}if(Ct(g,"schedule")){if(e.laborForm){const t=[e.laborForm];e.employmentForm&&"长期用工"!==e.employmentForm&&t.push(e.employmentForm),w+=` 用工形式:${t.join(",")}\n`}if(e.timeSlots.length>0&&(w+=` 时间:${e.timeSlots.slice(0,3).join("、")}\n`),(e.minHoursPerWeek||e.maxHoursPerWeek)&&(w+=` 每周工时:${e.minHoursPerWeek||0}-${e.maxHoursPerWeek||"不限"}小时\n`),null!=e.perMonthMinWorkTime){const t=null!=e.perMonthMinWorkTimeUnit?String(e.perMonthMinWorkTimeUnit):"";w+=` 月最低工时:${e.perMonthMinWorkTime}${t}\n`}}if(Ct(g,"policy")&&(e.attendanceRequirement?.description&&(w+=` 出勤要求:${e.attendanceRequirement.description}\n`),e.trainingRequired&&"不需要"!==e.trainingRequired&&(w+=` 培训要求:${e.trainingRequired}\n`),e.probationRequired&&"不需要"!==e.probationRequired&&(w+=` 试岗要求:${e.probationRequired}\n`)),Ct(g,"availability")){const t=e.availableSlots?.filter(e=>e.isAvailable).slice(0,3)||[];t.length>0&&(w+=` 可用时段:${t.map(e=>e.slot).join("、")}\n`)}if(Ct(g,"requirements")&&e.hiringRequirements){const t=e.hiringRequirements,n=[];null==t.minAge&&null==t.maxAge||n.push(`年龄${t.minAge??"不限"}-${t.maxAge??"不限"}岁`),t.genderRequirement&&"0"!==t.genderRequirement&&n.push(`性别:${t.genderRequirement}`),t.education&&"不限"!==t.education&&n.push(`学历:${t.education}`),t.healthCertificate&&n.push(t.healthCertificate),t.languages&&n.push(`语言:${t.languages}`),t.socialIdentity&&"不限"!==t.socialIdentity&&n.push(`社会身份:${t.socialIdentity}`),n.length>0&&(w+=` 要求:${n.join("、")}\n`),t.recruitmentRemark&&(w+=` 招聘备注:${t.recruitmentRemark.slice(0,200)}\n`)}})})):w+=y?"当前处于首轮或浅层沟通,优先泛化回答,不主动展开具体门店、数字或筛选条件。\n":"本轮以推进沟通为主,无需展开岗位细节,请保持回答聚焦且克制。\n",{contextInfo:w,resolvedBrand:I,debugInfo:{relevantStores:R.length>0?R:L.map(e=>({store:e,distance:void 0})),storeCount:M,detailLevel:v,primaryNeed:p,turnPlan:t,aliasLookupError:_}}}var Ft=/[^。!?!?]*[??]/g,Pt={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 Bt(e){return e?.outputGuards??se}function jt(e){const t=e.match(Ft)??[],n=new Set(t.map(e=>e.replace(/[??]/g,"").trim()).filter(Boolean)),r=e.split(/[。!?!?]/).map(e=>e.trim()).filter(Boolean).filter(e=>/[吗呢么]$/.test(e)&&!n.has(e)).length;return t.length+r}function Gt(e){return e.split(/[。!?!?]/).map(e=>e.trim()).filter(Boolean).length}function Kt(e){return/(?:^|\s)(?:\d+\.\s|- |•)/m.test(e)}function Ht(e,t="mention"){return Object.entries(Pt).filter(([,n])=>n[t].some(t=>t.test(e))).map(([e])=>e)}function qt(e,t){return t.some(t=>t&&e.includes(t))}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,t,n){let r=0;return Gt(e)>=4&&(r+=1),Kt(e)&&(r+=1),t>=3&&(r+=1),n.length>=2&&(r+=1),r>=2}function Yt(e){return Ht(e,"concrete")}function zt(e){const t=[];return/薪资:/.test(e)&&t.push("salary"),/排班:|时间:|每周工时:/.test(e)&&t.push("schedule"),/匹配到的门店信息:[\s\S]*• .*:/.test(e)&&t.push("location"),/考勤:|出勤要求:/.test(e)&&t.push("policy"),/要求:/.test(e)&&t.push("requirements"),/可用时段:/.test(e)&&t.push("availability"),t}function Qt(e,t){const n=new Set(e.flatMap(e=>Q[e]));return 0===n.size?t.length>0:t.some(e=>!n.has(e))}function Jt(e){const{text:t,turnIndex:n,mode:r,policy:o}=e,s=Bt(o),a=jt(t),i=s.maxQuestionsByMode[r],c=Yt(t),u=e.allowedNeeds?.length?e.allowedNeeds:[e.primaryNeed],l=[];return a>i&&l.push("too_many_questions"),qt(t,s.blockedAuditPhrases)&&l.push("audit_tone"),s.blockFirstTurnSpecificFacts&&1===n&&Vt(t)&&l.push("premature_numeric_disclosure"),Qt(u,c)&&l.push("off_axis_fact_disclosure"),Wt(t,a,c)&&l.push("reply_overpacked"),{violations:l,questionCount:a,factFamilies:c}}import Zt from"ora";function Xt(){let e=null;return{update(t){e?e.text=t:e=Zt({text:t,stream:process.stderr}).start()},succeed(t){e?(e.succeed(t),e=null):console.error(`✓ ${t}`)},fail(t){e?(e.fail(t),e=null):console.error(`✗ ${t}`)}}}import{z as en}from"zod";var tn=en.object({minAge:en.number().nullable(),maxAge:en.number().nullable()}),nn=en.object({evidence:en.array(tn),matchedCount:en.number().int().min(0),total:en.number().int().min(0),isComplete:en.boolean()}),rn={enabled:!1,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!1,redirectPriority:"low"},on=200;function sn(e){return(e??"").trim().toLowerCase()}function an(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function cn(e){if("string"==typeof e)return e;if(Array.isArray(e)){const t=e.find(e=>"string"==typeof e);return"string"==typeof t?t:""}return""}function un(e,t){for(const n of t){if(!(n in e))continue;const t=cn(e[n]);if(t)return t}return""}function ln(e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e&&""!==e.trim()){const t=Number(e);if(Number.isFinite(t))return t}return null}function dn(e){return e.map(e=>sn(e)).filter(Boolean)}function mn(e,t){if(0===t.length)return!0;const n=sn(e);return!!n&&t.some(e=>n.includes(e)||e.includes(n))}function pn(e,t){return 0===t.length||e.some(e=>mn(e,t))}function fn(e,t){return!t||e.some(e=>sn(e).includes(t))}function gn(e){return e.some(e=>null!==e.minAge||null!==e.maxAge)}function yn(e,t){const n=t??rn;let r=n.unknownStrategy;return"pass"===e?r=n.passStrategy:"fail"===e&&(r=n.failStrategy),{...n,status:e,strategy:r}}function hn(){return{evidence:[],matchedCount:0,total:0,isComplete:!0}}function En(e){if(Array.isArray(e)){const t=e.map(e=>tn.safeParse(e)).filter(e=>e.success).map(e=>e.data);return{evidence:t,matchedCount:t.length,total:t.length,isComplete:!0}}const t=nn.safeParse(e);if(!t.success)return hn();return{evidence:t.data.evidence.map(e=>tn.safeParse(e)).filter(e=>e.success).map(e=>e.data),matchedCount:t.data.matchedCount,total:t.data.total,isComplete:t.data.isComplete}}function _n(e){return{name:"config-data",async collect(t){const n=dn(x(t.brandAlias,t.cityName)),r=dn(k(t.cityName)),o=sn(t.regionName),s=[];let a=0,i=0;for(const t of e.brands){if(pn([t.name,...t.aliases??[]],n))for(const e of t.stores)if(pn([e.city],r)&&(a+=e.positions.length,fn([e.district,e.subarea,e.location,e.name],o))){i+=e.positions.length;for(const t of e.positions)s.push({minAge:t.hiringRequirements?.minAge??null,maxAge:t.hiringRequirements?.maxAge??null})}}return{evidence:s,matchedCount:i,total:a,isComplete:!0}}}}function Nn({token:e,jobListUrl:t}){return{name:"duliday-api",async collect(n){try{const r=await j(e,t,1,on,{brandAlias:n.brandAlias??null,cityName:n.cityName??null}),{items:o,total:s}=P(r),a=s>o.length&&o.length>=on,i=dn(x(n.brandAlias,n.cityName)),c=dn(k(n.cityName)),u=sn(n.regionName),l=[];let d=0;for(const e of o){if(!an(e))continue;const t=e,n=an(t.basicInfo)?t.basicInfo:null,r=n&&an(n.storeInfo)?n.storeInfo:null,o=un(t,["brandAlias","brandName","brand","organizationName"])||(n?un(n,["brandAlias","brandName","brand"]):""),s=un(t,["cityName","storeCityName","jobCityName"])||(r?un(r,["storeCityName","cityName"]):""),a=un(t,["regionName","storeRegionName","districtName"])||(r?un(r,["storeRegionName","regionName","districtName"]):""),m=un(t,["storeAddress","jobAddress","address","storeExactAddress"])||(r?un(r,["storeAddress","storeExactAddress","address"]):"");if(!mn(o,i))continue;if(!mn(s,c))continue;if(!fn([a,m],u))continue;d+=1;const p=an(t.hiringRequirement)?t.hiringRequirement:void 0,f=an(p?.basicPersonalRequirements)?p.basicPersonalRequirements:void 0;l.push({minAge:ln(f?.minAge??t.minAge),maxAge:ln(f?.maxAge??t.maxAge)})}return{evidence:l,matchedCount:d,total:s,isComplete:!a}}catch{return hn()}}}}function In({configData:e,token:t,jobListUrl:n}){const r=[_n(e)];return t&&n&&r.push(Nn({token:t,jobListUrl:n})),r}async function An({sources:e,...t}){let n=hn();for(const r of e??[])try{const e=En(await r.collect(t));if(0===e.total&&0===e.matchedCount&&0===e.evidence.length)continue;if(e.isComplete&&gn(e.evidence))return e;0===n.total&&0===n.matchedCount&&0===n.evidence.length&&(n=e)}catch{continue}return n}function Sn({age:e,evidence:t,matchedCount:n,total:r,isComplete:o=!0,strategy:s}){const a=t.map(e=>tn.safeParse(e)).filter(e=>e.success).map(e=>e.data),i={minAgeObserved:null,maxAgeObserved:null,matchedCount:n??a.length,total:r??a.length};if("number"!=typeof e||!Number.isFinite(e)||0===a.length||!o)return{status:"unknown",summary:i,appliedStrategy:yn("unknown",s)};let c=!1,u=!1;for(const t of a){const{minAge:n,maxAge:r}=t;null!==n&&(c=!0,i.minAgeObserved=null===i.minAgeObserved?n:Math.min(i.minAgeObserved,n)),null!==r&&(c=!0,i.maxAgeObserved=null===i.maxAgeObserved?r:Math.max(i.maxAgeObserved,r));null!==n&&e<n||null!==r&&e>r||(u=!0)}if(!c)return{status:"unknown",summary:i,appliedStrategy:yn("unknown",s)};const l=u?"pass":"fail";return{status:l,summary:i,appliedStrategy:yn(l,s)}}function Tn(e){if(!e)return;const t=e.match(/(\d+)/);return t?t[1]:e}function bn(e,t){if("number"==typeof t?.age)return t.age;const n=Tn(t?.age);if(n){const e=Number(n);if(Number.isFinite(e))return e}return"number"==typeof e.extractedInfo.specificAge?e.extractedInfo.specificAge:void 0}function On(e,t){const n=e.extractedInfo.mentionedDistricts?.[0]?.district;if(n)return n;const r=e.extractedInfo.mentionedLocations?.[0]?.location;return r||(t?.jobAddress?t.jobAddress:void 0)}var Ln=[{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 Rn(e){if(!e)return{factsText:"",knownFieldNames:[]};const t=[];for(const{key:n,label:r}of Ln){const o=e[n];"string"==typeof o&&o.trim()?t.push({label:r,value:o.trim()}):"boolean"==typeof o&&t.push({label:r,value:o?"是":"否"})}return 0===t.length?{factsText:"",knownFieldNames:[]}:{factsText:t.map(e=>`${e.label}:${e.value}`).join("\n"),knownFieldNames:t.map(e=>e.label)}}function Mn(e){if(null===e.minAgeObserved&&null===e.maxAgeObserved)return null;return`${e.minAgeObserved??"?"}-${e.maxAgeObserved??"?"}`}function vn(e,t,n){const r=t?.qualificationPolicy?.age;if(!e||!r||!r.enabled)return[];if("unknown"===e.status&&!n.riskFlags.includes("age_sensitive"))return[];const o=["[QualificationPolicy:Age]"],s=Mn(e.summary);return o.push(`- gateStatus: ${e.status}`),o.push(`- expressionStrategy: ${e.appliedStrategy.strategy}`),o.push("- redirect: "+(r.allowRedirect?`allowed priority=${r.redirectPriority}`:"not allowed")),o.push("- revealRange: "+(r.revealRange?"allowed":"not allowed")),r.revealRange&&s&&o.push(`- rangeObserved: ${s}`),"pass"===e.status?o.push(`- writingConstraint: ${e.appliedStrategy.strategy};匹配通过后推进下一步,避免强调年龄筛选`):"fail"===e.status?(o.push(`- writingConstraint: ${e.appliedStrategy.strategy};礼貌说明不匹配,避免承诺或争辩`),r.allowRedirect&&o.push("- writingConstraint: 可提示其他岗位或门店选项")):o.push("- writingConstraint: 如确需涉及年龄或资格,用合规、轻量的方式核实,不要审查式逐条盘问"),o}function wn(e){return"minimal"===e?["4. 当前为浅层沟通,优先泛化回答,不主动抛具体数字、时间、地址或筛选条件。","5. 若候选人追问具体事实,承接需求并引导进一步沟通,不编造细节。"]:["4. 围绕 primaryNeed 回答,上下文中有的事实可以正常引用,不要刻意回避。","5. 不主动展开其他事实轴;若候选人同时问两个点,只在上下文支持时简要带上次要问题。"]}function Dn(e,t,n,r,o,s,a,i,c,u,l,d){if(!e)return{system:"你是招聘助手。遵循事实,不夸大承诺,回复简洁自然。",prompt:`候选人消息:${o}\n\n上下文:\n${r}\n\n请直接回复候选人。`};const m=e.stageGoals[t.stage],p=e.industryVoices[u||e.defaultIndustryVoiceId],f=e.outputGuards.maxQuestionsByMode[i];return{system:["你是政策驱动的招聘助手。",`当前阶段:${t.stage}`,`当前轮次:${a}`,`当前披露模式:${i}`,`主回答轴:${t.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("、")}`,...c.knownFieldNames.length>0?[`候选人资料已确认:${c.knownFieldNames.join("、")}。这些信息不得重复追问;如需引用,自然带过即可,不要像念资料一样复述。`]:[],...vn(d,e,t),l?`如涉及换微信,优先引导平台交换,必要时可提供默认微信号:${l}`:"如涉及换微信,优先引导平台交换,不编造联系方式。","必须口语化、简洁,不输出解释。"].filter(Boolean).join("\n"),prompt:["[回合规划]",`stage=${t.stage}`,`subGoals=${t.subGoals.join("、")||"无"}`,`contextNeeds=${n.join("、")||"none"}`,`primaryNeed=${t.primaryNeed}`,`riskFlags=${t.riskFlags.join("、")||"无"}`,`confidence=${t.confidence.toFixed(2)}`,"","[对话历史]",s.slice(-6).join("\n")||"无","","[业务上下文]",r,"",...c.factsText?["[候选人已知信息]",c.factsText,""]:[],"[候选人消息]",o,"","[输出要求]","1. 直接给候选人的单条回复,不得输出多段解释或元信息。",`2. 最多追问 ${f} 个关键问题。`,"3. 禁止使用“是否满足”“是否符合”“基本入职要求”等审查措辞。",...wn(i)].join("\n")}}function Un(e,t,n){const r=Yt(e);if(0===r.length)return!1;const o=new Set(zt(t)),s=new Set(n.flatMap(e=>Q[e]));return r.some(e=>!s.has(e)||!o.has(e))}function $n(e){return"private_channel"===e||"interview_scheduling"===e}function Cn(e,t){return Number.isInteger(t)&&void 0!==t&&t>=1?t:0===e.length?1:2}function kn(e,t){return 1===e||"trust_building"===t||"private_channel"===t?"minimal":"focused"}function xn(e,t){const n=["- 只修正命中的违规点,没有命中的部分不要过度改写。"];return e.includes("too_many_questions")&&n.push(`- 删除多余追问,只保留最关键的 ${t} 个问题。`),e.includes("audit_tone")&&n.push("- 保留原意,但把审查式措辞改成自然口语,不要像筛选候选人。"),e.includes("premature_numeric_disclosure")&&n.push("- 把具体数字、时间和地址细节改成泛化表达,例如“细节我帮你确认”或“以门店安排为准”。"),e.includes("off_axis_fact_disclosure")&&n.push("- 删除不属于主回答轴的具体事实;如果要提到次要问题,只能做不带细节的承接。"),e.includes("reply_overpacked")&&n.push("- 压缩成最多两句,不要列表、不要枚举、不要一口气展开太多信息。"),n}async function Fn(e,t,n){const r=["请重写下面这条招聘回复。","要求:","- 不新增任何具体数字、地址、福利承诺。","- 仅保留泛化表达,强调可进一步沟通确认细节。","- 口语化、单行、简洁。","","[原回复]",e,"","[可用上下文]",n].join("\n"),o=await Ye({model:t,prompt:r,context:"SmartReplyFactGateRewrite",timeoutMs:2e4,maxOutputTokens:500});return o.success?{text:o.text,usage:o.usage,latencyMs:o.latencyMs}:{text:e}}async function Pn(e,t,n,r){const{turnIndex:o,effectiveDisclosureMode:s,primaryNeed:a,allowedNeeds:i,violations:c,policy:u}=r,l=u?.outputGuards.maxQuestionsByMode[s]??1,d=u?.outputGuards.blockedAuditPhrases.join("、")??"",m=xn(c,l),p=(i??[]).filter(e=>e!==a&&"none"!==e),f=["请重写下面这条招聘回复。","要求:",`- 当前轮次=${o},披露模式=${s},主回答轴=${a}。`,p.length>0?`- 允许顺带覆盖的次要轴:${p.join("、")}。`:"",`- 当前违规点:${c.join("、")}。`,...m,"- 只保留单条口语化回复,不输出解释。",`- 问题数最多 ${l} 个。`,"- 围绕主回答轴回答,不主动展开其他事实轴。","- 首轮时不要主动报具体数字、时间、地址或筛选条件。",d?`- 禁止使用这些措辞:${d}。`:"","","[原回复]",e,"","[可用上下文]",n].filter(Boolean).join("\n"),g=await Ye({model:t,prompt:f,context:"SmartReplyReplyGateRewrite",timeoutMs:2e4,maxOutputTokens:500});return g.success?{text:g.text,usage:g.usage,latencyMs:g.latencyMs}:{text:e}}async function Bn(e){const t=Xt();c(!0);try{return await jn(e,t)}catch(e){throw t.fail("回复生成失败"),e}finally{c(!1)}}async function jn(e,t){const{modelConfig:n,preferredBrand:r,toolBrand:o,brandPriorityStrategy:s,conversationHistory:a=[],candidateMessage:i,configData:c,replyPolicy:u,candidateInfo:l,defaultWechatId:d,industryVoiceId:m,channelType:p,turnIndex:y,ageEligibilitySources:h}=e,E=n?.providerConfigs||f,_=L(c),N={..._?{city:_}:{},defaultBrand:O(c),availableBrands:S(c),storeCount:A(c).length},T=Rn(l);t.update("分析对话意图...");const b=await ht(i,{modelConfig:n||{},conversationHistory:a,brandData:N,providerConfigs:E,...void 0!==p?{channelType:p}:{},...void 0!==u?{replyPolicy:u}:{},...T.knownFieldNames.length>0?{knownCandidateFields:T.knownFieldNames}:{}}),R=Cn(a,y),M=kn(R,b.stage),v="focused"===M?pt(b.primaryNeed,b.needs,i,2):[b.primaryNeed],w=o||b.extractedInfo.mentionedBrand||void 0;t.update("构建业务上下文...");const{contextInfo:D,debugInfo:C,resolvedBrand:k}=await xt(c,b,r,w,s,l,u,m,R,M,v);t.update("校验候选人资格...");const x=bn(b,l),F=On(b,l),P=b.extractedInfo.city??L(c,k),B=h??In({configData:c,token:$(),jobListUrl:U()}),j=await An({sources:B,brandAlias:k,..."string"==typeof P?{cityName:P}:{},...void 0!==F?{regionName:F}:{}}),G=Sn({...void 0!==x?{age:x}:{},evidence:j.evidence,matchedCount:j.matchedCount,total:j.total,isComplete:j.isComplete,...void 0!==u?.qualificationPolicy?.age?{strategy:u.qualificationPolicy.age}:{}}),K=I(E),H=n?.replyModel||g.replyModel,q=K.languageModel(H),V=Dn(u,b,v,D,i,a,R,M,T,m,d,G);t.update("生成回复...");const W=await Ye({model:q,system:V.system,prompt:V.prompt,context:"SmartReply",timeoutMs:3e4,maxOutputTokens:2e3});if(!W.success)return t.fail("回复生成失败"),xe("SmartReply 生成失败",W.error),{turnPlan:b,suggestedReply:"",confidence:0,shouldExchangeWechat:$n(b.stage),factGateRewritten:!1,replyGateRewritten:!1,gateViolations:[],contextInfo:D,debugInfo:{...C,resolvedBrand:k,turnIndex:R,effectiveDisclosureMode:M,primaryNeed:b.primaryNeed,replyGateRewritten:!1,gateViolations:[],gateStatus:G.status,appliedStrategy:G.appliedStrategy,ageRangeSummary:G.summary},usage:void 0,error:W.error};let Y=W.text,z=W.usage,Q=W.latencyMs,J=!1,Z=!1,X=[];if(t.update("检查回复质量..."),"strict"===u?.factGate.mode){if(Un(Y,D,v)){J=!0;const e=await Fn(Y,q,D);Y=e.text,e.usage&&(z=e.usage),void 0!==e.latencyMs&&(Q=(Q??0)+e.latencyMs)}}if(X=Jt({text:Y,turnIndex:R,mode:M,primaryNeed:b.primaryNeed,allowedNeeds:v,policy:u}).violations,X.length>0){t.update("优化回复..."),Z=!0;const e=await Pn(Y,q,D,{turnIndex:R,effectiveDisclosureMode:M,primaryNeed:b.primaryNeed,allowedNeeds:v,violations:X,policy:u});Y=e.text,e.usage&&(z=e.usage),void 0!==e.latencyMs&&(Q=(Q??0)+e.latencyMs),X=Jt({text:Y,turnIndex:R,mode:M,primaryNeed:b.primaryNeed,allowedNeeds:v,policy:u}).violations}const ee=Q??0,te=z?.totalTokens??0;return t.succeed(`回复已生成 | ${b.stage} | ${ee}ms | ${te} tokens${Z?" | 已优化":""}`),{turnPlan:b,suggestedReply:Y,confidence:Math.max(0,Math.min(1,b.confidence)),shouldExchangeWechat:$n(b.stage),factGateRewritten:J,replyGateRewritten:Z,gateViolations:X,contextInfo:`${D}\n当前品牌:${k}`,debugInfo:{...C,resolvedBrand:k,turnIndex:R,effectiveDisclosureMode:M,primaryNeed:b.primaryNeed,replyGateRewritten:Z,gateViolations:X,gateStatus:G.status,appliedStrategy:G.appliedStrategy,ageRangeSummary:G.summary},usage:z,latencyMs:Q}}export{An as collectAgeEvidenceFromSources,_n as createConfigDataAgeSource,In as createDefaultAgeEligibilitySources,Nn as createDulidayApiAgeSource,Sn as evaluateAgeEligibility,Bn as generateSmartReply};
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export type BrandAliasMap = Map<string, string>;
|
|
2
|
-
export type BrandDictionary = Record<string, string[]>;
|
|
3
|
-
export declare function getSharedBrandDictionary(dulidayToken?: string): Promise<BrandDictionary>;
|
|
4
|
-
export declare function getSharedBrandAliasMap(dulidayToken?: string): Promise<BrandAliasMap>;
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { Brand, Store, ZhipinData } from "../types/zhipin.ts";
|
|
2
|
-
export declare function getAllStores(data: ZhipinData): Store[];
|
|
3
|
-
export declare function getAvailableBrandNames(data: ZhipinData): string[];
|
|
4
|
-
export declare function findBrandByName(data: ZhipinData, brandName?: string | null): Brand | undefined;
|
|
5
|
-
export declare function resolveDefaultBrand(data: ZhipinData): Brand | undefined;
|
|
6
|
-
export declare function resolveDefaultBrandName(data: ZhipinData): string;
|
|
7
|
-
export declare function resolvePrimaryCity(data: ZhipinData, brandName?: string | null): string | undefined;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { ZhipinData } from "../types/zhipin.ts";
|
|
2
|
-
import type { ReplyPolicyConfig } from "../types/reply-policy.ts";
|
|
3
|
-
export declare function loadBrandConfig(): ZhipinData;
|
|
4
|
-
export declare function saveBrandConfig(data: ZhipinData): void;
|
|
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;
|
|
11
|
-
export declare function saveReplyPolicy(policy: ReplyPolicyConfig): void;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
export declare function getDulidayJobListEndpoint(): string | undefined;
|
|
2
|
-
export declare function getDulidayToken(): string | undefined;
|
|
3
|
-
export declare function normalizeName(value: string | null | undefined): string;
|
|
4
|
-
export declare function buildCityCandidates(cityName?: string | null): string[];
|
|
5
|
-
export declare function buildBrandCandidates(brandAlias?: string | null, cityName?: string | null): string[];
|
|
6
|
-
export declare function extractResults(payload: unknown): {
|
|
7
|
-
items: unknown[];
|
|
8
|
-
total: number;
|
|
9
|
-
};
|
|
10
|
-
export declare const FULL_INCLUDE_OPTIONS: {
|
|
11
|
-
readonly includeBasicInfo: true;
|
|
12
|
-
readonly includeJobSalary: true;
|
|
13
|
-
readonly includeWelfare: true;
|
|
14
|
-
readonly includeHiringRequirement: true;
|
|
15
|
-
readonly includeWorkTime: true;
|
|
16
|
-
};
|
|
17
|
-
export type FetchJobListIncludeOptions = Partial<Record<keyof typeof FULL_INCLUDE_OPTIONS, boolean>>;
|
|
18
|
-
export declare function fetchJobListPage(token: string, endpoint: string, pageNum: number, pageSize: number, options?: {
|
|
19
|
-
brandAlias?: string | null;
|
|
20
|
-
cityName?: string | null;
|
|
21
|
-
include?: FetchJobListIncludeOptions;
|
|
22
|
-
}): Promise<unknown>;
|
|
23
|
-
export declare function fetchAllJobListPages(token: string, endpoint: string, options?: {
|
|
24
|
-
brandAlias?: string | null;
|
|
25
|
-
cityName?: string | null;
|
|
26
|
-
include?: FetchJobListIncludeOptions;
|
|
27
|
-
}): Promise<{
|
|
28
|
-
items: unknown[];
|
|
29
|
-
total: number;
|
|
30
|
-
}>;
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { DulidaySalaryScenario, DulidayNewWelfare } from "../types/duliday-api.ts";
|
|
2
|
-
import type { ZhipinData, SalaryDetails, Benefits } from "../types/zhipin.ts";
|
|
3
|
-
export declare function convertPositionsToZhipinData(rawPositions: unknown[], preferredDefaultBrandName?: string | undefined, cityName?: string | undefined): ZhipinData;
|
|
4
|
-
export declare function parseSalaryDetails(baseSalary: number | null, salaryUnit: string | null, welfare: DulidayNewWelfare): SalaryDetails;
|
|
5
|
-
export declare function buildScenarioSummary(scenarios: DulidaySalaryScenario[] | null | undefined): string | undefined;
|
|
6
|
-
export declare function extractSettlementCycle(scenarios: DulidaySalaryScenario[] | null | undefined): string | undefined;
|
|
7
|
-
export declare function parseBenefits(welfare: DulidayNewWelfare): Benefits;
|
|
8
|
-
export declare function parseTimeStringToSeconds(timeStr: unknown): number;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export declare const syncBrandData: import("@roll-agent/sdk").ToolDefinition<{
|
|
2
|
-
cityName: string;
|
|
3
|
-
brandAlias?: string | undefined;
|
|
4
|
-
}, {
|
|
5
|
-
success: boolean;
|
|
6
|
-
brandsCount: number;
|
|
7
|
-
storesCount: number;
|
|
8
|
-
positionsCount: number;
|
|
9
|
-
updatedAt: string;
|
|
10
|
-
error?: string | undefined;
|
|
11
|
-
}>;
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import type { BrandPriorityStrategy } from "./config.ts";
|
|
3
|
-
export declare const BrandResolutionInputSchema: z.ZodObject<{
|
|
4
|
-
uiSelectedBrand: z.ZodOptional<z.ZodString>;
|
|
5
|
-
configDefaultBrand: z.ZodOptional<z.ZodString>;
|
|
6
|
-
conversationBrand: z.ZodOptional<z.ZodString>;
|
|
7
|
-
availableBrands: z.ZodArray<z.ZodString, "many">;
|
|
8
|
-
strategy: z.ZodEnum<["user-selected", "conversation-extracted", "smart"]>;
|
|
9
|
-
}, "strip", z.ZodTypeAny, {
|
|
10
|
-
availableBrands: string[];
|
|
11
|
-
strategy: "user-selected" | "conversation-extracted" | "smart";
|
|
12
|
-
uiSelectedBrand?: string | undefined;
|
|
13
|
-
configDefaultBrand?: string | undefined;
|
|
14
|
-
conversationBrand?: string | undefined;
|
|
15
|
-
}, {
|
|
16
|
-
availableBrands: string[];
|
|
17
|
-
strategy: "user-selected" | "conversation-extracted" | "smart";
|
|
18
|
-
uiSelectedBrand?: string | undefined;
|
|
19
|
-
configDefaultBrand?: string | undefined;
|
|
20
|
-
conversationBrand?: string | undefined;
|
|
21
|
-
}>;
|
|
22
|
-
export type BrandResolutionInput = z.infer<typeof BrandResolutionInputSchema> & {
|
|
23
|
-
aliasMap?: Map<string, string> | undefined;
|
|
24
|
-
};
|
|
25
|
-
export declare const BrandMatchTypeSchema: z.ZodEnum<["exact", "fuzzy", "fallback"]>;
|
|
26
|
-
export type BrandMatchType = z.infer<typeof BrandMatchTypeSchema>;
|
|
27
|
-
export declare const BrandSourceSchema: z.ZodEnum<["ui", "conversation", "config", "default"]>;
|
|
28
|
-
export type BrandSource = z.infer<typeof BrandSourceSchema>;
|
|
29
|
-
export declare const BrandResolutionOutputSchema: z.ZodObject<{
|
|
30
|
-
resolvedBrand: z.ZodString;
|
|
31
|
-
matchType: z.ZodEnum<["exact", "fuzzy", "fallback"]>;
|
|
32
|
-
source: z.ZodEnum<["ui", "conversation", "config", "default"]>;
|
|
33
|
-
reason: z.ZodString;
|
|
34
|
-
originalInput: z.ZodOptional<z.ZodString>;
|
|
35
|
-
}, "strip", z.ZodTypeAny, {
|
|
36
|
-
source: "default" | "config" | "ui" | "conversation";
|
|
37
|
-
resolvedBrand: string;
|
|
38
|
-
matchType: "exact" | "fuzzy" | "fallback";
|
|
39
|
-
reason: string;
|
|
40
|
-
originalInput?: string | undefined;
|
|
41
|
-
}, {
|
|
42
|
-
source: "default" | "config" | "ui" | "conversation";
|
|
43
|
-
resolvedBrand: string;
|
|
44
|
-
matchType: "exact" | "fuzzy" | "fallback";
|
|
45
|
-
reason: string;
|
|
46
|
-
originalInput?: string | undefined;
|
|
47
|
-
}>;
|
|
48
|
-
export type BrandResolutionOutput = z.infer<typeof BrandResolutionOutputSchema>;
|
|
49
|
-
export declare const FuzzyMatchResultSchema: z.ZodObject<{
|
|
50
|
-
brand: z.ZodString;
|
|
51
|
-
isExact: z.ZodBoolean;
|
|
52
|
-
originalInput: z.ZodString;
|
|
53
|
-
}, "strip", z.ZodTypeAny, {
|
|
54
|
-
brand: string;
|
|
55
|
-
originalInput: string;
|
|
56
|
-
isExact: boolean;
|
|
57
|
-
}, {
|
|
58
|
-
brand: string;
|
|
59
|
-
originalInput: string;
|
|
60
|
-
isExact: boolean;
|
|
61
|
-
}>;
|
|
62
|
-
export type FuzzyMatchResult = z.infer<typeof FuzzyMatchResultSchema>;
|
|
63
|
-
export declare const BRAND_RESOLUTION_PRIORITY: {
|
|
64
|
-
readonly "user-selected": readonly ["uiSelectedBrand", "configDefaultBrand", "firstAvailable"];
|
|
65
|
-
readonly "conversation-extracted": readonly ["conversationBrand", "uiSelectedBrand", "configDefaultBrand", "firstAvailable"];
|
|
66
|
-
readonly smart: readonly ["conversationBrand", "uiSelectedBrand", "configDefaultBrand", "firstAvailable"];
|
|
67
|
-
};
|
|
68
|
-
export declare function isBrandPriorityStrategy(value: unknown): value is BrandPriorityStrategy;
|
|
69
|
-
export interface BrandResolutionContext {
|
|
70
|
-
sources: {
|
|
71
|
-
ui?: string;
|
|
72
|
-
conversation?: string;
|
|
73
|
-
config?: string;
|
|
74
|
-
};
|
|
75
|
-
availableBrands: string[];
|
|
76
|
-
strategy: BrandPriorityStrategy;
|
|
77
|
-
attempts: Array<{
|
|
78
|
-
source: string;
|
|
79
|
-
value: string | undefined;
|
|
80
|
-
matched: boolean;
|
|
81
|
-
reason: string;
|
|
82
|
-
}>;
|
|
83
|
-
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export declare const ProviderConfigSchema: z.ZodObject<{
|
|
3
|
-
name: z.ZodString;
|
|
4
|
-
baseURL: z.ZodString;
|
|
5
|
-
description: z.ZodString;
|
|
6
|
-
}, "strip", z.ZodTypeAny, {
|
|
7
|
-
description: string;
|
|
8
|
-
name: string;
|
|
9
|
-
baseURL: string;
|
|
10
|
-
}, {
|
|
11
|
-
description: string;
|
|
12
|
-
name: string;
|
|
13
|
-
baseURL: string;
|
|
14
|
-
}>;
|
|
15
|
-
export declare const ProviderConfigsSchema: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
16
|
-
name: z.ZodString;
|
|
17
|
-
baseURL: z.ZodString;
|
|
18
|
-
description: z.ZodString;
|
|
19
|
-
}, "strip", z.ZodTypeAny, {
|
|
20
|
-
description: string;
|
|
21
|
-
name: string;
|
|
22
|
-
baseURL: string;
|
|
23
|
-
}, {
|
|
24
|
-
description: string;
|
|
25
|
-
name: string;
|
|
26
|
-
baseURL: string;
|
|
27
|
-
}>>;
|
|
28
|
-
export declare const ModelConfigSchema: z.ZodObject<{
|
|
29
|
-
chatModel: z.ZodOptional<z.ZodString>;
|
|
30
|
-
classifyModel: z.ZodOptional<z.ZodString>;
|
|
31
|
-
replyModel: z.ZodOptional<z.ZodString>;
|
|
32
|
-
providerConfigs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
33
|
-
name: z.ZodString;
|
|
34
|
-
baseURL: z.ZodString;
|
|
35
|
-
description: z.ZodString;
|
|
36
|
-
}, "strip", z.ZodTypeAny, {
|
|
37
|
-
description: string;
|
|
38
|
-
name: string;
|
|
39
|
-
baseURL: string;
|
|
40
|
-
}, {
|
|
41
|
-
description: string;
|
|
42
|
-
name: string;
|
|
43
|
-
baseURL: string;
|
|
44
|
-
}>>>;
|
|
45
|
-
}, "strip", z.ZodTypeAny, {
|
|
46
|
-
chatModel?: string | undefined;
|
|
47
|
-
classifyModel?: string | undefined;
|
|
48
|
-
replyModel?: string | undefined;
|
|
49
|
-
providerConfigs?: Record<string, {
|
|
50
|
-
description: string;
|
|
51
|
-
name: string;
|
|
52
|
-
baseURL: string;
|
|
53
|
-
}> | undefined;
|
|
54
|
-
}, {
|
|
55
|
-
chatModel?: string | undefined;
|
|
56
|
-
classifyModel?: string | undefined;
|
|
57
|
-
replyModel?: string | undefined;
|
|
58
|
-
providerConfigs?: Record<string, {
|
|
59
|
-
description: string;
|
|
60
|
-
name: string;
|
|
61
|
-
baseURL: string;
|
|
62
|
-
}> | undefined;
|
|
63
|
-
}>;
|
|
64
|
-
export declare const BrandDataSchema: z.ZodObject<{
|
|
65
|
-
city: z.ZodOptional<z.ZodString>;
|
|
66
|
-
defaultBrand: z.ZodString;
|
|
67
|
-
availableBrands: z.ZodArray<z.ZodString, "many">;
|
|
68
|
-
storeCount: z.ZodNumber;
|
|
69
|
-
}, "strip", z.ZodTypeAny, {
|
|
70
|
-
defaultBrand: string;
|
|
71
|
-
availableBrands: string[];
|
|
72
|
-
storeCount: number;
|
|
73
|
-
city?: string | undefined;
|
|
74
|
-
}, {
|
|
75
|
-
defaultBrand: string;
|
|
76
|
-
availableBrands: string[];
|
|
77
|
-
storeCount: number;
|
|
78
|
-
city?: string | undefined;
|
|
79
|
-
}>;
|
|
80
|
-
export declare const ClassificationOptionsSchema: z.ZodObject<{
|
|
81
|
-
modelConfig: z.ZodObject<{
|
|
82
|
-
chatModel: z.ZodOptional<z.ZodString>;
|
|
83
|
-
classifyModel: z.ZodOptional<z.ZodString>;
|
|
84
|
-
replyModel: z.ZodOptional<z.ZodString>;
|
|
85
|
-
providerConfigs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
86
|
-
name: z.ZodString;
|
|
87
|
-
baseURL: z.ZodString;
|
|
88
|
-
description: z.ZodString;
|
|
89
|
-
}, "strip", z.ZodTypeAny, {
|
|
90
|
-
description: string;
|
|
91
|
-
name: string;
|
|
92
|
-
baseURL: string;
|
|
93
|
-
}, {
|
|
94
|
-
description: string;
|
|
95
|
-
name: string;
|
|
96
|
-
baseURL: string;
|
|
97
|
-
}>>>;
|
|
98
|
-
}, "strip", z.ZodTypeAny, {
|
|
99
|
-
chatModel?: string | undefined;
|
|
100
|
-
classifyModel?: string | undefined;
|
|
101
|
-
replyModel?: string | undefined;
|
|
102
|
-
providerConfigs?: Record<string, {
|
|
103
|
-
description: string;
|
|
104
|
-
name: string;
|
|
105
|
-
baseURL: string;
|
|
106
|
-
}> | undefined;
|
|
107
|
-
}, {
|
|
108
|
-
chatModel?: string | undefined;
|
|
109
|
-
classifyModel?: string | undefined;
|
|
110
|
-
replyModel?: string | undefined;
|
|
111
|
-
providerConfigs?: Record<string, {
|
|
112
|
-
description: string;
|
|
113
|
-
name: string;
|
|
114
|
-
baseURL: string;
|
|
115
|
-
}> | undefined;
|
|
116
|
-
}>;
|
|
117
|
-
candidateMessage: z.ZodString;
|
|
118
|
-
conversationHistory: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
119
|
-
brandData: z.ZodOptional<z.ZodObject<{
|
|
120
|
-
city: z.ZodOptional<z.ZodString>;
|
|
121
|
-
defaultBrand: z.ZodString;
|
|
122
|
-
availableBrands: z.ZodArray<z.ZodString, "many">;
|
|
123
|
-
storeCount: z.ZodNumber;
|
|
124
|
-
}, "strip", z.ZodTypeAny, {
|
|
125
|
-
defaultBrand: string;
|
|
126
|
-
availableBrands: string[];
|
|
127
|
-
storeCount: number;
|
|
128
|
-
city?: string | undefined;
|
|
129
|
-
}, {
|
|
130
|
-
defaultBrand: string;
|
|
131
|
-
availableBrands: string[];
|
|
132
|
-
storeCount: number;
|
|
133
|
-
city?: string | undefined;
|
|
134
|
-
}>>;
|
|
135
|
-
channelType: z.ZodOptional<z.ZodEnum<["public", "private"]>>;
|
|
136
|
-
}, "strip", z.ZodTypeAny, {
|
|
137
|
-
modelConfig: {
|
|
138
|
-
chatModel?: string | undefined;
|
|
139
|
-
classifyModel?: string | undefined;
|
|
140
|
-
replyModel?: string | undefined;
|
|
141
|
-
providerConfigs?: Record<string, {
|
|
142
|
-
description: string;
|
|
143
|
-
name: string;
|
|
144
|
-
baseURL: string;
|
|
145
|
-
}> | undefined;
|
|
146
|
-
};
|
|
147
|
-
candidateMessage: string;
|
|
148
|
-
conversationHistory: string[];
|
|
149
|
-
brandData?: {
|
|
150
|
-
defaultBrand: string;
|
|
151
|
-
availableBrands: string[];
|
|
152
|
-
storeCount: number;
|
|
153
|
-
city?: string | undefined;
|
|
154
|
-
} | undefined;
|
|
155
|
-
channelType?: "public" | "private" | undefined;
|
|
156
|
-
}, {
|
|
157
|
-
modelConfig: {
|
|
158
|
-
chatModel?: string | undefined;
|
|
159
|
-
classifyModel?: string | undefined;
|
|
160
|
-
replyModel?: string | undefined;
|
|
161
|
-
providerConfigs?: Record<string, {
|
|
162
|
-
description: string;
|
|
163
|
-
name: string;
|
|
164
|
-
baseURL: string;
|
|
165
|
-
}> | undefined;
|
|
166
|
-
};
|
|
167
|
-
candidateMessage: string;
|
|
168
|
-
conversationHistory?: string[] | undefined;
|
|
169
|
-
brandData?: {
|
|
170
|
-
defaultBrand: string;
|
|
171
|
-
availableBrands: string[];
|
|
172
|
-
storeCount: number;
|
|
173
|
-
city?: string | undefined;
|
|
174
|
-
} | undefined;
|
|
175
|
-
channelType?: "public" | "private" | undefined;
|
|
176
|
-
}>;
|
|
177
|
-
export type ProviderConfig = z.infer<typeof ProviderConfigSchema>;
|
|
178
|
-
export type ModelConfig = z.infer<typeof ModelConfigSchema>;
|
|
179
|
-
export type ProviderConfigs = z.infer<typeof ProviderConfigsSchema>;
|
|
180
|
-
export type BrandData = z.infer<typeof BrandDataSchema>;
|
|
181
|
-
export type ClassificationOptions = z.infer<typeof ClassificationOptionsSchema>;
|
package/dist/types/config.d.ts
DELETED