@roll-agent/smart-reply-agent 0.1.0 → 0.1.1
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/dist/ai/model-registry.d.ts +0 -1
- package/dist/ai/model-registry.js +1 -205
- package/dist/ai/structured-output.d.ts +0 -1
- package/dist/ai/structured-output.js +1 -78
- package/dist/errors/app-error.d.ts +0 -1
- package/dist/errors/app-error.js +1 -95
- package/dist/errors/error-codes.d.ts +0 -1
- package/dist/errors/error-codes.js +1 -115
- package/dist/errors/error-factory.d.ts +0 -1
- package/dist/errors/error-factory.js +1 -86
- package/dist/errors/error-utils.d.ts +0 -1
- package/dist/errors/error-utils.js +1 -188
- package/dist/errors/index.d.ts +0 -1
- package/dist/errors/index.js +1 -5
- package/dist/index.d.ts +0 -1
- package/dist/index.js +1 -12
- package/dist/log-control.d.ts +0 -1
- package/dist/log-control.js +1 -15
- package/dist/pipeline/age-eligibility.d.ts +0 -1
- package/dist/pipeline/age-eligibility.js +1 -176
- package/dist/pipeline/candidate-context.d.ts +0 -1
- package/dist/pipeline/candidate-context.js +1 -31
- package/dist/pipeline/candidate-utils.d.ts +0 -1
- package/dist/pipeline/candidate-utils.js +1 -33
- package/dist/pipeline/classification.d.ts +0 -1
- package/dist/pipeline/classification.js +1 -206
- package/dist/pipeline/context-builder.d.ts +0 -1
- package/dist/pipeline/context-builder.js +1 -404
- package/dist/pipeline/pipeline-progress.d.ts +0 -1
- package/dist/pipeline/pipeline-progress.js +1 -33
- package/dist/pipeline/reply-gate.d.ts +0 -1
- package/dist/pipeline/reply-gate.js +1 -139
- package/dist/pipeline/smart-reply.d.ts +0 -1
- package/dist/pipeline/smart-reply.js +1 -418
- package/dist/pipeline.d.ts +0 -1
- package/dist/pipeline.js +1 -12
- package/dist/services/brand-alias.d.ts +0 -1
- package/dist/services/brand-alias.js +1 -184
- package/dist/services/brand-config-selectors.d.ts +0 -1
- package/dist/services/brand-config-selectors.js +1 -30
- package/dist/services/config-loader.d.ts +0 -1
- package/dist/services/config-loader.js +1 -45
- package/dist/services/duliday-api.d.ts +0 -1
- package/dist/services/duliday-api.js +1 -160
- package/dist/services/duliday-mapper.d.ts +0 -1
- package/dist/services/duliday-mapper.js +1 -536
- package/dist/tools/generate-reply.d.ts +0 -1
- package/dist/tools/generate-reply.js +1 -132
- package/dist/tools/sync-brand-data.d.ts +0 -1
- package/dist/tools/sync-brand-data.js +1 -114
- package/dist/types/brand-resolution.d.ts +0 -1
- package/dist/types/brand-resolution.js +1 -37
- package/dist/types/classification.d.ts +0 -1
- package/dist/types/classification.js +1 -30
- package/dist/types/config.d.ts +0 -1
- package/dist/types/config.js +1 -7
- package/dist/types/duliday-api.d.ts +0 -1
- package/dist/types/duliday-api.js +1 -235
- package/dist/types/geocoding.d.ts +0 -1
- package/dist/types/geocoding.js +1 -12
- package/dist/types/reply-policy.d.ts +0 -1
- package/dist/types/reply-policy.js +1 -332
- package/dist/types/zhipin.d.ts +0 -1
- package/dist/types/zhipin.js +1 -123
- package/package.json +3 -3
- package/dist/ai/model-registry.d.ts.map +0 -1
- package/dist/ai/model-registry.js.map +0 -1
- package/dist/ai/structured-output.d.ts.map +0 -1
- package/dist/ai/structured-output.js.map +0 -1
- package/dist/errors/app-error.d.ts.map +0 -1
- package/dist/errors/app-error.js.map +0 -1
- package/dist/errors/error-codes.d.ts.map +0 -1
- package/dist/errors/error-codes.js.map +0 -1
- package/dist/errors/error-factory.d.ts.map +0 -1
- package/dist/errors/error-factory.js.map +0 -1
- package/dist/errors/error-utils.d.ts.map +0 -1
- package/dist/errors/error-utils.js.map +0 -1
- package/dist/errors/index.d.ts.map +0 -1
- package/dist/errors/index.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/log-control.d.ts.map +0 -1
- package/dist/log-control.js.map +0 -1
- package/dist/pipeline/age-eligibility.d.ts.map +0 -1
- package/dist/pipeline/age-eligibility.js.map +0 -1
- package/dist/pipeline/candidate-context.d.ts.map +0 -1
- package/dist/pipeline/candidate-context.js.map +0 -1
- package/dist/pipeline/candidate-utils.d.ts.map +0 -1
- package/dist/pipeline/candidate-utils.js.map +0 -1
- package/dist/pipeline/classification.d.ts.map +0 -1
- package/dist/pipeline/classification.js.map +0 -1
- package/dist/pipeline/context-builder.d.ts.map +0 -1
- package/dist/pipeline/context-builder.js.map +0 -1
- package/dist/pipeline/pipeline-progress.d.ts.map +0 -1
- package/dist/pipeline/pipeline-progress.js.map +0 -1
- package/dist/pipeline/reply-gate.d.ts.map +0 -1
- package/dist/pipeline/reply-gate.js.map +0 -1
- package/dist/pipeline/smart-reply.d.ts.map +0 -1
- package/dist/pipeline/smart-reply.js.map +0 -1
- package/dist/pipeline.d.ts.map +0 -1
- package/dist/pipeline.js.map +0 -1
- package/dist/services/brand-alias.d.ts.map +0 -1
- package/dist/services/brand-alias.js.map +0 -1
- package/dist/services/brand-config-selectors.d.ts.map +0 -1
- package/dist/services/brand-config-selectors.js.map +0 -1
- package/dist/services/config-loader.d.ts.map +0 -1
- package/dist/services/config-loader.js.map +0 -1
- package/dist/services/duliday-api.d.ts.map +0 -1
- package/dist/services/duliday-api.js.map +0 -1
- package/dist/services/duliday-mapper.d.ts.map +0 -1
- package/dist/services/duliday-mapper.js.map +0 -1
- package/dist/tools/generate-reply.d.ts.map +0 -1
- package/dist/tools/generate-reply.js.map +0 -1
- package/dist/tools/sync-brand-data.d.ts.map +0 -1
- package/dist/tools/sync-brand-data.js.map +0 -1
- package/dist/types/brand-resolution.d.ts.map +0 -1
- package/dist/types/brand-resolution.js.map +0 -1
- package/dist/types/classification.d.ts.map +0 -1
- package/dist/types/classification.js.map +0 -1
- package/dist/types/config.d.ts.map +0 -1
- package/dist/types/config.js.map +0 -1
- package/dist/types/duliday-api.d.ts.map +0 -1
- package/dist/types/duliday-api.js.map +0 -1
- package/dist/types/geocoding.d.ts.map +0 -1
- package/dist/types/geocoding.js.map +0 -1
- package/dist/types/reply-policy.d.ts.map +0 -1
- package/dist/types/reply-policy.js.map +0 -1
- package/dist/types/zhipin.d.ts.map +0 -1
- package/dist/types/zhipin.js.map +0 -1
|
@@ -1,188 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AppError, isAppError } from "./app-error.js";
|
|
3
|
-
import { ErrorCode as EC } from "./error-codes.js";
|
|
4
|
-
import { createLLMError, createNetworkError, createStructuredOutputError, } from "./error-factory.js";
|
|
5
|
-
export function parseAISDKError(error) {
|
|
6
|
-
if (!error || typeof error !== "object")
|
|
7
|
-
return null;
|
|
8
|
-
const err = error;
|
|
9
|
-
const isAISDKError = err.name === "AI_APICallError" ||
|
|
10
|
-
err.name === "APICallError" ||
|
|
11
|
-
(typeof err.url === "string" && typeof err.statusCode === "number");
|
|
12
|
-
if (!isAISDKError)
|
|
13
|
-
return null;
|
|
14
|
-
const statusCode = typeof err.statusCode === "number" ? err.statusCode : undefined;
|
|
15
|
-
const responseBody = typeof err.responseBody === "string" ? err.responseBody : undefined;
|
|
16
|
-
const url = typeof err.url === "string" ? err.url : undefined;
|
|
17
|
-
const message = err.message;
|
|
18
|
-
let provider;
|
|
19
|
-
if (url) {
|
|
20
|
-
if (url.includes("openai.com"))
|
|
21
|
-
provider = "openai";
|
|
22
|
-
else if (url.includes("anthropic.com"))
|
|
23
|
-
provider = "anthropic";
|
|
24
|
-
else if (url.includes("dashscope.aliyuncs.com"))
|
|
25
|
-
provider = "qwen";
|
|
26
|
-
else if (url.includes("openrouter.ai"))
|
|
27
|
-
provider = "openrouter";
|
|
28
|
-
else if (url.includes("deepseek.com"))
|
|
29
|
-
provider = "deepseek";
|
|
30
|
-
else if (url.includes("moonshot.cn"))
|
|
31
|
-
provider = "moonshotai";
|
|
32
|
-
else if (url.includes("googleapis.com"))
|
|
33
|
-
provider = "google";
|
|
34
|
-
}
|
|
35
|
-
let model;
|
|
36
|
-
if (responseBody) {
|
|
37
|
-
const modelMatch = responseBody.match(/model[`'":\s]+([^`'"}\s,]+)/i);
|
|
38
|
-
if (modelMatch)
|
|
39
|
-
model = modelMatch[1];
|
|
40
|
-
}
|
|
41
|
-
return {
|
|
42
|
-
isAuthError: statusCode === 401 || statusCode === 403,
|
|
43
|
-
isModelNotFound: (responseBody?.includes("model") && responseBody?.includes("not exist")) ||
|
|
44
|
-
responseBody?.includes("not authorized to access this model") ||
|
|
45
|
-
false,
|
|
46
|
-
isRateLimited: statusCode === 429,
|
|
47
|
-
isTimeout: statusCode === 408 ||
|
|
48
|
-
statusCode === 504 ||
|
|
49
|
-
message?.toLowerCase().includes("timeout") ||
|
|
50
|
-
false,
|
|
51
|
-
statusCode,
|
|
52
|
-
provider,
|
|
53
|
-
model,
|
|
54
|
-
originalMessage: message,
|
|
55
|
-
responseBody,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
function detectMarkdownFormat(text) {
|
|
59
|
-
const markdownPatterns = [
|
|
60
|
-
/^```/m,
|
|
61
|
-
/^#{1,6}\s/m,
|
|
62
|
-
/^\s*[-*+]\s/m,
|
|
63
|
-
/^\s*\d+\.\s/m,
|
|
64
|
-
/\[.+\]\(.+\)/,
|
|
65
|
-
/^\s*>/m,
|
|
66
|
-
];
|
|
67
|
-
return markdownPatterns.some((pattern) => pattern.test(text));
|
|
68
|
-
}
|
|
69
|
-
export function parseNoObjectGeneratedError(error) {
|
|
70
|
-
try {
|
|
71
|
-
if (typeof NoObjectGeneratedError === "undefined" ||
|
|
72
|
-
typeof NoObjectGeneratedError.isInstance !== "function") {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
if (!NoObjectGeneratedError.isInstance(error))
|
|
76
|
-
return null;
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return null;
|
|
80
|
-
}
|
|
81
|
-
const rawText = error.text;
|
|
82
|
-
const isMarkdownFormat = rawText ? detectMarkdownFormat(rawText) : false;
|
|
83
|
-
const response = error.response
|
|
84
|
-
? {
|
|
85
|
-
id: error.response.id,
|
|
86
|
-
timestamp: error.response.timestamp,
|
|
87
|
-
modelId: error.response.modelId,
|
|
88
|
-
}
|
|
89
|
-
: undefined;
|
|
90
|
-
const usage = error.usage ?? undefined;
|
|
91
|
-
const result = { isNoObjectGeneratedError: true, isMarkdownFormat };
|
|
92
|
-
if (rawText !== undefined)
|
|
93
|
-
result.rawText = rawText;
|
|
94
|
-
if (error.cause instanceof Error)
|
|
95
|
-
result.cause = error.cause;
|
|
96
|
-
if (response !== undefined)
|
|
97
|
-
result.response = response;
|
|
98
|
-
if (usage !== undefined)
|
|
99
|
-
result.usage = usage;
|
|
100
|
-
return result;
|
|
101
|
-
}
|
|
102
|
-
export function wrapError(error, fallbackCode = EC.SYSTEM_UNKNOWN, userMessage) {
|
|
103
|
-
if (isAppError(error)) {
|
|
104
|
-
if (userMessage && userMessage !== error.userMessage) {
|
|
105
|
-
return new AppError({
|
|
106
|
-
code: error.code,
|
|
107
|
-
message: error.message,
|
|
108
|
-
userMessage,
|
|
109
|
-
cause: error.cause,
|
|
110
|
-
details: error.details,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
return error;
|
|
114
|
-
}
|
|
115
|
-
const originalError = toError(error);
|
|
116
|
-
const aiInfo = parseAISDKError(error);
|
|
117
|
-
if (aiInfo) {
|
|
118
|
-
const context = {
|
|
119
|
-
model: aiInfo.model,
|
|
120
|
-
provider: aiInfo.provider,
|
|
121
|
-
statusCode: aiInfo.statusCode,
|
|
122
|
-
responseBody: aiInfo.responseBody,
|
|
123
|
-
};
|
|
124
|
-
if (aiInfo.isModelNotFound) {
|
|
125
|
-
return createLLMError(EC.LLM_MODEL_NOT_FOUND, originalError, context);
|
|
126
|
-
}
|
|
127
|
-
if (aiInfo.isAuthError)
|
|
128
|
-
return createLLMError(EC.LLM_UNAUTHORIZED, originalError, context);
|
|
129
|
-
if (aiInfo.isRateLimited)
|
|
130
|
-
return createLLMError(EC.LLM_RATE_LIMITED, originalError, context);
|
|
131
|
-
if (aiInfo.isTimeout)
|
|
132
|
-
return createLLMError(EC.LLM_TIMEOUT, originalError, context);
|
|
133
|
-
return createLLMError(EC.LLM_GENERATION_FAILED, originalError, context);
|
|
134
|
-
}
|
|
135
|
-
const noObjectInfo = parseNoObjectGeneratedError(error);
|
|
136
|
-
if (noObjectInfo) {
|
|
137
|
-
return createStructuredOutputError(EC.LLM_RESPONSE_PARSE_ERROR, originalError, {
|
|
138
|
-
rawText: noObjectInfo.rawText,
|
|
139
|
-
isMarkdownFormat: noObjectInfo.isMarkdownFormat,
|
|
140
|
-
parseErrorMessage: noObjectInfo.cause?.message,
|
|
141
|
-
usage: noObjectInfo.usage,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
const message = originalError.message.toLowerCase();
|
|
145
|
-
if (message.includes("timeout") ||
|
|
146
|
-
message.includes("econnrefused") ||
|
|
147
|
-
message.includes("network") ||
|
|
148
|
-
message.includes("fetch failed")) {
|
|
149
|
-
if (message.includes("timeout"))
|
|
150
|
-
return createNetworkError(EC.NETWORK_TIMEOUT, originalError);
|
|
151
|
-
return createNetworkError(EC.NETWORK_CONNECTION_FAILED, originalError);
|
|
152
|
-
}
|
|
153
|
-
return new AppError({ code: fallbackCode, message: originalError.message, cause: originalError });
|
|
154
|
-
}
|
|
155
|
-
export function toError(error) {
|
|
156
|
-
if (error instanceof Error)
|
|
157
|
-
return error;
|
|
158
|
-
if (typeof error === "string")
|
|
159
|
-
return new Error(error);
|
|
160
|
-
if (typeof error === "object" && error !== null) {
|
|
161
|
-
const message = error.message ||
|
|
162
|
-
error.error ||
|
|
163
|
-
JSON.stringify(error);
|
|
164
|
-
return new Error(String(message));
|
|
165
|
-
}
|
|
166
|
-
return new Error(String(error));
|
|
167
|
-
}
|
|
168
|
-
export function extractErrorContext(error) {
|
|
169
|
-
const context = { errorCode: error.code, category: error.category };
|
|
170
|
-
if (error.cause)
|
|
171
|
-
context.originalError = error.cause.message;
|
|
172
|
-
if (error.details)
|
|
173
|
-
context.details = error.details;
|
|
174
|
-
return context;
|
|
175
|
-
}
|
|
176
|
-
export function getUserMessage(error) {
|
|
177
|
-
if (isAppError(error))
|
|
178
|
-
return error.userMessage;
|
|
179
|
-
if (error instanceof Error)
|
|
180
|
-
return "操作失败,请稍后重试";
|
|
181
|
-
return "发生未知错误,请稍后重试";
|
|
182
|
-
}
|
|
183
|
-
export function logError(context, error) {
|
|
184
|
-
console.error(`[${error.code}] ${context}:`, error.toLogString());
|
|
185
|
-
if (error.cause)
|
|
186
|
-
console.error("Original error:", error.cause);
|
|
187
|
-
}
|
|
188
|
-
//# sourceMappingURL=error-utils.js.map
|
|
1
|
+
import{NoObjectGeneratedError as e}from"ai";import{AppError as r,isAppError as o}from"./app-error.js";import{ErrorCode as s}from"./error-codes.js";import{createLLMError as t,createNetworkError as n,createStructuredOutputError as i}from"./error-factory.js";export function parseAISDKError(e){if(!e||"object"!=typeof e)return null;const r=e;if(!("AI_APICallError"===r.name||"APICallError"===r.name||"string"==typeof r.url&&"number"==typeof r.statusCode))return null;const o="number"==typeof r.statusCode?r.statusCode:void 0,s="string"==typeof r.responseBody?r.responseBody:void 0,t="string"==typeof r.url?r.url:void 0,n=r.message;let i,a;if(t&&(t.includes("openai.com")?i="openai":t.includes("anthropic.com")?i="anthropic":t.includes("dashscope.aliyuncs.com")?i="qwen":t.includes("openrouter.ai")?i="openrouter":t.includes("deepseek.com")?i="deepseek":t.includes("moonshot.cn")?i="moonshotai":t.includes("googleapis.com")&&(i="google")),s){const e=s.match(/model[`'":\s]+([^`'"}\s,]+)/i);e&&(a=e[1])}return{isAuthError:401===o||403===o,isModelNotFound:s?.includes("model")&&s?.includes("not exist")||s?.includes("not authorized to access this model")||!1,isRateLimited:429===o,isTimeout:408===o||504===o||n?.toLowerCase().includes("timeout")||!1,statusCode:o,provider:i,model:a,originalMessage:n,responseBody:s}}function a(e){return[/^```/m,/^#{1,6}\s/m,/^\s*[-*+]\s/m,/^\s*\d+\.\s/m,/\[.+\]\(.+\)/,/^\s*>/m].some(r=>r.test(e))}export function parseNoObjectGeneratedError(r){try{if(void 0===e||"function"!=typeof e.isInstance)return null;if(!e.isInstance(r))return null}catch{return null}const o=r.text,s=!!o&&a(o),t=r.response?{id:r.response.id,timestamp:r.response.timestamp,modelId:r.response.modelId}:void 0,n=r.usage??void 0,i={isNoObjectGeneratedError:!0,isMarkdownFormat:s};return void 0!==o&&(i.rawText=o),r.cause instanceof Error&&(i.cause=r.cause),void 0!==t&&(i.response=t),void 0!==n&&(i.usage=n),i}export function wrapError(e,a=s.SYSTEM_UNKNOWN,u){if(o(e))return u&&u!==e.userMessage?new r({code:e.code,message:e.message,userMessage:u,cause:e.cause,details:e.details}):e;const c=toError(e),d=parseAISDKError(e);if(d){const e={model:d.model,provider:d.provider,statusCode:d.statusCode,responseBody:d.responseBody};return d.isModelNotFound?t(s.LLM_MODEL_NOT_FOUND,c,e):d.isAuthError?t(s.LLM_UNAUTHORIZED,c,e):d.isRateLimited?t(s.LLM_RATE_LIMITED,c,e):d.isTimeout?t(s.LLM_TIMEOUT,c,e):t(s.LLM_GENERATION_FAILED,c,e)}const l=parseNoObjectGeneratedError(e);if(l)return i(s.LLM_RESPONSE_PARSE_ERROR,c,{rawText:l.rawText,isMarkdownFormat:l.isMarkdownFormat,parseErrorMessage:l.cause?.message,usage:l.usage});const m=c.message.toLowerCase();return m.includes("timeout")||m.includes("econnrefused")||m.includes("network")||m.includes("fetch failed")?m.includes("timeout")?n(s.NETWORK_TIMEOUT,c):n(s.NETWORK_CONNECTION_FAILED,c):new r({code:a,message:c.message,cause:c})}export function toError(e){if(e instanceof Error)return e;if("string"==typeof e)return new Error(e);if("object"==typeof e&&null!==e){const r=e.message||e.error||JSON.stringify(e);return new Error(String(r))}return new Error(String(e))}export function extractErrorContext(e){const r={errorCode:e.code,category:e.category};return e.cause&&(r.originalError=e.cause.message),e.details&&(r.details=e.details),r}export function getUserMessage(e){return o(e)?e.userMessage:e instanceof Error?"操作失败,请稍后重试":"发生未知错误,请稍后重试"}export function logError(e,r){console.error(`[${r.code}] ${e}:`,r.toLogString()),r.cause&&console.error("Original error:",r.cause)}
|
package/dist/errors/index.d.ts
CHANGED
|
@@ -6,4 +6,3 @@ export { createLLMError, createConfigError, createNetworkError, createValidation
|
|
|
6
6
|
export type { LLMErrorContext, StructuredOutputErrorContext } from "./error-factory.ts";
|
|
7
7
|
export { wrapError, toError, parseAISDKError, parseNoObjectGeneratedError, extractErrorContext, getUserMessage, logError, } from "./error-utils.ts";
|
|
8
8
|
export type { ErrorContext, NoObjectGeneratedErrorInfo } from "./error-utils.ts";
|
|
9
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/errors/index.js
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export { AppError, isAppError, isErrorCode, isErrorCategory, isLLMError, isConfigError, isNetworkError, isAuthError, } from "./app-error.js";
|
|
3
|
-
export { createLLMError, createConfigError, createNetworkError, createValidationError, createBusinessError, createSystemError, createStructuredOutputError, } from "./error-factory.js";
|
|
4
|
-
export { wrapError, toError, parseAISDKError, parseNoObjectGeneratedError, extractErrorContext, getUserMessage, logError, } from "./error-utils.js";
|
|
5
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
export{ErrorCode,ErrorCategory,ERROR_CODE_TO_CATEGORY,ERROR_USER_MESSAGES,getErrorCategory,getErrorUserMessage,isErrorInCategory}from"./error-codes.js";export{AppError,isAppError,isErrorCode,isErrorCategory,isLLMError,isConfigError,isNetworkError,isAuthError}from"./app-error.js";export{createLLMError,createConfigError,createNetworkError,createValidationError,createBusinessError,createSystemError,createStructuredOutputError}from"./error-factory.js";export{wrapError,toError,parseAISDKError,parseNoObjectGeneratedError,extractErrorContext,getUserMessage,logError}from"./error-utils.js";
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,12 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { generateReply } from "./tools/generate-reply.js";
|
|
3
|
-
import { syncBrandData } from "./tools/sync-brand-data.js";
|
|
4
|
-
const agent = defineAgent({
|
|
5
|
-
name: "smart-reply-agent",
|
|
6
|
-
tools: [generateReply, syncBrandData],
|
|
7
|
-
});
|
|
8
|
-
agent.listen().catch((err) => {
|
|
9
|
-
console.error("Fatal error:", err);
|
|
10
|
-
process.exit(1);
|
|
11
|
-
});
|
|
12
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
import{defineAgent as o}from"@roll-agent/sdk";import{generateReply as r}from"./tools/generate-reply.js";import{syncBrandData as t}from"./tools/sync-brand-data.js";const e=o({name:"smart-reply-agent",tools:[r,t]});e.listen().catch(o=>{console.error("Fatal error:",o),process.exit(1)});
|
package/dist/log-control.d.ts
CHANGED
package/dist/log-control.js
CHANGED
|
@@ -1,15 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Pipeline 运行期间(spinner 活跃时)抑制中间日志,调试信息改走 diagnostics。
|
|
3
|
-
*
|
|
4
|
-
* 注意:当前使用模块级标志,仅适用于串行调用场景(stdio MCP)。
|
|
5
|
-
* 若需并发安全,应改为 AsyncLocalStorage。
|
|
6
|
-
*/
|
|
7
|
-
let _suppress = false;
|
|
8
|
-
export function setSuppressVerboseLogs(value) {
|
|
9
|
-
_suppress = value;
|
|
10
|
-
}
|
|
11
|
-
export function verboseLog(...args) {
|
|
12
|
-
if (!_suppress)
|
|
13
|
-
console.error(...args);
|
|
14
|
-
}
|
|
15
|
-
//# sourceMappingURL=log-control.js.map
|
|
1
|
+
let e=!1;export function setSuppressVerboseLogs(o){e=o}export function verboseLog(...o){e||console.error(...o)}
|
|
@@ -1,176 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
export const AGE_ELIGIBILITY_STATUSES = ["pass", "fail", "unknown"];
|
|
3
|
-
const fallbackPolicy = {
|
|
4
|
-
enabled: false,
|
|
5
|
-
revealRange: false,
|
|
6
|
-
failStrategy: "礼貌说明不匹配,避免承诺",
|
|
7
|
-
unknownStrategy: "先核实年龄或资格条件",
|
|
8
|
-
passStrategy: "确认匹配后推进下一步",
|
|
9
|
-
allowRedirect: false,
|
|
10
|
-
redirectPriority: "low",
|
|
11
|
-
};
|
|
12
|
-
const JOB_LIST_PAGE_SIZE = 200;
|
|
13
|
-
function normalizeText(value) {
|
|
14
|
-
return (value ?? "").trim().toLowerCase();
|
|
15
|
-
}
|
|
16
|
-
function isRecord(value) {
|
|
17
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18
|
-
}
|
|
19
|
-
function firstText(value) {
|
|
20
|
-
if (typeof value === "string")
|
|
21
|
-
return value;
|
|
22
|
-
if (Array.isArray(value)) {
|
|
23
|
-
const first = value.find((item) => typeof item === "string");
|
|
24
|
-
return typeof first === "string" ? first : "";
|
|
25
|
-
}
|
|
26
|
-
return "";
|
|
27
|
-
}
|
|
28
|
-
function pickText(source, keys) {
|
|
29
|
-
for (const key of keys) {
|
|
30
|
-
if (key in source) {
|
|
31
|
-
const text = firstText(source[key]);
|
|
32
|
-
if (text)
|
|
33
|
-
return text;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return "";
|
|
37
|
-
}
|
|
38
|
-
function toNumber(value) {
|
|
39
|
-
if (typeof value === "number" && Number.isFinite(value))
|
|
40
|
-
return value;
|
|
41
|
-
if (typeof value === "string" && value.trim() !== "") {
|
|
42
|
-
const num = Number(value);
|
|
43
|
-
return Number.isFinite(num) ? num : null;
|
|
44
|
-
}
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
function buildAppliedStrategy(status, policy) {
|
|
48
|
-
const effective = policy ?? fallbackPolicy;
|
|
49
|
-
const strategy = status === "pass"
|
|
50
|
-
? effective.passStrategy
|
|
51
|
-
: status === "fail"
|
|
52
|
-
? effective.failStrategy
|
|
53
|
-
: effective.unknownStrategy;
|
|
54
|
-
return { ...effective, status, strategy };
|
|
55
|
-
}
|
|
56
|
-
export async function evaluateAgeEligibility({ age, brandAlias, cityName, regionName, strategy, }) {
|
|
57
|
-
const token = getDulidayToken();
|
|
58
|
-
const endpoint = getDulidayJobListEndpoint();
|
|
59
|
-
const summary = {
|
|
60
|
-
minAgeObserved: null,
|
|
61
|
-
maxAgeObserved: null,
|
|
62
|
-
matchedCount: 0,
|
|
63
|
-
total: 0,
|
|
64
|
-
};
|
|
65
|
-
if (!token) {
|
|
66
|
-
return {
|
|
67
|
-
status: "unknown",
|
|
68
|
-
summary,
|
|
69
|
-
appliedStrategy: buildAppliedStrategy("unknown", strategy),
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
if (!endpoint) {
|
|
73
|
-
return {
|
|
74
|
-
status: "unknown",
|
|
75
|
-
summary,
|
|
76
|
-
appliedStrategy: buildAppliedStrategy("unknown", strategy),
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
const payload = await fetchJobListPage(token, endpoint, 1, JOB_LIST_PAGE_SIZE, {
|
|
81
|
-
brandAlias: brandAlias ?? null,
|
|
82
|
-
cityName: cityName ?? null,
|
|
83
|
-
});
|
|
84
|
-
const { items, total } = extractResults(payload);
|
|
85
|
-
summary.total = total;
|
|
86
|
-
const hasAdditionalPages = total > items.length && items.length >= JOB_LIST_PAGE_SIZE;
|
|
87
|
-
const brandFilters = buildBrandCandidates(brandAlias, cityName)
|
|
88
|
-
.map((c) => normalizeText(c))
|
|
89
|
-
.filter(Boolean);
|
|
90
|
-
const cityFilters = buildCityCandidates(cityName)
|
|
91
|
-
.map((c) => normalizeText(c))
|
|
92
|
-
.filter(Boolean);
|
|
93
|
-
const regionFilter = normalizeText(regionName);
|
|
94
|
-
let anyRange = false;
|
|
95
|
-
let anyMatch = false;
|
|
96
|
-
for (const item of items) {
|
|
97
|
-
if (!isRecord(item))
|
|
98
|
-
continue;
|
|
99
|
-
const record = item;
|
|
100
|
-
const basicInfo = isRecord(record.basicInfo)
|
|
101
|
-
? record.basicInfo
|
|
102
|
-
: null;
|
|
103
|
-
const storeInfo = basicInfo && isRecord(basicInfo.storeInfo)
|
|
104
|
-
? basicInfo.storeInfo
|
|
105
|
-
: null;
|
|
106
|
-
const itemBrand = normalizeText(pickText(record, ["brandAlias", "brandName", "brand", "organizationName"]) ||
|
|
107
|
-
(basicInfo ? pickText(basicInfo, ["brandAlias", "brandName", "brand"]) : ""));
|
|
108
|
-
const itemCity = normalizeText(pickText(record, ["cityName", "storeCityName", "jobCityName"]) ||
|
|
109
|
-
(storeInfo ? pickText(storeInfo, ["storeCityName", "cityName"]) : ""));
|
|
110
|
-
const itemRegion = normalizeText(pickText(record, ["regionName", "storeRegionName", "districtName"]) ||
|
|
111
|
-
(storeInfo ? pickText(storeInfo, ["storeRegionName", "regionName", "districtName"]) : ""));
|
|
112
|
-
const itemAddress = normalizeText(pickText(record, ["storeAddress", "jobAddress", "address", "storeExactAddress"]) ||
|
|
113
|
-
(storeInfo ? pickText(storeInfo, ["storeAddress", "storeExactAddress", "address"]) : ""));
|
|
114
|
-
if (brandFilters.length > 0 &&
|
|
115
|
-
!brandFilters.some((f) => itemBrand.includes(f) || f.includes(itemBrand))) {
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
if (cityFilters.length > 0 && !cityFilters.some((f) => itemCity.includes(f)))
|
|
119
|
-
continue;
|
|
120
|
-
if (regionFilter &&
|
|
121
|
-
!itemRegion.includes(regionFilter) &&
|
|
122
|
-
!itemAddress.includes(regionFilter)) {
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
summary.matchedCount += 1;
|
|
126
|
-
const hiringRequirement = isRecord(record.hiringRequirement)
|
|
127
|
-
? record.hiringRequirement
|
|
128
|
-
: undefined;
|
|
129
|
-
const requirement = isRecord(hiringRequirement?.basicPersonalRequirements)
|
|
130
|
-
? hiringRequirement.basicPersonalRequirements
|
|
131
|
-
: undefined;
|
|
132
|
-
const minAge = toNumber(requirement?.minAge ?? record.minAge);
|
|
133
|
-
const maxAge = toNumber(requirement?.maxAge ?? record.maxAge);
|
|
134
|
-
if (minAge !== null) {
|
|
135
|
-
anyRange = true;
|
|
136
|
-
summary.minAgeObserved =
|
|
137
|
-
summary.minAgeObserved === null ? minAge : Math.min(summary.minAgeObserved, minAge);
|
|
138
|
-
}
|
|
139
|
-
if (maxAge !== null) {
|
|
140
|
-
anyRange = true;
|
|
141
|
-
summary.maxAgeObserved =
|
|
142
|
-
summary.maxAgeObserved === null ? maxAge : Math.max(summary.maxAgeObserved, maxAge);
|
|
143
|
-
}
|
|
144
|
-
if (typeof age === "number") {
|
|
145
|
-
const belowMin = minAge !== null && age < minAge;
|
|
146
|
-
const aboveMax = maxAge !== null && age > maxAge;
|
|
147
|
-
if (!belowMin && !aboveMax)
|
|
148
|
-
anyMatch = true;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
if (typeof age !== "number" || summary.matchedCount === 0 || !anyRange) {
|
|
152
|
-
return {
|
|
153
|
-
status: "unknown",
|
|
154
|
-
summary,
|
|
155
|
-
appliedStrategy: buildAppliedStrategy("unknown", strategy),
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
if (hasAdditionalPages) {
|
|
159
|
-
return {
|
|
160
|
-
status: "unknown",
|
|
161
|
-
summary,
|
|
162
|
-
appliedStrategy: buildAppliedStrategy("unknown", strategy),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
const status = anyMatch ? "pass" : "fail";
|
|
166
|
-
return { status, summary, appliedStrategy: buildAppliedStrategy(status, strategy) };
|
|
167
|
-
}
|
|
168
|
-
catch {
|
|
169
|
-
return {
|
|
170
|
-
status: "unknown",
|
|
171
|
-
summary,
|
|
172
|
-
appliedStrategy: buildAppliedStrategy("unknown", strategy),
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
//# sourceMappingURL=age-eligibility.js.map
|
|
1
|
+
import{fetchJobListPage as e,getDulidayToken as n,getDulidayJobListEndpoint as t,extractResults as r,buildCityCandidates as a,buildBrandCandidates as i}from"../services/duliday-api.js";export const AGE_ELIGIBILITY_STATUSES=["pass","fail","unknown"];const s={enabled:!1,revealRange:!1,failStrategy:"礼貌说明不匹配,避免承诺",unknownStrategy:"先核实年龄或资格条件",passStrategy:"确认匹配后推进下一步",allowRedirect:!1,redirectPriority:"low"},o=200;function u(e){return(e??"").trim().toLowerCase()}function l(e){return null!==e&&"object"==typeof e&&!Array.isArray(e)}function m(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 d(e,n){for(const t of n)if(t in e){const n=m(e[t]);if(n)return n}return""}function c(e){if("number"==typeof e&&Number.isFinite(e))return e;if("string"==typeof e&&""!==e.trim()){const n=Number(e);return Number.isFinite(n)?n:null}return null}function f(e,n){const t=n??s,r="pass"===e?t.passStrategy:"fail"===e?t.failStrategy:t.unknownStrategy;return{...t,status:e,strategy:r}}export async function evaluateAgeEligibility({age:s,brandAlias:m,cityName:g,regionName:y,strategy:b}){const p=n(),A=t(),N={minAgeObserved:null,maxAgeObserved:null,matchedCount:0,total:0};if(!p)return{status:"unknown",summary:N,appliedStrategy:f("unknown",b)};if(!A)return{status:"unknown",summary:N,appliedStrategy:f("unknown",b)};try{const n=await e(p,A,1,o,{brandAlias:m??null,cityName:g??null}),{items:t,total:w}=r(n);N.total=w;const S=w>t.length&&t.length>=o,k=i(m,g).map(e=>u(e)).filter(Boolean),v=a(g).map(e=>u(e)).filter(Boolean),h=u(y);let x=!1,I=!1;for(const e of t){if(!l(e))continue;const n=e,t=l(n.basicInfo)?n.basicInfo:null,r=t&&l(t.storeInfo)?t.storeInfo:null,a=u(d(n,["brandAlias","brandName","brand","organizationName"])||(t?d(t,["brandAlias","brandName","brand"]):"")),i=u(d(n,["cityName","storeCityName","jobCityName"])||(r?d(r,["storeCityName","cityName"]):"")),o=u(d(n,["regionName","storeRegionName","districtName"])||(r?d(r,["storeRegionName","regionName","districtName"]):"")),m=u(d(n,["storeAddress","jobAddress","address","storeExactAddress"])||(r?d(r,["storeAddress","storeExactAddress","address"]):""));if(k.length>0&&!k.some(e=>a.includes(e)||e.includes(a)))continue;if(v.length>0&&!v.some(e=>i.includes(e)))continue;if(h&&!o.includes(h)&&!m.includes(h))continue;N.matchedCount+=1;const f=l(n.hiringRequirement)?n.hiringRequirement:void 0,g=l(f?.basicPersonalRequirements)?f.basicPersonalRequirements:void 0,y=c(g?.minAge??n.minAge),b=c(g?.maxAge??n.maxAge);if(null!==y&&(x=!0,N.minAgeObserved=null===N.minAgeObserved?y:Math.min(N.minAgeObserved,y)),null!==b&&(x=!0,N.maxAgeObserved=null===N.maxAgeObserved?b:Math.max(N.maxAgeObserved,b)),"number"==typeof s){null!==y&&s<y||null!==b&&s>b||(I=!0)}}if("number"!=typeof s||0===N.matchedCount||!x)return{status:"unknown",summary:N,appliedStrategy:f("unknown",b)};if(S)return{status:"unknown",summary:N,appliedStrategy:f("unknown",b)};const O=I?"pass":"fail";return{status:O,summary:N,appliedStrategy:f(O,b)}}catch{return{status:"unknown",summary:N,appliedStrategy:f("unknown",b)}}}
|
|
@@ -1,31 +1 @@
|
|
|
1
|
-
const
|
|
2
|
-
{ key: "age", label: "年龄" },
|
|
3
|
-
{ key: "gender", label: "性别" },
|
|
4
|
-
{ key: "education", label: "学历" },
|
|
5
|
-
{ key: "experience", label: "工作经验" },
|
|
6
|
-
{ key: "expectedSalary", label: "期望薪资" },
|
|
7
|
-
{ key: "expectedLocation", label: "期望位置" },
|
|
8
|
-
{ key: "jobAddress", label: "工作地址" },
|
|
9
|
-
{ key: "healthCertificate", label: "健康证" },
|
|
10
|
-
];
|
|
11
|
-
export function buildKnownCandidateContext(candidateInfo) {
|
|
12
|
-
if (!candidateInfo)
|
|
13
|
-
return { factsText: "", knownFieldNames: [] };
|
|
14
|
-
const fields = [];
|
|
15
|
-
for (const { key, label } of CANDIDATE_FIELD_MAP) {
|
|
16
|
-
const raw = candidateInfo[key];
|
|
17
|
-
if (typeof raw === "string" && raw.trim()) {
|
|
18
|
-
fields.push({ label, value: raw.trim() });
|
|
19
|
-
}
|
|
20
|
-
else if (typeof raw === "boolean") {
|
|
21
|
-
fields.push({ label, value: raw ? "是" : "否" });
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
if (fields.length === 0)
|
|
25
|
-
return { factsText: "", knownFieldNames: [] };
|
|
26
|
-
return {
|
|
27
|
-
factsText: fields.map((f) => `${f.label}:${f.value}`).join("\n"),
|
|
28
|
-
knownFieldNames: fields.map((f) => f.label),
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=candidate-context.js.map
|
|
1
|
+
const e=[{key:"age",label:"年龄"},{key:"gender",label:"性别"},{key:"education",label:"学历"},{key:"experience",label:"工作经验"},{key:"expectedSalary",label:"期望薪资"},{key:"expectedLocation",label:"期望位置"},{key:"jobAddress",label:"工作地址"},{key:"healthCertificate",label:"健康证"}];export function buildKnownCandidateContext(l){if(!l)return{factsText:"",knownFieldNames:[]};const a=[];for(const{key:t,label:n}of e){const e=l[t];"string"==typeof e&&e.trim()?a.push({label:n,value:e.trim()}):"boolean"==typeof e&&a.push({label:n,value:e?"是":"否"})}return 0===a.length?{factsText:"",knownFieldNames:[]}:{factsText:a.map(e=>`${e.label}:${e.value}`).join("\n"),knownFieldNames:a.map(e=>e.label)}}
|
|
@@ -3,4 +3,3 @@ import type { CandidateInfo } from "../types/zhipin.ts";
|
|
|
3
3
|
export declare function parseAge(ageStr?: string): string | undefined;
|
|
4
4
|
export declare function resolveCandidateAge(turnPlan: TurnPlan, candidateInfo?: CandidateInfo): number | undefined;
|
|
5
5
|
export declare function resolveRegionName(turnPlan: TurnPlan, candidateInfo?: CandidateInfo): string | undefined;
|
|
6
|
-
//# sourceMappingURL=candidate-utils.d.ts.map
|
|
@@ -1,33 +1 @@
|
|
|
1
|
-
export function parseAge(
|
|
2
|
-
if (!ageStr)
|
|
3
|
-
return undefined;
|
|
4
|
-
const match = ageStr.match(/(\d+)/);
|
|
5
|
-
return match ? match[1] : ageStr;
|
|
6
|
-
}
|
|
7
|
-
export function resolveCandidateAge(turnPlan, candidateInfo) {
|
|
8
|
-
if (typeof candidateInfo?.age === "number") {
|
|
9
|
-
return candidateInfo.age;
|
|
10
|
-
}
|
|
11
|
-
const parsedAge = parseAge(candidateInfo?.age);
|
|
12
|
-
if (parsedAge) {
|
|
13
|
-
const age = Number(parsedAge);
|
|
14
|
-
if (Number.isFinite(age))
|
|
15
|
-
return age;
|
|
16
|
-
}
|
|
17
|
-
if (typeof turnPlan.extractedInfo.specificAge === "number") {
|
|
18
|
-
return turnPlan.extractedInfo.specificAge;
|
|
19
|
-
}
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
export function resolveRegionName(turnPlan, candidateInfo) {
|
|
23
|
-
const district = turnPlan.extractedInfo.mentionedDistricts?.[0]?.district;
|
|
24
|
-
if (district)
|
|
25
|
-
return district;
|
|
26
|
-
const location = turnPlan.extractedInfo.mentionedLocations?.[0]?.location;
|
|
27
|
-
if (location)
|
|
28
|
-
return location;
|
|
29
|
-
if (candidateInfo?.jobAddress)
|
|
30
|
-
return candidateInfo.jobAddress;
|
|
31
|
-
return undefined;
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=candidate-utils.js.map
|
|
1
|
+
export function parseAge(e){if(!e)return;const t=e.match(/(\d+)/);return t?t[1]:e}export function resolveCandidateAge(e,t){if("number"==typeof t?.age)return t.age;const n=parseAge(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}export function resolveRegionName(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)}
|