chatlab-cli 0.0.0 → 0.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/CHANGELOG.md +51 -0
- package/LICENSE +661 -0
- package/README.md +115 -3
- package/bin/chatlab.mjs +2 -0
- package/dist/chunk-2AIOU3PW.mjs +26 -0
- package/dist/chunk-2AIOU3PW.mjs.map +1 -0
- package/dist/chunk-DL3BFEAH.mjs +144 -0
- package/dist/chunk-DL3BFEAH.mjs.map +1 -0
- package/dist/chunk-JMRDNHIR.mjs +18601 -0
- package/dist/chunk-JMRDNHIR.mjs.map +1 -0
- package/dist/chunk-OC73KSMV.mjs +395 -0
- package/dist/chunk-OC73KSMV.mjs.map +1 -0
- package/dist/chunk-P4N5GEFF.mjs +411 -0
- package/dist/chunk-P4N5GEFF.mjs.map +1 -0
- package/dist/chunk-PF4QFHC6.mjs +3375 -0
- package/dist/chunk-PF4QFHC6.mjs.map +1 -0
- package/dist/chunk-YAOFJ73U.mjs +1393 -0
- package/dist/chunk-YAOFJ73U.mjs.map +1 -0
- package/dist/cli.mjs +15 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/http-PQEOFGJK.mjs +32 -0
- package/dist/http-PQEOFGJK.mjs.map +1 -0
- package/dist/import-UR2IE2O7.mjs +39 -0
- package/dist/import-UR2IE2O7.mjs.map +1 -0
- package/dist/index.mjs +24 -0
- package/dist/index.mjs.map +1 -0
- package/dist/mcp-4XCDZ5PU.mjs +406 -0
- package/dist/mcp-4XCDZ5PU.mjs.map +1 -0
- package/dist/src-ZELOFE7P.mjs +327 -0
- package/dist/src-ZELOFE7P.mjs.map +1 -0
- package/dist/stream-import-RP3XB6NM.mjs +31 -0
- package/dist/stream-import-RP3XB6NM.mjs.map +1 -0
- package/dist-web/assets/DebugToolsPanel-dUV6pVqD.css +1 -0
- package/dist-web/assets/DebugToolsPanel.vue_vue_type_script_setup_true_lang-BuOhHrGp.js +155 -0
- package/dist-web/assets/EChartWordcloud-DcC12j9S.js +1 -0
- package/dist-web/assets/MessageExportModal-CUS9nnwi.js +1 -0
- package/dist-web/assets/electron-8qi0d92j.js +1 -0
- package/dist-web/assets/electron-BHjOx6B6.js +1 -0
- package/dist-web/assets/electron-CTK4NJag.js +1 -0
- package/dist-web/assets/electron-DPsrYwTt.js +1 -0
- package/dist-web/assets/electron-DfpXsXsS.js +1 -0
- package/dist-web/assets/electron-DvcSSc-D.js +1 -0
- package/dist-web/assets/electron-HoVzpIVc.js +1 -0
- package/dist-web/assets/fetch-BS4SlQjA.js +1 -0
- package/dist-web/assets/fetch-CJ8Q4qM2.js +1 -0
- package/dist-web/assets/fetch-CclRWOHf.js +1 -0
- package/dist-web/assets/fetch-DgQkWW73.js +3 -0
- package/dist-web/assets/fetch-DvfIZxuz.js +17 -0
- package/dist-web/assets/fetch-W43zfemj.js +1 -0
- package/dist-web/assets/http-CeXMt-Fv.js +1 -0
- package/dist-web/assets/index-68UnLyFT.js +173 -0
- package/dist-web/assets/index-BKFGuwJu.css +1 -0
- package/dist-web/assets/index-CCE1zef2.js +2 -0
- package/dist-web/assets/index-CLGv8Den.css +1 -0
- package/dist-web/assets/index-CUTe0Sc3.js +16 -0
- package/dist-web/assets/index-CmU6x-uJ.css +1 -0
- package/dist-web/assets/index-CzR1sElx.css +1 -0
- package/dist-web/assets/index-D3siJhmm.js +163 -0
- package/dist-web/assets/index-n2XUUgti.js +7 -0
- package/dist-web/assets/sse-CACcGGWv.js +2 -0
- package/dist-web/assets/vendor-echarts-BXkS9r5W.js +11 -0
- package/dist-web/assets/vendor-echarts-wordcloud-CmDVLUv0.js +1 -0
- package/dist-web/assets/vendor-nuxt-ui-D1aReMtR.js +15 -0
- package/dist-web/assets/vendor-reka-ui-CW2cIgMu.js +11 -0
- package/dist-web/assets/vendor-snapdom-XnBoh1gd.js +8 -0
- package/dist-web/assets/vendor-zrender-B6SpLIkk.js +8 -0
- package/dist-web/assets/web-DOZKbBMQ.js +1 -0
- package/dist-web/index.html +18 -0
- package/package.json +71 -15
- package/cli.js +0 -3
|
@@ -0,0 +1,1393 @@
|
|
|
1
|
+
import { createRequire as __createRequire } from 'module';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
4
|
+
const require = __createRequire(import.meta.url);
|
|
5
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = __pathDirname(__filename);
|
|
7
|
+
import {
|
|
8
|
+
executeParameterizedSql,
|
|
9
|
+
executeReadonlySql,
|
|
10
|
+
getChatOverview,
|
|
11
|
+
getConversationBetween,
|
|
12
|
+
getDailyActivity,
|
|
13
|
+
getDatabaseSchema,
|
|
14
|
+
getHourlyActivity,
|
|
15
|
+
getMemberActivity,
|
|
16
|
+
getMemberNameHistory,
|
|
17
|
+
getMembers,
|
|
18
|
+
getMembersWithAliases,
|
|
19
|
+
getMessageContext,
|
|
20
|
+
getRecentMessages,
|
|
21
|
+
getSearchMessageContext,
|
|
22
|
+
getSessionMessages,
|
|
23
|
+
getSessionMeta,
|
|
24
|
+
getSessionOverview,
|
|
25
|
+
getSessionSummaries,
|
|
26
|
+
getWeekdayActivity,
|
|
27
|
+
searchMessagesLike,
|
|
28
|
+
searchSessions
|
|
29
|
+
} from "./chunk-JMRDNHIR.mjs";
|
|
30
|
+
|
|
31
|
+
// ../../packages/tools/src/definitions/search.ts
|
|
32
|
+
var inputSchema = {
|
|
33
|
+
type: "object",
|
|
34
|
+
properties: {
|
|
35
|
+
keyword: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "\u641C\u7D22\u5173\u952E\u8BCD"
|
|
38
|
+
},
|
|
39
|
+
limit: {
|
|
40
|
+
type: "number",
|
|
41
|
+
description: "\u8FD4\u56DE\u7684\u6700\u5927\u6D88\u606F\u6761\u6570",
|
|
42
|
+
default: 50
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
required: ["keyword"]
|
|
46
|
+
};
|
|
47
|
+
async function handler(params, context) {
|
|
48
|
+
const keyword = params.keyword;
|
|
49
|
+
const limit = params.limit || 50;
|
|
50
|
+
const result = await context.dataProvider.searchMessages([keyword], {
|
|
51
|
+
timeFilter: context.timeFilter,
|
|
52
|
+
limit
|
|
53
|
+
});
|
|
54
|
+
const data = {
|
|
55
|
+
total: result.total,
|
|
56
|
+
returned: result.messages.length,
|
|
57
|
+
hasMore: result.messages.length < result.total,
|
|
58
|
+
messages: result.messages.map((m) => ({
|
|
59
|
+
sender: m.senderName,
|
|
60
|
+
content: m.content,
|
|
61
|
+
time: new Date(m.timestamp * 1e3).toISOString()
|
|
62
|
+
}))
|
|
63
|
+
};
|
|
64
|
+
return {
|
|
65
|
+
content: JSON.stringify(data),
|
|
66
|
+
data,
|
|
67
|
+
rawMessages: result.messages
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
var searchTool = {
|
|
71
|
+
name: "search_keyword",
|
|
72
|
+
description: "\u5728\u804A\u5929\u8BB0\u5F55\u4E2D\u641C\u7D22\u5173\u952E\u8BCD\uFF0C\u8FD4\u56DE\u5339\u914D\u7684\u6D88\u606F\u5217\u8868\uFF08\u53D1\u9001\u8005\u3001\u5185\u5BB9\u3001\u65F6\u95F4\uFF09",
|
|
73
|
+
inputSchema,
|
|
74
|
+
handler,
|
|
75
|
+
category: "core",
|
|
76
|
+
truncationStrategy: "keep_first"
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// ../../packages/tools/src/definitions/sql-query.ts
|
|
80
|
+
var inputSchema2 = {
|
|
81
|
+
type: "object",
|
|
82
|
+
properties: {
|
|
83
|
+
sql: {
|
|
84
|
+
type: "string",
|
|
85
|
+
description: "\u8981\u6267\u884C\u7684 SELECT SQL \u67E5\u8BE2\u8BED\u53E5"
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
required: ["sql"]
|
|
89
|
+
};
|
|
90
|
+
async function handler2(params, context) {
|
|
91
|
+
const sql = params.sql;
|
|
92
|
+
try {
|
|
93
|
+
const result = await context.dataProvider.executeSql(sql);
|
|
94
|
+
return {
|
|
95
|
+
content: JSON.stringify(result),
|
|
96
|
+
data: result
|
|
97
|
+
};
|
|
98
|
+
} catch (err) {
|
|
99
|
+
return {
|
|
100
|
+
content: JSON.stringify({ error: err instanceof Error ? err.message : String(err) })
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
var schemaInputSchema = {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: {}
|
|
107
|
+
};
|
|
108
|
+
async function schemaHandler(_params, context) {
|
|
109
|
+
const schema = await context.dataProvider.getSchema();
|
|
110
|
+
return {
|
|
111
|
+
content: JSON.stringify({ tables: schema }),
|
|
112
|
+
data: schema
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
var sqlQueryTool = {
|
|
116
|
+
name: "execute_sql",
|
|
117
|
+
description: "\u5BF9\u804A\u5929\u6570\u636E\u5E93\u6267\u884C\u53EA\u8BFB SELECT \u67E5\u8BE2\u3002\u4F7F\u7528\u524D\u53EF\u5148\u8C03\u7528 get_schema \u67E5\u770B\u8868\u7ED3\u6784\u3002",
|
|
118
|
+
inputSchema: inputSchema2,
|
|
119
|
+
handler: handler2
|
|
120
|
+
};
|
|
121
|
+
var schemaTool = {
|
|
122
|
+
name: "get_schema",
|
|
123
|
+
description: "\u67E5\u770B\u804A\u5929\u6570\u636E\u5E93\u7684\u8868\u7ED3\u6784\uFF08\u6240\u6709\u8868\u7684 CREATE TABLE \u8BED\u53E5\uFF09",
|
|
124
|
+
inputSchema: schemaInputSchema,
|
|
125
|
+
handler: schemaHandler
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
// ../../packages/tools/src/definitions/session-info.ts
|
|
129
|
+
var inputSchema3 = {
|
|
130
|
+
type: "object",
|
|
131
|
+
properties: {
|
|
132
|
+
include_members: {
|
|
133
|
+
type: "boolean",
|
|
134
|
+
description: "\u662F\u5426\u5305\u542B\u6210\u5458\u5217\u8868\uFF08\u9ED8\u8BA4 false\uFF09",
|
|
135
|
+
default: false
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
function handler3(params, context) {
|
|
140
|
+
const db = context.db;
|
|
141
|
+
const meta = getSessionMeta(db);
|
|
142
|
+
const overview = getSessionOverview(db);
|
|
143
|
+
const includeMembers = params.include_members;
|
|
144
|
+
const data = { ...meta, ...overview };
|
|
145
|
+
if (includeMembers) {
|
|
146
|
+
data.members = getMembers(db);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
content: JSON.stringify(data),
|
|
150
|
+
data
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
var sessionInfoTool = {
|
|
154
|
+
name: "get_session_info",
|
|
155
|
+
description: "\u83B7\u53D6\u5F53\u524D\u4F1A\u8BDD\u7684\u8BE6\u7EC6\u4FE1\u606F\uFF0C\u5305\u62EC\u540D\u79F0\u3001\u5E73\u53F0\u3001\u6D88\u606F\u603B\u6570\u3001\u6210\u5458\u6570\u3001\u65F6\u95F4\u8303\u56F4\u7B49",
|
|
156
|
+
inputSchema: inputSchema3,
|
|
157
|
+
handler: handler3
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// ../../packages/tools/src/definitions/sessions.ts
|
|
161
|
+
var inputSchema4 = {
|
|
162
|
+
type: "object",
|
|
163
|
+
properties: {
|
|
164
|
+
keyword: {
|
|
165
|
+
type: "string",
|
|
166
|
+
description: "\u6309\u540D\u79F0\u7B5B\u9009\u4F1A\u8BDD\uFF08\u53EF\u9009\uFF09"
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
function handler4(_params, context) {
|
|
171
|
+
const keyword = _params.keyword?.toLowerCase();
|
|
172
|
+
const sessionIds = context.listSessionIds();
|
|
173
|
+
const sessions = sessionIds.map((id) => {
|
|
174
|
+
const db = context.openDb(id);
|
|
175
|
+
if (!db) return null;
|
|
176
|
+
const meta = getSessionMeta(db);
|
|
177
|
+
if (!meta) return null;
|
|
178
|
+
if (keyword && !meta.name.toLowerCase().includes(keyword)) return null;
|
|
179
|
+
const overview = getSessionOverview(db);
|
|
180
|
+
return { id, ...meta, ...overview };
|
|
181
|
+
}).filter(Boolean);
|
|
182
|
+
return {
|
|
183
|
+
content: JSON.stringify({ total: sessions.length, sessions }),
|
|
184
|
+
data: sessions
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
var sessionsListTool = {
|
|
188
|
+
name: "list_sessions",
|
|
189
|
+
description: "\u5217\u51FA\u6240\u6709\u53EF\u7528\u7684\u804A\u5929\u4F1A\u8BDD\uFF0C\u8FD4\u56DE\u4F1A\u8BDD\u540D\u79F0\u3001\u5E73\u53F0\u3001\u6D88\u606F\u6570\u7B49\u57FA\u672C\u4FE1\u606F",
|
|
190
|
+
inputSchema: inputSchema4,
|
|
191
|
+
handler: handler4
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
// ../../packages/tools/src/utils/format.ts
|
|
195
|
+
function isChineseLocale(locale) {
|
|
196
|
+
return locale?.startsWith("zh") ?? false;
|
|
197
|
+
}
|
|
198
|
+
var i18nTexts = {
|
|
199
|
+
allTime: { zh: "\u5168\u90E8\u65F6\u95F4", en: "All time" },
|
|
200
|
+
noContent: { zh: "[\u65E0\u5185\u5BB9]", en: "[No content]" },
|
|
201
|
+
memberNotFound: { zh: "\u672A\u627E\u5230\u8BE5\u6210\u5458", en: "Member not found" },
|
|
202
|
+
untilNow: { zh: "\u81F3\u4ECA", en: "Present" },
|
|
203
|
+
noChangeRecord: { zh: "\u65E0\u53D8\u66F4\u8BB0\u5F55", en: "No change record" },
|
|
204
|
+
noConversation: { zh: "\u672A\u627E\u5230\u8FD9\u4E24\u4EBA\u4E4B\u95F4\u7684\u5BF9\u8BDD", en: "No conversation found between these two members" },
|
|
205
|
+
noMessageContext: { zh: "\u672A\u627E\u5230\u6307\u5B9A\u7684\u6D88\u606F\u6216\u4E0A\u4E0B\u6587", en: "Message or context not found" },
|
|
206
|
+
messages: { zh: "\u6761", en: "" },
|
|
207
|
+
alias: { zh: "\u522B\u540D", en: "Alias" }
|
|
208
|
+
};
|
|
209
|
+
function t(key, locale) {
|
|
210
|
+
const text = i18nTexts[key];
|
|
211
|
+
if (typeof text === "object" && "zh" in text && "en" in text) {
|
|
212
|
+
return isChineseLocale(locale) ? text.zh : text.en;
|
|
213
|
+
}
|
|
214
|
+
return "";
|
|
215
|
+
}
|
|
216
|
+
function formatTimeRange(timeFilter, locale) {
|
|
217
|
+
if (!timeFilter) return t("allTime", locale);
|
|
218
|
+
const localeStr = isChineseLocale(locale) ? "zh-CN" : "en-US";
|
|
219
|
+
return {
|
|
220
|
+
start: new Date(timeFilter.startTs * 1e3).toLocaleString(localeStr),
|
|
221
|
+
end: new Date(timeFilter.endTs * 1e3).toLocaleString(localeStr)
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function formatMessageCompact(msg, locale) {
|
|
225
|
+
const localeStr = isChineseLocale(locale) ? "zh-CN" : "en-US";
|
|
226
|
+
const time = new Date(msg.timestamp * 1e3).toLocaleString(localeStr);
|
|
227
|
+
let content = msg.content || t("noContent", locale);
|
|
228
|
+
if (content.length > 200) {
|
|
229
|
+
content = content.slice(0, 200) + "...";
|
|
230
|
+
}
|
|
231
|
+
return `${time} ${msg.senderName}: ${content}`;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ../../packages/tools/src/definitions/chat-overview.ts
|
|
235
|
+
var inputSchema5 = {
|
|
236
|
+
type: "object",
|
|
237
|
+
properties: {
|
|
238
|
+
top_n: { type: "number", description: "\u8FD4\u56DE\u6D3B\u8DC3\u5EA6\u6700\u9AD8\u7684\u524D N \u4E2A\u6210\u5458\uFF0C\u9ED8\u8BA4 10" }
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
async function handler5(params, context) {
|
|
242
|
+
const { locale } = context;
|
|
243
|
+
const topN = params.top_n || 10;
|
|
244
|
+
const result = await context.dataProvider.getChatOverview(topN);
|
|
245
|
+
if (!result) {
|
|
246
|
+
const msg = isChineseLocale(locale) ? "\u65E0\u6CD5\u83B7\u53D6\u804A\u5929\u6982\u89C8" : "Unable to get chat overview";
|
|
247
|
+
return { content: msg, data: { error: msg } };
|
|
248
|
+
}
|
|
249
|
+
const msgSuffix = isChineseLocale(locale) ? "\u6761" : "";
|
|
250
|
+
const lines = [
|
|
251
|
+
`name: ${result.name}`,
|
|
252
|
+
`platform: ${result.platform}`,
|
|
253
|
+
`type: ${result.type}`,
|
|
254
|
+
`totalMessages: ${result.totalMessages}`,
|
|
255
|
+
`totalMembers: ${result.totalMembers}`
|
|
256
|
+
];
|
|
257
|
+
if (result.firstMessageTs != null && result.lastMessageTs != null) {
|
|
258
|
+
const start = new Date(result.firstMessageTs * 1e3).toLocaleDateString();
|
|
259
|
+
const end = new Date(result.lastMessageTs * 1e3).toLocaleDateString();
|
|
260
|
+
lines.push(`timeRange: ${start} ~ ${end}`);
|
|
261
|
+
}
|
|
262
|
+
if (result.topMembers.length > 0) {
|
|
263
|
+
lines.push(`topMembers:`);
|
|
264
|
+
for (let i = 0; i < result.topMembers.length; i++) {
|
|
265
|
+
const m = result.topMembers[i];
|
|
266
|
+
const pct = result.totalMessages > 0 ? (m.count / result.totalMessages * 100).toFixed(1) : "0";
|
|
267
|
+
lines.push(`${i + 1}. ${m.name} ${m.count}${msgSuffix}(${pct}%)`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return { content: lines.join("\n"), data: result };
|
|
271
|
+
}
|
|
272
|
+
var chatOverviewTool = {
|
|
273
|
+
name: "get_chat_overview",
|
|
274
|
+
description: "\u83B7\u53D6\u804A\u5929\u6982\u89C8\u4FE1\u606F\uFF0C\u5305\u62EC\u804A\u5929\u540D\u79F0\u3001\u5E73\u53F0\u3001\u603B\u6D88\u606F\u6570\u3001\u603B\u6210\u5458\u6570\u3001\u65F6\u95F4\u8303\u56F4\u548C\u6D3B\u8DC3\u6210\u5458\u6392\u884C",
|
|
275
|
+
inputSchema: inputSchema5,
|
|
276
|
+
handler: handler5,
|
|
277
|
+
category: "core"
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// ../../packages/tools/src/utils/time-params.ts
|
|
281
|
+
function parseExtendedTimeParams(params, contextTimeFilter) {
|
|
282
|
+
if (params.start_time || params.end_time) {
|
|
283
|
+
let startTs;
|
|
284
|
+
let endTs;
|
|
285
|
+
if (params.start_time) {
|
|
286
|
+
const startDate = new Date(params.start_time.replace(" ", "T"));
|
|
287
|
+
if (!isNaN(startDate.getTime())) {
|
|
288
|
+
startTs = Math.floor(startDate.getTime() / 1e3);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (params.end_time) {
|
|
292
|
+
const endDate = new Date(params.end_time.replace(" ", "T"));
|
|
293
|
+
if (!isNaN(endDate.getTime())) {
|
|
294
|
+
endTs = Math.floor(endDate.getTime() / 1e3);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (startTs !== void 0 || endTs !== void 0) {
|
|
298
|
+
return {
|
|
299
|
+
startTs: startTs ?? 0,
|
|
300
|
+
endTs: endTs ?? Math.floor(Date.now() / 1e3)
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return contextTimeFilter;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// ../../packages/tools/src/utils/schemas.ts
|
|
308
|
+
var timeParamProperties = {
|
|
309
|
+
start_time: {
|
|
310
|
+
type: "string",
|
|
311
|
+
description: "\u8D77\u59CB\u65F6\u95F4, \u683C\u5F0F: YYYY-MM-DD HH:mm"
|
|
312
|
+
},
|
|
313
|
+
end_time: {
|
|
314
|
+
type: "string",
|
|
315
|
+
description: "\u7ED3\u675F\u65F6\u95F4, \u683C\u5F0F: YYYY-MM-DD HH:mm"
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// ../../packages/tools/src/definitions/search-messages.ts
|
|
320
|
+
var inputSchema6 = {
|
|
321
|
+
type: "object",
|
|
322
|
+
properties: {
|
|
323
|
+
keywords: { type: "array", items: { type: "string" }, description: "\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868" },
|
|
324
|
+
sender_id: { type: "number", description: "\u6309\u53D1\u9001\u8005 ID \u8FC7\u6EE4\uFF08\u901A\u8FC7 get_members \u83B7\u53D6\uFF09" },
|
|
325
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u7684\u6700\u5927\u6D88\u606F\u6761\u6570" },
|
|
326
|
+
...timeParamProperties
|
|
327
|
+
},
|
|
328
|
+
required: ["keywords"]
|
|
329
|
+
};
|
|
330
|
+
async function handler6(params, context) {
|
|
331
|
+
const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context;
|
|
332
|
+
const keywords = params.keywords;
|
|
333
|
+
const limit = Math.min(maxMessagesLimit || params.limit || 1e3, 5e4);
|
|
334
|
+
const effectiveTimeFilter = parseExtendedTimeParams(params, contextTimeFilter);
|
|
335
|
+
const result = await context.dataProvider.searchMessages(keywords, {
|
|
336
|
+
timeFilter: effectiveTimeFilter,
|
|
337
|
+
limit,
|
|
338
|
+
senderId: params.sender_id
|
|
339
|
+
});
|
|
340
|
+
const contextBefore = context.searchContextBefore ?? 2;
|
|
341
|
+
const contextAfter = context.searchContextAfter ?? 2;
|
|
342
|
+
let finalMessages = result.messages;
|
|
343
|
+
if ((contextBefore > 0 || contextAfter > 0) && result.messages.length > 0) {
|
|
344
|
+
const hitIds = result.messages.map((m) => m.id).filter((id) => id != null);
|
|
345
|
+
if (hitIds.length > 0) {
|
|
346
|
+
finalMessages = await context.dataProvider.getSearchMessageContext(hitIds, contextBefore, contextAfter);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
const data = {
|
|
350
|
+
total: result.total,
|
|
351
|
+
returned: finalMessages.length,
|
|
352
|
+
timeRange: formatTimeRange(effectiveTimeFilter, locale),
|
|
353
|
+
rawMessages: finalMessages
|
|
354
|
+
};
|
|
355
|
+
return { content: JSON.stringify(data), data, rawMessages: finalMessages };
|
|
356
|
+
}
|
|
357
|
+
var searchMessagesTool = {
|
|
358
|
+
name: "search_messages",
|
|
359
|
+
description: "\u6839\u636E\u5173\u952E\u8BCD\u641C\u7D22\u7FA4\u804A\u8BB0\u5F55\u3002\u9002\u7528\u4E8E\u7528\u6237\u60F3\u8981\u67E5\u627E\u7279\u5B9A\u8BDD\u9898\u3001\u5173\u952E\u8BCD\u76F8\u5173\u7684\u804A\u5929\u5185\u5BB9\u3002\u53EF\u4EE5\u6307\u5B9A\u65F6\u95F4\u8303\u56F4\u548C\u53D1\u9001\u8005\u6765\u7B5B\u9009\u6D88\u606F\u3002",
|
|
360
|
+
inputSchema: inputSchema6,
|
|
361
|
+
handler: handler6,
|
|
362
|
+
category: "core",
|
|
363
|
+
truncationStrategy: "keep_first"
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// ../../packages/tools/src/definitions/deep-search-messages.ts
|
|
367
|
+
var inputSchema7 = {
|
|
368
|
+
type: "object",
|
|
369
|
+
properties: {
|
|
370
|
+
keywords: { type: "array", items: { type: "string" }, description: "\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868" },
|
|
371
|
+
sender_id: { type: "number", description: "\u6309\u53D1\u9001\u8005 ID \u8FC7\u6EE4\uFF08\u901A\u8FC7 get_members \u83B7\u53D6\uFF09" },
|
|
372
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u7684\u6700\u5927\u6D88\u606F\u6761\u6570" },
|
|
373
|
+
...timeParamProperties
|
|
374
|
+
},
|
|
375
|
+
required: ["keywords"]
|
|
376
|
+
};
|
|
377
|
+
async function handler7(params, context) {
|
|
378
|
+
const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context;
|
|
379
|
+
const keywords = params.keywords;
|
|
380
|
+
const limit = Math.min(maxMessagesLimit || params.limit || 1e3, 5e4);
|
|
381
|
+
const effectiveTimeFilter = parseExtendedTimeParams(params, contextTimeFilter);
|
|
382
|
+
const result = await context.dataProvider.deepSearchMessages(keywords, {
|
|
383
|
+
timeFilter: effectiveTimeFilter,
|
|
384
|
+
limit,
|
|
385
|
+
senderId: params.sender_id
|
|
386
|
+
});
|
|
387
|
+
const contextBefore = context.searchContextBefore ?? 2;
|
|
388
|
+
const contextAfter = context.searchContextAfter ?? 2;
|
|
389
|
+
let finalMessages = result.messages;
|
|
390
|
+
if ((contextBefore > 0 || contextAfter > 0) && result.messages.length > 0) {
|
|
391
|
+
const hitIds = result.messages.map((m) => m.id).filter((id) => id != null);
|
|
392
|
+
if (hitIds.length > 0) {
|
|
393
|
+
finalMessages = await context.dataProvider.getSearchMessageContext(hitIds, contextBefore, contextAfter);
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const data = {
|
|
397
|
+
total: result.total,
|
|
398
|
+
returned: finalMessages.length,
|
|
399
|
+
timeRange: formatTimeRange(effectiveTimeFilter, locale),
|
|
400
|
+
rawMessages: finalMessages
|
|
401
|
+
};
|
|
402
|
+
return { content: JSON.stringify(data), data, rawMessages: finalMessages };
|
|
403
|
+
}
|
|
404
|
+
var deepSearchMessagesTool = {
|
|
405
|
+
name: "deep_search_messages",
|
|
406
|
+
description: "\u6DF1\u5EA6\u641C\u7D22\u6D88\u606F\uFF08LIKE \u5B50\u4E32\u5339\u914D\uFF0C\u901F\u5EA6\u8F83\u6162\u4F46\u4E0D\u4F1A\u9057\u6F0F\uFF09\uFF0C\u9002\u7528\u4E8E\u5168\u6587\u641C\u7D22\u7CBE\u786E\u5339\u914D\u6216 FTS \u641C\u7D22\u65E0\u7ED3\u679C\u65F6\u7684\u8865\u5145\u641C\u7D22\u3002",
|
|
407
|
+
inputSchema: inputSchema7,
|
|
408
|
+
handler: handler7,
|
|
409
|
+
category: "core",
|
|
410
|
+
truncationStrategy: "keep_first"
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// ../../packages/tools/src/definitions/get-message-context.ts
|
|
414
|
+
var inputSchema8 = {
|
|
415
|
+
type: "object",
|
|
416
|
+
properties: {
|
|
417
|
+
message_ids: { type: "array", items: { type: "number" }, description: "\u6D88\u606F ID \u5217\u8868" },
|
|
418
|
+
context_size: { type: "number", description: "\u6BCF\u6761\u6D88\u606F\u524D\u540E\u83B7\u53D6\u7684\u4E0A\u4E0B\u6587\u6761\u6570\uFF0C\u9ED8\u8BA4 20" }
|
|
419
|
+
},
|
|
420
|
+
required: ["message_ids"]
|
|
421
|
+
};
|
|
422
|
+
async function handler8(params, context) {
|
|
423
|
+
const { locale } = context;
|
|
424
|
+
const messageIds = params.message_ids;
|
|
425
|
+
const contextSize = params.context_size || 20;
|
|
426
|
+
const messages = await context.dataProvider.getMessageContext(messageIds, contextSize);
|
|
427
|
+
if (messages.length === 0) {
|
|
428
|
+
const data2 = {
|
|
429
|
+
error: t("noMessageContext", locale),
|
|
430
|
+
messageIds
|
|
431
|
+
};
|
|
432
|
+
return { content: JSON.stringify(data2), data: data2 };
|
|
433
|
+
}
|
|
434
|
+
const data = {
|
|
435
|
+
totalMessages: messages.length,
|
|
436
|
+
contextSize,
|
|
437
|
+
requestedMessageIds: messageIds,
|
|
438
|
+
rawMessages: messages
|
|
439
|
+
};
|
|
440
|
+
return { content: JSON.stringify(data), data, rawMessages: messages };
|
|
441
|
+
}
|
|
442
|
+
var getMessageContextTool = {
|
|
443
|
+
name: "get_message_context",
|
|
444
|
+
description: "\u6839\u636E\u6D88\u606F ID \u83B7\u53D6\u524D\u540E\u7684\u4E0A\u4E0B\u6587\u6D88\u606F\u3002\u9002\u7528\u4E8E\u9700\u8981\u67E5\u770B\u67D0\u6761\u6D88\u606F\u524D\u540E\u804A\u5929\u5185\u5BB9\u7684\u573A\u666F\u3002",
|
|
445
|
+
inputSchema: inputSchema8,
|
|
446
|
+
handler: handler8,
|
|
447
|
+
category: "core",
|
|
448
|
+
truncationStrategy: "keep_last"
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
// ../../packages/tools/src/definitions/search-sessions.ts
|
|
452
|
+
var inputSchema9 = {
|
|
453
|
+
type: "object",
|
|
454
|
+
properties: {
|
|
455
|
+
keywords: { type: "array", items: { type: "string" }, description: "\u641C\u7D22\u5173\u952E\u8BCD\u5217\u8868" },
|
|
456
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u7684\u6700\u5927\u4F1A\u8BDD\u6570\uFF0C\u9ED8\u8BA4 20" },
|
|
457
|
+
...timeParamProperties
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
async function handler9(params, context) {
|
|
461
|
+
const { locale, timeFilter: contextTimeFilter } = context;
|
|
462
|
+
const limit = params.limit || 20;
|
|
463
|
+
const effectiveTimeFilter = parseExtendedTimeParams(params, contextTimeFilter);
|
|
464
|
+
const sessions = await context.dataProvider.searchSessions(
|
|
465
|
+
params.keywords,
|
|
466
|
+
effectiveTimeFilter,
|
|
467
|
+
limit,
|
|
468
|
+
5
|
|
469
|
+
);
|
|
470
|
+
if (sessions.length === 0) {
|
|
471
|
+
const data2 = {
|
|
472
|
+
total: 0,
|
|
473
|
+
message: isChineseLocale(locale) ? "\u672A\u627E\u5230\u5339\u914D\u7684\u4F1A\u8BDD" : "No matching sessions found"
|
|
474
|
+
};
|
|
475
|
+
return { content: JSON.stringify(data2), data: data2 };
|
|
476
|
+
}
|
|
477
|
+
const localeStr = isChineseLocale(locale) ? "zh-CN" : "en-US";
|
|
478
|
+
const msgSuffix = isChineseLocale(locale) ? "\u6761\u6D88\u606F" : " messages";
|
|
479
|
+
const completeLabel = isChineseLocale(locale) ? "\u5B8C\u6574\u4F1A\u8BDD" : "complete";
|
|
480
|
+
const data = {
|
|
481
|
+
total: sessions.length,
|
|
482
|
+
timeRange: formatTimeRange(effectiveTimeFilter, locale),
|
|
483
|
+
sessions: sessions.map((s) => {
|
|
484
|
+
const startTime = new Date(s.startTs * 1e3).toLocaleString(localeStr);
|
|
485
|
+
const endTime = new Date(s.endTs * 1e3).toLocaleString(localeStr);
|
|
486
|
+
const completeTag = s.isComplete ? ` [${completeLabel}]` : "";
|
|
487
|
+
return {
|
|
488
|
+
sessionId: s.id,
|
|
489
|
+
time: `${startTime} ~ ${endTime}`,
|
|
490
|
+
messageCount: `${s.messageCount}${msgSuffix}${completeTag}`,
|
|
491
|
+
preview: s.previewMessages.map((m) => formatMessageCompact(m, locale))
|
|
492
|
+
};
|
|
493
|
+
})
|
|
494
|
+
};
|
|
495
|
+
return { content: JSON.stringify(data), data };
|
|
496
|
+
}
|
|
497
|
+
var searchSessionsTool = {
|
|
498
|
+
name: "search_sessions",
|
|
499
|
+
description: "\u641C\u7D22\u804A\u5929\u4F1A\u8BDD\uFF08\u5BF9\u8BDD\u6BB5\u843D\uFF09\u3002\u4F1A\u8BDD\u662F\u6839\u636E\u6D88\u606F\u65F6\u95F4\u95F4\u9694\u81EA\u52A8\u5207\u5206\u7684\u5BF9\u8BDD\u5355\u5143\u3002\u8FD4\u56DE\u5339\u914D\u7684\u4F1A\u8BDD\u5217\u8868\u53CA\u6BCF\u4E2A\u4F1A\u8BDD\u7684\u524D5\u6761\u6D88\u606F\u9884\u89C8\u3002",
|
|
500
|
+
inputSchema: inputSchema9,
|
|
501
|
+
handler: handler9,
|
|
502
|
+
category: "core"
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// ../../packages/tools/src/definitions/get-session-messages.ts
|
|
506
|
+
var inputSchema10 = {
|
|
507
|
+
type: "object",
|
|
508
|
+
properties: {
|
|
509
|
+
session_id: { type: "number", description: "\u4F1A\u8BDD ID\uFF08\u901A\u8FC7 search_sessions \u83B7\u53D6\uFF09" },
|
|
510
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u7684\u6700\u5927\u6D88\u606F\u6761\u6570" }
|
|
511
|
+
},
|
|
512
|
+
required: ["session_id"]
|
|
513
|
+
};
|
|
514
|
+
async function handler10(params, context) {
|
|
515
|
+
const { locale, maxMessagesLimit } = context;
|
|
516
|
+
const limit = maxMessagesLimit || params.limit || 1e3;
|
|
517
|
+
const result = await context.dataProvider.getSessionMessages(params.session_id, limit);
|
|
518
|
+
if (!result) {
|
|
519
|
+
const data2 = {
|
|
520
|
+
error: isChineseLocale(locale) ? "\u672A\u627E\u5230\u6307\u5B9A\u7684\u4F1A\u8BDD" : "Session not found",
|
|
521
|
+
sessionId: params.session_id
|
|
522
|
+
};
|
|
523
|
+
return { content: JSON.stringify(data2), data: data2 };
|
|
524
|
+
}
|
|
525
|
+
const localeStr = isChineseLocale(locale) ? "zh-CN" : "en-US";
|
|
526
|
+
const startTime = new Date(result.startTs * 1e3).toLocaleString(localeStr);
|
|
527
|
+
const endTime = new Date(result.endTs * 1e3).toLocaleString(localeStr);
|
|
528
|
+
const rawMessages = result.messages.map((m) => ({
|
|
529
|
+
id: m.id,
|
|
530
|
+
senderName: m.senderName,
|
|
531
|
+
content: m.content,
|
|
532
|
+
timestamp: m.timestamp
|
|
533
|
+
}));
|
|
534
|
+
const data = {
|
|
535
|
+
sessionId: result.sessionId,
|
|
536
|
+
time: `${startTime} ~ ${endTime}`,
|
|
537
|
+
messageCount: result.messageCount,
|
|
538
|
+
returnedCount: result.returnedCount,
|
|
539
|
+
participants: result.participants,
|
|
540
|
+
rawMessages
|
|
541
|
+
};
|
|
542
|
+
return { content: JSON.stringify(data), data, rawMessages };
|
|
543
|
+
}
|
|
544
|
+
var getSessionMessagesTool = {
|
|
545
|
+
name: "get_session_messages",
|
|
546
|
+
description: "\u83B7\u53D6\u6307\u5B9A\u4F1A\u8BDD\u7684\u5B8C\u6574\u6D88\u606F\u5217\u8868\u3002\u7528\u4E8E\u5728 search_sessions \u627E\u5230\u76F8\u5173\u4F1A\u8BDD\u540E\uFF0C\u83B7\u53D6\u8BE5\u4F1A\u8BDD\u7684\u5B8C\u6574\u4E0A\u4E0B\u6587\u3002",
|
|
547
|
+
inputSchema: inputSchema10,
|
|
548
|
+
handler: handler10,
|
|
549
|
+
category: "core",
|
|
550
|
+
truncationStrategy: "keep_last"
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
// ../../packages/tools/src/definitions/get-members.ts
|
|
554
|
+
var inputSchema11 = {
|
|
555
|
+
type: "object",
|
|
556
|
+
properties: {
|
|
557
|
+
search: { type: "string", description: "\u6309\u540D\u79F0/\u522B\u540D/\u5E73\u53F0ID\u641C\u7D22\u8FC7\u6EE4" },
|
|
558
|
+
limit: { type: "number", description: "\u6700\u5927\u8FD4\u56DE\u6570\u91CF" }
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
async function handler11(params, context) {
|
|
562
|
+
const { locale } = context;
|
|
563
|
+
const members = await context.dataProvider.getMembers();
|
|
564
|
+
let filteredMembers = members;
|
|
565
|
+
if (params.search) {
|
|
566
|
+
const keyword = params.search.toLowerCase();
|
|
567
|
+
filteredMembers = members.filter((m) => {
|
|
568
|
+
if (m.groupNickname && m.groupNickname.toLowerCase().includes(keyword)) return true;
|
|
569
|
+
if (m.accountName && m.accountName.toLowerCase().includes(keyword)) return true;
|
|
570
|
+
if (m.platformId.includes(keyword)) return true;
|
|
571
|
+
if (m.aliases.some((alias) => alias.toLowerCase().includes(keyword))) return true;
|
|
572
|
+
return false;
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
if (params.limit && params.limit > 0) {
|
|
576
|
+
filteredMembers = filteredMembers.slice(0, params.limit);
|
|
577
|
+
}
|
|
578
|
+
const msgSuffix = isChineseLocale(locale) ? "\u6761" : "";
|
|
579
|
+
const aliasLabel = t("alias", locale);
|
|
580
|
+
const data = {
|
|
581
|
+
totalMembers: members.length,
|
|
582
|
+
returnedMembers: filteredMembers.length,
|
|
583
|
+
members: filteredMembers.map((m) => {
|
|
584
|
+
const displayName = m.groupNickname || m.accountName || m.platformId;
|
|
585
|
+
const aliasStr = m.aliases.length > 0 ? `|${aliasLabel}:${m.aliases.join(",")}` : "";
|
|
586
|
+
return `${m.id}|${m.platformId}|${displayName}|${m.messageCount}${msgSuffix}${aliasStr}`;
|
|
587
|
+
})
|
|
588
|
+
};
|
|
589
|
+
return { content: JSON.stringify(data), data };
|
|
590
|
+
}
|
|
591
|
+
var getMembersTool = {
|
|
592
|
+
name: "get_members",
|
|
593
|
+
description: '\u83B7\u53D6\u6210\u5458\u5217\u8868\uFF0C\u5305\u62EC\u6210\u5458\u7684\u57FA\u672C\u4FE1\u606F\u3001\u522B\u540D\u548C\u6D88\u606F\u7EDF\u8BA1\u3002\u9002\u7528\u4E8E\u67E5\u8BE2"\u6709\u54EA\u4E9B\u4EBA"\u3001"\u67D0\u4EBA\u7684\u522B\u540D\u662F\u4EC0\u4E48"\u7B49\u95EE\u9898\u3002',
|
|
594
|
+
inputSchema: inputSchema11,
|
|
595
|
+
handler: handler11,
|
|
596
|
+
category: "core"
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
// ../../packages/tools/src/definitions/member-stats.ts
|
|
600
|
+
var inputSchema12 = {
|
|
601
|
+
type: "object",
|
|
602
|
+
properties: {
|
|
603
|
+
top: {
|
|
604
|
+
type: "number",
|
|
605
|
+
description: "\u8FD4\u56DE\u524D N \u4E2A\u6D3B\u8DC3\u6210\u5458",
|
|
606
|
+
default: 20
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
async function handler12(params, context) {
|
|
611
|
+
const top = params.top || 20;
|
|
612
|
+
const members = await context.dataProvider.getMemberStats({ timeFilter: context.timeFilter, top });
|
|
613
|
+
const data = {
|
|
614
|
+
total: members.length,
|
|
615
|
+
members: members.map((m) => ({
|
|
616
|
+
name: m.name,
|
|
617
|
+
messageCount: m.messageCount,
|
|
618
|
+
percentage: m.percentage
|
|
619
|
+
}))
|
|
620
|
+
};
|
|
621
|
+
return {
|
|
622
|
+
content: JSON.stringify(data),
|
|
623
|
+
data
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
var memberStatsTool = {
|
|
627
|
+
name: "get_member_stats",
|
|
628
|
+
description: "\u83B7\u53D6\u6210\u5458\u6D3B\u8DC3\u5EA6\u6392\u884C\uFF0C\u5305\u62EC\u6D88\u606F\u6570\u91CF\u548C\u5360\u6BD4",
|
|
629
|
+
inputSchema: inputSchema12,
|
|
630
|
+
handler: handler12,
|
|
631
|
+
category: "core"
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
// ../../packages/tools/src/definitions/time-stats.ts
|
|
635
|
+
var inputSchema13 = {
|
|
636
|
+
type: "object",
|
|
637
|
+
properties: {
|
|
638
|
+
type: {
|
|
639
|
+
type: "string",
|
|
640
|
+
description: "\u7EDF\u8BA1\u7C7B\u578B\uFF1Ahourly\uFF08\u6309\u5C0F\u65F6\uFF09\u3001weekday\uFF08\u6309\u661F\u671F\uFF09\u3001daily\uFF08\u6309\u5929\uFF09",
|
|
641
|
+
enum: ["hourly", "weekday", "daily"],
|
|
642
|
+
default: "hourly"
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
};
|
|
646
|
+
async function handler13(params, context) {
|
|
647
|
+
const type = params.type || "hourly";
|
|
648
|
+
const data = await context.dataProvider.getTimeStats(type, { timeFilter: context.timeFilter });
|
|
649
|
+
return {
|
|
650
|
+
content: JSON.stringify({ type, data }),
|
|
651
|
+
data
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
var timeStatsTool = {
|
|
655
|
+
name: "get_time_stats",
|
|
656
|
+
description: "\u83B7\u53D6\u804A\u5929\u6D3B\u8DC3\u65F6\u6BB5\u5206\u5E03\uFF08\u6309\u5C0F\u65F6/\u661F\u671F/\u6BCF\u65E5\u8D8B\u52BF\uFF09",
|
|
657
|
+
inputSchema: inputSchema13,
|
|
658
|
+
handler: handler13,
|
|
659
|
+
category: "core"
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// ../../packages/tools/src/definitions/recent-messages.ts
|
|
663
|
+
var inputSchema14 = {
|
|
664
|
+
type: "object",
|
|
665
|
+
properties: {
|
|
666
|
+
limit: {
|
|
667
|
+
type: "number",
|
|
668
|
+
description: "\u8FD4\u56DE\u7684\u6D88\u606F\u6761\u6570",
|
|
669
|
+
default: 100
|
|
670
|
+
},
|
|
671
|
+
...timeParamProperties
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
async function handler14(params, context) {
|
|
675
|
+
const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context;
|
|
676
|
+
const limit = maxMessagesLimit || params.limit || 100;
|
|
677
|
+
const effectiveTimeFilter = parseExtendedTimeParams(params, contextTimeFilter);
|
|
678
|
+
const result = await context.dataProvider.getRecentMessages({ timeFilter: effectiveTimeFilter, limit });
|
|
679
|
+
const data = {
|
|
680
|
+
total: result.total,
|
|
681
|
+
returned: result.messages.length,
|
|
682
|
+
timeRange: formatTimeRange(effectiveTimeFilter, locale),
|
|
683
|
+
rawMessages: result.messages
|
|
684
|
+
};
|
|
685
|
+
return {
|
|
686
|
+
content: JSON.stringify(data),
|
|
687
|
+
data,
|
|
688
|
+
rawMessages: result.messages
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
var recentMessagesTool = {
|
|
692
|
+
name: "get_recent_messages",
|
|
693
|
+
description: '\u83B7\u53D6\u6307\u5B9A\u65F6\u95F4\u6BB5\u5185\u7684\u7FA4\u804A\u6D88\u606F\u3002\u9002\u7528\u4E8E\u56DE\u7B54"\u6700\u8FD1\u5927\u5BB6\u804A\u4E86\u4EC0\u4E48"\u7B49\u6982\u89C8\u6027\u95EE\u9898\u3002\u652F\u6301\u7CBE\u786E\u5230\u5206\u949F\u7EA7\u522B\u7684\u65F6\u95F4\u67E5\u8BE2\u3002',
|
|
694
|
+
inputSchema: inputSchema14,
|
|
695
|
+
handler: handler14,
|
|
696
|
+
category: "core",
|
|
697
|
+
truncationStrategy: "keep_last"
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
// ../../packages/tools/src/definitions/get-member-name-history.ts
|
|
701
|
+
var inputSchema15 = {
|
|
702
|
+
type: "object",
|
|
703
|
+
properties: {
|
|
704
|
+
member_id: { type: "number", description: "\u6210\u5458 ID\uFF08\u901A\u8FC7 get_members \u83B7\u53D6\uFF09" }
|
|
705
|
+
},
|
|
706
|
+
required: ["member_id"]
|
|
707
|
+
};
|
|
708
|
+
async function handler15(params, context) {
|
|
709
|
+
const { locale } = context;
|
|
710
|
+
const memberId = params.member_id;
|
|
711
|
+
const members = await context.dataProvider.getMembers();
|
|
712
|
+
const member = members.find((m) => m.id === memberId);
|
|
713
|
+
if (!member) {
|
|
714
|
+
const data2 = {
|
|
715
|
+
error: t("memberNotFound", locale),
|
|
716
|
+
member_id: memberId
|
|
717
|
+
};
|
|
718
|
+
return { content: JSON.stringify(data2), data: data2 };
|
|
719
|
+
}
|
|
720
|
+
const history = await context.dataProvider.getMemberNameHistory(memberId);
|
|
721
|
+
const localeStr = isChineseLocale(locale) ? "zh-CN" : "en-US";
|
|
722
|
+
const untilNow = t("untilNow", locale);
|
|
723
|
+
const formatHistory = (h) => {
|
|
724
|
+
const start = new Date(h.startTs * 1e3).toLocaleDateString(localeStr);
|
|
725
|
+
const end = h.endTs ? new Date(h.endTs * 1e3).toLocaleDateString(localeStr) : untilNow;
|
|
726
|
+
return `${h.name} (${start} ~ ${end})`;
|
|
727
|
+
};
|
|
728
|
+
const accountNames = history.filter((h) => h.nameType === "account_name").map(formatHistory);
|
|
729
|
+
const groupNicknames = history.filter((h) => h.nameType === "group_nickname").map(formatHistory);
|
|
730
|
+
const displayName = member.groupNickname || member.accountName || member.platformId;
|
|
731
|
+
const aliasLabel = t("alias", locale);
|
|
732
|
+
const aliasStr = member.aliases.length > 0 ? `|${aliasLabel}:${member.aliases.join(",")}` : "";
|
|
733
|
+
const noChangeRecord = t("noChangeRecord", locale);
|
|
734
|
+
const data = {
|
|
735
|
+
member: `${member.id}|${member.platformId}|${displayName}${aliasStr}`,
|
|
736
|
+
accountNameHistory: accountNames.length > 0 ? accountNames : noChangeRecord,
|
|
737
|
+
groupNicknameHistory: groupNicknames.length > 0 ? groupNicknames : noChangeRecord
|
|
738
|
+
};
|
|
739
|
+
return { content: JSON.stringify(data), data };
|
|
740
|
+
}
|
|
741
|
+
var getMemberNameHistoryTool = {
|
|
742
|
+
name: "get_member_name_history",
|
|
743
|
+
description: '\u83B7\u53D6\u6210\u5458\u7684\u6635\u79F0\u53D8\u66F4\u5386\u53F2\u8BB0\u5F55\u3002\u9002\u7528\u4E8E\u56DE\u7B54"\u67D0\u4EBA\u4EE5\u524D\u53EB\u4EC0\u4E48\u540D\u5B57"\u3001"\u67D0\u4EBA\u7684\u6635\u79F0\u53D8\u5316"\u7B49\u95EE\u9898\u3002',
|
|
744
|
+
inputSchema: inputSchema15,
|
|
745
|
+
handler: handler15,
|
|
746
|
+
category: "analysis"
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
// ../../packages/tools/src/definitions/get-conversation-between.ts
|
|
750
|
+
var inputSchema16 = {
|
|
751
|
+
type: "object",
|
|
752
|
+
properties: {
|
|
753
|
+
member_id_1: { type: "number", description: "\u7B2C\u4E00\u4E2A\u6210\u5458\u7684 ID\uFF08\u901A\u8FC7 get_members \u83B7\u53D6\uFF09" },
|
|
754
|
+
member_id_2: { type: "number", description: "\u7B2C\u4E8C\u4E2A\u6210\u5458\u7684 ID\uFF08\u901A\u8FC7 get_members \u83B7\u53D6\uFF09" },
|
|
755
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u7684\u6700\u5927\u6D88\u606F\u6761\u6570" },
|
|
756
|
+
...timeParamProperties
|
|
757
|
+
},
|
|
758
|
+
required: ["member_id_1", "member_id_2"]
|
|
759
|
+
};
|
|
760
|
+
async function handler16(params, context) {
|
|
761
|
+
const { locale, timeFilter: contextTimeFilter, maxMessagesLimit } = context;
|
|
762
|
+
const limit = maxMessagesLimit || params.limit || 100;
|
|
763
|
+
const effectiveTimeFilter = parseExtendedTimeParams(params, contextTimeFilter);
|
|
764
|
+
const result = await context.dataProvider.getConversationBetween(
|
|
765
|
+
params.member_id_1,
|
|
766
|
+
params.member_id_2,
|
|
767
|
+
effectiveTimeFilter,
|
|
768
|
+
limit
|
|
769
|
+
);
|
|
770
|
+
if (result.messages.length === 0) {
|
|
771
|
+
const data2 = {
|
|
772
|
+
error: t("noConversation", locale),
|
|
773
|
+
member1Id: params.member_id_1,
|
|
774
|
+
member2Id: params.member_id_2
|
|
775
|
+
};
|
|
776
|
+
return { content: JSON.stringify(data2), data: data2 };
|
|
777
|
+
}
|
|
778
|
+
const data = {
|
|
779
|
+
total: result.total,
|
|
780
|
+
returned: result.messages.length,
|
|
781
|
+
member1: result.member1Name,
|
|
782
|
+
member2: result.member2Name,
|
|
783
|
+
timeRange: formatTimeRange(effectiveTimeFilter, locale),
|
|
784
|
+
rawMessages: result.messages
|
|
785
|
+
};
|
|
786
|
+
return { content: JSON.stringify(data), data, rawMessages: result.messages };
|
|
787
|
+
}
|
|
788
|
+
var getConversationBetweenTool = {
|
|
789
|
+
name: "get_conversation_between",
|
|
790
|
+
description: '\u83B7\u53D6\u4E24\u4E2A\u7FA4\u6210\u5458\u4E4B\u95F4\u7684\u5BF9\u8BDD\u8BB0\u5F55\u3002\u9002\u7528\u4E8E\u56DE\u7B54"A\u548CB\u4E4B\u95F4\u804A\u4E86\u4EC0\u4E48"\u7B49\u95EE\u9898\u3002\u9700\u8981\u5148\u901A\u8FC7 get_members \u83B7\u53D6\u6210\u5458 ID\u3002',
|
|
791
|
+
inputSchema: inputSchema16,
|
|
792
|
+
handler: handler16,
|
|
793
|
+
category: "analysis",
|
|
794
|
+
truncationStrategy: "keep_last"
|
|
795
|
+
};
|
|
796
|
+
|
|
797
|
+
// ../../packages/tools/src/definitions/get-session-summaries.ts
|
|
798
|
+
var inputSchema17 = {
|
|
799
|
+
type: "object",
|
|
800
|
+
properties: {
|
|
801
|
+
keywords: { type: "array", items: { type: "string" }, description: "\u6309\u5173\u952E\u8BCD\u8FC7\u6EE4\u6458\u8981\u5185\u5BB9" },
|
|
802
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u7684\u6700\u5927\u4F1A\u8BDD\u6570\uFF0C\u9ED8\u8BA4 20" },
|
|
803
|
+
...timeParamProperties
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
async function handler17(params, context) {
|
|
807
|
+
const { locale, timeFilter: contextTimeFilter } = context;
|
|
808
|
+
const limit = params.limit || 20;
|
|
809
|
+
const effectiveTimeFilter = parseExtendedTimeParams(params, contextTimeFilter);
|
|
810
|
+
const sessions = await context.dataProvider.getSessionSummaries({
|
|
811
|
+
limit: limit * 2,
|
|
812
|
+
timeFilter: effectiveTimeFilter
|
|
813
|
+
});
|
|
814
|
+
if (!sessions || sessions.length === 0) {
|
|
815
|
+
const data2 = {
|
|
816
|
+
message: isChineseLocale(locale) ? '\u672A\u627E\u5230\u5E26\u6458\u8981\u7684\u4F1A\u8BDD\u3002\u53EF\u80FD\u8FD8\u6CA1\u6709\u751F\u6210\u6458\u8981\uFF0C\u8BF7\u5728\u4F1A\u8BDD\u65F6\u95F4\u7EBF\u4E2D\u70B9\u51FB"\u6279\u91CF\u751F\u6210"\u6309\u94AE\u3002' : "No sessions with summaries found. Summaries may not have been generated yet."
|
|
817
|
+
};
|
|
818
|
+
return { content: JSON.stringify(data2), data: data2 };
|
|
819
|
+
}
|
|
820
|
+
let filteredSessions = sessions;
|
|
821
|
+
const keywords = params.keywords;
|
|
822
|
+
if (keywords && keywords.length > 0) {
|
|
823
|
+
const lowerKeywords = keywords.map((k) => k.toLowerCase());
|
|
824
|
+
filteredSessions = sessions.filter(
|
|
825
|
+
(s) => lowerKeywords.some((keyword) => s.summary?.toLowerCase().includes(keyword))
|
|
826
|
+
);
|
|
827
|
+
}
|
|
828
|
+
filteredSessions = filteredSessions.filter((s) => s.summary);
|
|
829
|
+
const limitedSessions = filteredSessions.slice(0, limit);
|
|
830
|
+
const localeStr = isChineseLocale(locale) ? "zh-CN" : "en-US";
|
|
831
|
+
const data = {
|
|
832
|
+
total: filteredSessions.length,
|
|
833
|
+
returned: limitedSessions.length,
|
|
834
|
+
timeRange: formatTimeRange(effectiveTimeFilter, locale),
|
|
835
|
+
sessions: limitedSessions.map((s) => {
|
|
836
|
+
const startTime = new Date(s.startTs * 1e3).toLocaleString(localeStr);
|
|
837
|
+
const endTime = new Date(s.endTs * 1e3).toLocaleString(localeStr);
|
|
838
|
+
return {
|
|
839
|
+
sessionId: s.id,
|
|
840
|
+
time: `${startTime} ~ ${endTime}`,
|
|
841
|
+
messageCount: s.messageCount,
|
|
842
|
+
participants: s.participants,
|
|
843
|
+
summary: s.summary
|
|
844
|
+
};
|
|
845
|
+
})
|
|
846
|
+
};
|
|
847
|
+
return { content: JSON.stringify(data), data };
|
|
848
|
+
}
|
|
849
|
+
var getSessionSummariesTool = {
|
|
850
|
+
name: "get_session_summaries",
|
|
851
|
+
description: "\u83B7\u53D6\u4F1A\u8BDD\u6458\u8981\u5217\u8868\uFF0C\u5FEB\u901F\u4E86\u89E3\u7FA4\u804A\u5386\u53F2\u8BA8\u8BBA\u7684\u4E3B\u9898\u3002\u53EF\u4EE5\u6309\u5173\u952E\u8BCD\u641C\u7D22\u8BA8\u8BBA\u8FC7\u7684\u8BDD\u9898\u3002",
|
|
852
|
+
inputSchema: inputSchema17,
|
|
853
|
+
handler: handler17,
|
|
854
|
+
category: "analysis"
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
// ../../packages/tools/src/definitions/response-time-analysis.ts
|
|
858
|
+
var inputSchema18 = {
|
|
859
|
+
type: "object",
|
|
860
|
+
properties: {
|
|
861
|
+
days: { type: "number", description: "\u5206\u6790\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E\uFF0C\u9ED8\u8BA4 30" },
|
|
862
|
+
top_n: { type: "number", description: "\u8FD4\u56DE\u524D\u591A\u5C11\u540D\uFF0C\u9ED8\u8BA4 10" }
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
async function handler18(params, context) {
|
|
866
|
+
const { locale } = context;
|
|
867
|
+
const isZh = isChineseLocale(locale);
|
|
868
|
+
const days = params.days || 30;
|
|
869
|
+
const topN = params.top_n || 10;
|
|
870
|
+
const sql = `
|
|
871
|
+
SELECT msg.sender_id, COALESCE(m.group_nickname, m.account_name) AS name, msg.ts
|
|
872
|
+
FROM message msg
|
|
873
|
+
JOIN member m ON msg.sender_id = m.id
|
|
874
|
+
WHERE msg.type = 0
|
|
875
|
+
AND msg.ts > unixepoch('now', '-' || @days || ' days')
|
|
876
|
+
ORDER BY msg.ts ASC
|
|
877
|
+
`;
|
|
878
|
+
const rows = await context.dataProvider.executeParameterizedSql(sql, { days });
|
|
879
|
+
if (!rows || rows.length < 2) {
|
|
880
|
+
const text = isZh ? "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6D88\u606F\u4E0D\u8DB3\uFF0C\u65E0\u6CD5\u5206\u6790\u54CD\u5E94\u65F6\u95F4" : "Not enough messages in this time range to analyze response time";
|
|
881
|
+
return { content: text, data: null };
|
|
882
|
+
}
|
|
883
|
+
const responseTimes = /* @__PURE__ */ new Map();
|
|
884
|
+
for (let i = 1; i < rows.length; i++) {
|
|
885
|
+
const prev = rows[i - 1];
|
|
886
|
+
const curr = rows[i];
|
|
887
|
+
if (curr.sender_id === prev.sender_id) continue;
|
|
888
|
+
const gap = curr.ts - prev.ts;
|
|
889
|
+
if (gap < 5 || gap > 1800) continue;
|
|
890
|
+
if (!responseTimes.has(curr.sender_id)) {
|
|
891
|
+
responseTimes.set(curr.sender_id, { name: curr.name, times: [] });
|
|
892
|
+
}
|
|
893
|
+
responseTimes.get(curr.sender_id).times.push(gap);
|
|
894
|
+
}
|
|
895
|
+
const stats = [...responseTimes.entries()].map(([id, { name, times }]) => {
|
|
896
|
+
times.sort((a, b) => a - b);
|
|
897
|
+
const avg = Math.round(times.reduce((s, t2) => s + t2, 0) / times.length);
|
|
898
|
+
const median = times[Math.floor(times.length / 2)];
|
|
899
|
+
return { id, name, avgSeconds: avg, medianSeconds: median, responseCount: times.length };
|
|
900
|
+
}).filter((s) => s.responseCount >= 3).sort((a, b) => a.medianSeconds - b.medianSeconds).slice(0, topN);
|
|
901
|
+
if (stats.length === 0) {
|
|
902
|
+
const text = isZh ? "\u6CA1\u6709\u8DB3\u591F\u7684\u54CD\u5E94\u6570\u636E\u8FDB\u884C\u5206\u6790" : "Not enough response data for analysis";
|
|
903
|
+
return { content: text, data: null };
|
|
904
|
+
}
|
|
905
|
+
const formatTime = (s) => {
|
|
906
|
+
if (s < 60) return isZh ? `${s}\u79D2` : `${s}s`;
|
|
907
|
+
const m = Math.floor(s / 60);
|
|
908
|
+
const sec = s % 60;
|
|
909
|
+
return isZh ? `${m}\u5206${sec}\u79D2` : `${m}m${sec}s`;
|
|
910
|
+
};
|
|
911
|
+
const ranking = stats.map((s, i) => ({
|
|
912
|
+
rank: i + 1,
|
|
913
|
+
name: s.name,
|
|
914
|
+
median: formatTime(s.medianSeconds),
|
|
915
|
+
avg: formatTime(s.avgSeconds),
|
|
916
|
+
count: s.responseCount
|
|
917
|
+
}));
|
|
918
|
+
const data = {
|
|
919
|
+
period: isZh ? `\u8FD1${days}\u5929` : `Last ${days} days`,
|
|
920
|
+
totalResponders: stats.length,
|
|
921
|
+
ranking: ranking.map(
|
|
922
|
+
(r) => `${r.rank}. ${r.name} \u2014 ${isZh ? "\u4E2D\u4F4D\u6570" : "median"} ${r.median}, ${isZh ? "\u5E73\u5747" : "avg"} ${r.avg} (${r.count}${isZh ? "\u6B21" : " responses"})`
|
|
923
|
+
)
|
|
924
|
+
};
|
|
925
|
+
return { content: JSON.stringify(data), data };
|
|
926
|
+
}
|
|
927
|
+
var responseTimeAnalysisTool = {
|
|
928
|
+
name: "response_time_analysis",
|
|
929
|
+
description: "\u5206\u6790\u7FA4\u6210\u5458\u7684\u54CD\u5E94\u901F\u5EA6\u6392\u884C\uFF0C\u57FA\u4E8E\u56DE\u590D\u95F4\u9694\u7684\u4E2D\u4F4D\u6570\u548C\u5E73\u5747\u503C\u3002",
|
|
930
|
+
inputSchema: inputSchema18,
|
|
931
|
+
handler: handler18,
|
|
932
|
+
category: "analysis"
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
// ../../packages/tools/src/definitions/keyword-frequency.ts
|
|
936
|
+
var inputSchema19 = {
|
|
937
|
+
type: "object",
|
|
938
|
+
properties: {
|
|
939
|
+
days: { type: "number", description: "\u5206\u6790\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E\uFF0C\u9ED8\u8BA4 30" },
|
|
940
|
+
top_n: { type: "number", description: "\u8FD4\u56DE\u524D\u591A\u5C11\u4E2A\u9AD8\u9891\u8BCD\uFF0C\u9ED8\u8BA4 50" }
|
|
941
|
+
}
|
|
942
|
+
};
|
|
943
|
+
async function handler19(params, context) {
|
|
944
|
+
const { locale, segmentText } = context;
|
|
945
|
+
const isZh = isChineseLocale(locale);
|
|
946
|
+
const days = params.days || 30;
|
|
947
|
+
const topN = params.top_n || 50;
|
|
948
|
+
if (!segmentText) {
|
|
949
|
+
const text = isZh ? "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u5206\u8BCD\u529F\u80FD" : "Text segmentation is not available in this environment";
|
|
950
|
+
return { content: text, data: null };
|
|
951
|
+
}
|
|
952
|
+
const sql = `
|
|
953
|
+
SELECT content FROM message
|
|
954
|
+
WHERE type = 0 AND content IS NOT NULL AND LENGTH(content) > 1
|
|
955
|
+
AND ts > unixepoch('now', '-' || @days || ' days')
|
|
956
|
+
LIMIT 50000
|
|
957
|
+
`;
|
|
958
|
+
const rows = await context.dataProvider.executeParameterizedSql(sql, { days });
|
|
959
|
+
if (!rows || rows.length === 0) {
|
|
960
|
+
const text = isZh ? "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u6587\u672C\u6D88\u606F" : "No text messages in this time range";
|
|
961
|
+
return { content: text, data: null };
|
|
962
|
+
}
|
|
963
|
+
const texts = rows.map((r) => r.content);
|
|
964
|
+
const segLocale = locale?.startsWith("ja") ? "ja-JP" : locale?.startsWith("zh") ? "zh-CN" : "en-US";
|
|
965
|
+
const freqResult = segmentText(texts, segLocale, {
|
|
966
|
+
minCount: 2,
|
|
967
|
+
topN,
|
|
968
|
+
posFilterMode: "meaningful",
|
|
969
|
+
enableStopwords: true
|
|
970
|
+
});
|
|
971
|
+
if (freqResult.words.size === 0) {
|
|
972
|
+
const text = isZh ? "\u5206\u8BCD\u540E\u6CA1\u6709\u6709\u610F\u4E49\u7684\u9AD8\u9891\u8BCD" : "No meaningful high-frequency words found after segmentation";
|
|
973
|
+
return { content: text, data: null };
|
|
974
|
+
}
|
|
975
|
+
const ranking = [...freqResult.words.entries()].map(([word, count], i) => ({
|
|
976
|
+
rank: i + 1,
|
|
977
|
+
word,
|
|
978
|
+
count
|
|
979
|
+
}));
|
|
980
|
+
const data = {
|
|
981
|
+
period: isZh ? `\u8FD1${days}\u5929` : `Last ${days} days`,
|
|
982
|
+
totalMessages: rows.length,
|
|
983
|
+
totalKeywords: ranking.length,
|
|
984
|
+
keywords: ranking.map((r) => `${r.rank}. ${r.word} (${r.count}${isZh ? "\u6B21" : ""})`)
|
|
985
|
+
};
|
|
986
|
+
return { content: JSON.stringify(data), data };
|
|
987
|
+
}
|
|
988
|
+
var keywordFrequencyTool = {
|
|
989
|
+
name: "keyword_frequency",
|
|
990
|
+
description: "\u7EDF\u8BA1\u7FA4\u804A\u4E2D\u7684\u9AD8\u9891\u5173\u952E\u8BCD\uFF0C\u901A\u8FC7 NLP \u5206\u8BCD\u5206\u6790\u6D88\u606F\u5185\u5BB9\u3002",
|
|
991
|
+
inputSchema: inputSchema19,
|
|
992
|
+
handler: handler19,
|
|
993
|
+
category: "analysis"
|
|
994
|
+
};
|
|
995
|
+
|
|
996
|
+
// ../../packages/tools/src/sql/definitions.ts
|
|
997
|
+
var SQL_TOOL_DEFS = [
|
|
998
|
+
// ==================== 通用分析 ====================
|
|
999
|
+
{
|
|
1000
|
+
name: "message_type_breakdown",
|
|
1001
|
+
description: "\u6309\u6D88\u606F\u7C7B\u578B\u7EDF\u8BA1\u8FD1 N \u5929\u7684\u6D88\u606F\u5206\u5E03\uFF08\u6587\u672C\u3001\u56FE\u7247\u3001\u8BED\u97F3\u3001\u8868\u60C5\u7B49\u5404\u6709\u591A\u5C11\u6761\uFF09\u3002\u9002\u7528\u4E8E\u4E86\u89E3\u6C9F\u901A\u65B9\u5F0F\u504F\u597D\u3002",
|
|
1002
|
+
parameters: {
|
|
1003
|
+
type: "object",
|
|
1004
|
+
properties: {
|
|
1005
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E" }
|
|
1006
|
+
},
|
|
1007
|
+
required: ["days"]
|
|
1008
|
+
},
|
|
1009
|
+
execution: {
|
|
1010
|
+
type: "sqlite",
|
|
1011
|
+
query: "SELECT CASE type WHEN 0 THEN '\u6587\u672C' WHEN 1 THEN '\u56FE\u7247' WHEN 2 THEN '\u8BED\u97F3' WHEN 3 THEN '\u89C6\u9891' WHEN 4 THEN '\u6587\u4EF6' WHEN 5 THEN '\u8868\u60C5' WHEN 7 THEN '\u94FE\u63A5' WHEN 20 THEN '\u7EA2\u5305' WHEN 22 THEN '\u62CD\u4E00\u62CD' WHEN 80 THEN '\u7CFB\u7EDF\u6D88\u606F' WHEN 81 THEN '\u64A4\u56DE' ELSE '\u5176\u4ED6' END AS type_name, COUNT(*) AS msg_count, ROUND(COUNT(*) * 100.0 / SUM(COUNT(*)) OVER(), 1) AS percentage FROM message WHERE ts > unixepoch('now', '-' || @days || ' days') GROUP BY type ORDER BY msg_count DESC",
|
|
1012
|
+
rowTemplate: "{type_name}\uFF1A{msg_count} \u6761\uFF08\u5360 {percentage}%\uFF09",
|
|
1013
|
+
summaryTemplate: "\u6D88\u606F\u7C7B\u578B\u5206\u5E03\uFF08\u5171 {rowCount} \u79CD\u7C7B\u578B\uFF09\uFF1A",
|
|
1014
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u6D88\u606F\u8BB0\u5F55"
|
|
1015
|
+
}
|
|
1016
|
+
},
|
|
1017
|
+
{
|
|
1018
|
+
name: "peak_chat_hours_by_member",
|
|
1019
|
+
description: "\u5206\u6790\u6307\u5B9A\u6210\u5458\u5728\u8FD1 N \u5929\u5185\u6BCF\u5C0F\u65F6\u7684\u53D1\u8A00\u91CF\u5206\u5E03\uFF0C\u627E\u51FA\u5176\u6700\u6D3B\u8DC3\u7684\u65F6\u6BB5\u3002\u9700\u8981\u5148\u901A\u8FC7 get_members \u83B7\u53D6 member_id\u3002",
|
|
1020
|
+
parameters: {
|
|
1021
|
+
type: "object",
|
|
1022
|
+
properties: {
|
|
1023
|
+
member_id: { type: "number", description: "\u6210\u5458 ID\uFF08\u901A\u8FC7 get_members \u83B7\u53D6\uFF09" },
|
|
1024
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E", default: 30 }
|
|
1025
|
+
},
|
|
1026
|
+
required: ["member_id"]
|
|
1027
|
+
},
|
|
1028
|
+
execution: {
|
|
1029
|
+
type: "sqlite",
|
|
1030
|
+
query: "SELECT CAST(strftime('%H', ts, 'unixepoch', 'localtime') AS INTEGER) AS hour, COUNT(*) AS msg_count FROM message WHERE sender_id = @member_id AND ts > unixepoch('now', '-' || @days || ' days') GROUP BY hour ORDER BY msg_count DESC",
|
|
1031
|
+
rowTemplate: "{hour}:00 \u2014 {msg_count} \u6761\u6D88\u606F",
|
|
1032
|
+
summaryTemplate: "\u8BE5\u6210\u5458\u5404\u65F6\u6BB5\u53D1\u8A00\u91CF\uFF08\u5171 {rowCount} \u4E2A\u6D3B\u8DC3\u65F6\u6BB5\uFF09\uFF1A",
|
|
1033
|
+
fallback: "\u8BE5\u6210\u5458\u5728\u6307\u5B9A\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u53D1\u8A00\u8BB0\u5F55"
|
|
1034
|
+
}
|
|
1035
|
+
},
|
|
1036
|
+
// ==================== 社群分析 ====================
|
|
1037
|
+
{
|
|
1038
|
+
name: "member_activity_trend",
|
|
1039
|
+
description: "\u67E5\u770B\u6307\u5B9A\u6210\u5458\u8FD1 N \u5929\u7684\u6BCF\u65E5\u53D1\u8A00\u6570\u91CF\u53D8\u5316\u8D8B\u52BF\u3002\u9002\u7528\u4E8E\u89C2\u5BDF\u67D0\u4EBA\u662F\u5426\u53D8\u5F97\u66F4\u6D3B\u8DC3\u6216\u66F4\u6C89\u9ED8\u3002\u9700\u8981\u5148\u901A\u8FC7 get_members \u83B7\u53D6 member_id\u3002",
|
|
1040
|
+
parameters: {
|
|
1041
|
+
type: "object",
|
|
1042
|
+
properties: {
|
|
1043
|
+
member_id: { type: "number", description: "\u6210\u5458 ID\uFF08\u901A\u8FC7 get_members \u83B7\u53D6\uFF09" },
|
|
1044
|
+
days: { type: "number", description: "\u67E5\u770B\u6700\u8FD1\u591A\u5C11\u5929\u7684\u8D8B\u52BF" }
|
|
1045
|
+
},
|
|
1046
|
+
required: ["member_id", "days"]
|
|
1047
|
+
},
|
|
1048
|
+
execution: {
|
|
1049
|
+
type: "sqlite",
|
|
1050
|
+
query: "SELECT date(ts, 'unixepoch', 'localtime') AS day, COUNT(*) AS msg_count FROM message WHERE sender_id = @member_id AND ts > unixepoch('now', '-' || @days || ' days') GROUP BY day ORDER BY day",
|
|
1051
|
+
rowTemplate: "{day}\uFF1A{msg_count} \u6761",
|
|
1052
|
+
summaryTemplate: "\u8BE5\u6210\u5458\u8FD1 {rowCount} \u5929\u6709\u53D1\u8A00\u8BB0\u5F55\uFF1A",
|
|
1053
|
+
fallback: "\u8BE5\u6210\u5458\u5728\u6307\u5B9A\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u53D1\u8A00\u8BB0\u5F55"
|
|
1054
|
+
}
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
name: "silent_members",
|
|
1058
|
+
description: "\u68C0\u6D4B\u8D85\u8FC7 N \u5929\u672A\u53D1\u8A00\u7684\u300C\u6C89\u9ED8\u6210\u5458\u300D\u3002\u9002\u7528\u4E8E\u793E\u7FA4\u8FD0\u8425\u4E2D\u53D1\u73B0\u6D41\u5931\u98CE\u9669\u7528\u6237\u3002",
|
|
1059
|
+
parameters: {
|
|
1060
|
+
type: "object",
|
|
1061
|
+
properties: {
|
|
1062
|
+
days: { type: "number", description: "\u591A\u5C11\u5929\u672A\u53D1\u8A00\u7B97\u6C89\u9ED8", default: 7 }
|
|
1063
|
+
},
|
|
1064
|
+
required: ["days"]
|
|
1065
|
+
},
|
|
1066
|
+
execution: {
|
|
1067
|
+
type: "sqlite",
|
|
1068
|
+
query: "SELECT m.id AS member_id, COALESCE(m.group_nickname, m.account_name, m.platform_id) AS name, MAX(msg.ts) AS last_msg_ts, CAST((unixepoch('now') - MAX(msg.ts)) / 86400 AS INTEGER) AS silent_days FROM member m JOIN message msg ON msg.sender_id = m.id GROUP BY m.id HAVING silent_days >= @days ORDER BY silent_days DESC LIMIT 30",
|
|
1069
|
+
rowTemplate: "{name} \u2014 \u5DF2\u6C89\u9ED8 {silent_days} \u5929",
|
|
1070
|
+
summaryTemplate: "\u5171\u53D1\u73B0 {rowCount} \u4F4D\u6C89\u9ED8\u6210\u5458\uFF1A",
|
|
1071
|
+
fallback: "\u6CA1\u6709\u53D1\u73B0\u8D85\u8FC7\u6307\u5B9A\u5929\u6570\u672A\u53D1\u8A00\u7684\u6210\u5458\uFF0C\u793E\u7FA4\u6D3B\u8DC3\u5EA6\u826F\u597D\uFF01"
|
|
1072
|
+
}
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
name: "reply_interaction_ranking",
|
|
1076
|
+
description: "\u5206\u6790\u7FA4\u5185\u7684\u56DE\u590D\u4E92\u52A8\u5173\u7CFB\u6392\u884C\uFF0C\u627E\u51FA\u8C01\u56DE\u590D\u8C01\u6700\u591A\u3002\u9002\u7528\u4E8E\u53D1\u73B0\u793E\u7FA4\u4E2D\u7684\u6838\u5FC3\u4E92\u52A8\u5173\u7CFB\u548C\u610F\u89C1\u9886\u8896\u3002",
|
|
1077
|
+
parameters: {
|
|
1078
|
+
type: "object",
|
|
1079
|
+
properties: {
|
|
1080
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E" },
|
|
1081
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u524D\u591A\u5C11\u5BF9\u4E92\u52A8\u5173\u7CFB", default: 10 }
|
|
1082
|
+
},
|
|
1083
|
+
required: ["days"]
|
|
1084
|
+
},
|
|
1085
|
+
execution: {
|
|
1086
|
+
type: "sqlite",
|
|
1087
|
+
query: "SELECT COALESCE(replier.group_nickname, replier.account_name) AS replier_name, COALESCE(original.group_nickname, original.account_name) AS original_name, COUNT(*) AS reply_count FROM message reply_msg JOIN message orig_msg ON reply_msg.reply_to_message_id = CAST(orig_msg.id AS TEXT) JOIN member replier ON reply_msg.sender_id = replier.id JOIN member original ON orig_msg.sender_id = original.id WHERE reply_msg.reply_to_message_id IS NOT NULL AND reply_msg.ts > unixepoch('now', '-' || @days || ' days') GROUP BY reply_msg.sender_id, orig_msg.sender_id ORDER BY reply_count DESC LIMIT @limit",
|
|
1088
|
+
rowTemplate: "{replier_name} \u2192 {original_name}\uFF1A{reply_count} \u6B21\u56DE\u590D",
|
|
1089
|
+
summaryTemplate: "\u56DE\u590D\u4E92\u52A8 Top {rowCount}\uFF1A",
|
|
1090
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u56DE\u590D\u4E92\u52A8\u8BB0\u5F55"
|
|
1091
|
+
}
|
|
1092
|
+
},
|
|
1093
|
+
// ==================== 情感分析 ====================
|
|
1094
|
+
{
|
|
1095
|
+
name: "mutual_interaction_pairs",
|
|
1096
|
+
description: "\u627E\u51FA\u4E92\u52A8\u6700\u9891\u7E41\u7684\u6210\u5458\u5BF9\uFF0C\u57FA\u4E8E\u53CC\u5411\u6D88\u606F\u65F6\u95F4\u63A5\u8FD1\u5EA6\uFF08\u4E00\u65B9\u53D1\u8A00\u540E 5 \u5206\u949F\u5185\u53E6\u4E00\u65B9\u4E5F\u53D1\u8A00\u5373\u89C6\u4E3A\u4E00\u6B21\u4E92\u52A8\uFF09\u3002\u9002\u7528\u4E8E\u53D1\u73B0\u5173\u7CFB\u4EB2\u5BC6\u7684\u597D\u53CB\u7EC4\u5408\u3002",
|
|
1097
|
+
parameters: {
|
|
1098
|
+
type: "object",
|
|
1099
|
+
properties: {
|
|
1100
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E" },
|
|
1101
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u524D\u591A\u5C11\u5BF9", default: 10 }
|
|
1102
|
+
},
|
|
1103
|
+
required: ["days"]
|
|
1104
|
+
},
|
|
1105
|
+
execution: {
|
|
1106
|
+
type: "sqlite",
|
|
1107
|
+
query: "SELECT COALESCE(m1.group_nickname, m1.account_name) AS member_a, COALESCE(m2.group_nickname, m2.account_name) AS member_b, COUNT(*) AS interaction_count FROM message a JOIN message b ON b.sender_id != a.sender_id AND b.ts > a.ts AND b.ts <= a.ts + 300 JOIN member m1 ON a.sender_id = m1.id JOIN member m2 ON b.sender_id = m2.id WHERE a.sender_id < b.sender_id AND a.ts > unixepoch('now', '-' || @days || ' days') AND a.type = 0 AND b.type = 0 GROUP BY a.sender_id, b.sender_id ORDER BY interaction_count DESC LIMIT @limit",
|
|
1108
|
+
rowTemplate: "{member_a} \u2194 {member_b}\uFF1A{interaction_count} \u6B21\u4E92\u52A8",
|
|
1109
|
+
summaryTemplate: "\u4E92\u52A8\u6700\u9891\u7E41\u7684 {rowCount} \u5BF9\u597D\u53CB\uFF1A",
|
|
1110
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u68C0\u6D4B\u5230\u660E\u663E\u7684\u4E92\u52A8\u5173\u7CFB"
|
|
1111
|
+
}
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
name: "member_message_length_stats",
|
|
1115
|
+
description: "\u7EDF\u8BA1\u5404\u6210\u5458\u7684\u5E73\u5747\u6D88\u606F\u957F\u5EA6\uFF08\u4EC5\u6587\u672C\u6D88\u606F\uFF09\uFF0C\u957F\u6D88\u606F\u901A\u5E38\u610F\u5473\u7740\u66F4\u7528\u5FC3\u7684\u4EA4\u6D41\u3002\u9002\u7528\u4E8E\u53D1\u73B0\u6DF1\u5EA6\u4EA4\u6D41\u8005\u3002",
|
|
1116
|
+
parameters: {
|
|
1117
|
+
type: "object",
|
|
1118
|
+
properties: {
|
|
1119
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E" },
|
|
1120
|
+
top_n: { type: "number", description: "\u8FD4\u56DE\u524D\u591A\u5C11\u540D", default: 10 }
|
|
1121
|
+
},
|
|
1122
|
+
required: ["days"]
|
|
1123
|
+
},
|
|
1124
|
+
execution: {
|
|
1125
|
+
type: "sqlite",
|
|
1126
|
+
query: "SELECT COALESCE(m.group_nickname, m.account_name) AS name, COUNT(*) AS msg_count, ROUND(AVG(LENGTH(msg.content)), 1) AS avg_length, MAX(LENGTH(msg.content)) AS max_length FROM message msg JOIN member m ON msg.sender_id = m.id WHERE msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(msg.content) > 0 AND msg.ts > unixepoch('now', '-' || @days || ' days') GROUP BY msg.sender_id HAVING msg_count >= 5 ORDER BY avg_length DESC LIMIT @top_n",
|
|
1127
|
+
rowTemplate: "{name} \u2014 \u5E73\u5747 {avg_length} \u5B57/\u6761\uFF08\u5171 {msg_count} \u6761\uFF0C\u6700\u957F {max_length} \u5B57\uFF09",
|
|
1128
|
+
summaryTemplate: "\u6D88\u606F\u957F\u5EA6 Top {rowCount}\uFF08\u66F4\u957F = \u66F4\u7528\u5FC3\uFF09\uFF1A",
|
|
1129
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u8DB3\u591F\u7684\u6587\u672C\u6D88\u606F\u6570\u636E"
|
|
1130
|
+
}
|
|
1131
|
+
},
|
|
1132
|
+
// ==================== 活跃度趋势 ====================
|
|
1133
|
+
{
|
|
1134
|
+
name: "daily_active_members",
|
|
1135
|
+
description: '\u7EDF\u8BA1\u6BCF\u65E5\u72EC\u7ACB\u53D1\u8A00\u4EBA\u6570\uFF08DAU\uFF09\u548C\u6D88\u606F\u91CF\uFF0C\u7528\u4E8E\u89C2\u5BDF\u7FA4\u6D3B\u529B\u53D8\u5316\u8D8B\u52BF\u3002\u9002\u7528\u4E8E"\u7FA4\u6D3B\u8DC3\u5EA6\u8D8B\u52BF\u600E\u4E48\u6837"\u3001"\u6700\u8FD1\u6709\u591A\u5C11\u4EBA\u5728\u8BF4\u8BDD"\u3002',
|
|
1136
|
+
parameters: {
|
|
1137
|
+
type: "object",
|
|
1138
|
+
properties: {
|
|
1139
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E", default: 30 }
|
|
1140
|
+
},
|
|
1141
|
+
required: ["days"]
|
|
1142
|
+
},
|
|
1143
|
+
execution: {
|
|
1144
|
+
type: "sqlite",
|
|
1145
|
+
query: "SELECT date(ts, 'unixepoch', 'localtime') AS day, COUNT(DISTINCT sender_id) AS active_members, COUNT(*) AS msg_count FROM message WHERE ts > unixepoch('now', '-' || @days || ' days') GROUP BY day ORDER BY day",
|
|
1146
|
+
rowTemplate: "{day}\uFF1A{active_members} \u4EBA\u6D3B\u8DC3\uFF0C{msg_count} \u6761\u6D88\u606F",
|
|
1147
|
+
summaryTemplate: "\u8FD1 {rowCount} \u5929\u7684\u6BCF\u65E5\u6D3B\u8DC3\u4EBA\u6570\u8D8B\u52BF\uFF1A",
|
|
1148
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u6D88\u606F\u8BB0\u5F55"
|
|
1149
|
+
}
|
|
1150
|
+
},
|
|
1151
|
+
{
|
|
1152
|
+
name: "conversation_initiator_stats",
|
|
1153
|
+
description: "\u7EDF\u8BA1\u6BCF\u4E2A\u6210\u5458\u53D1\u8D77\u4F1A\u8BDD\uFF08\u4F5C\u4E3A\u4F1A\u8BDD\u9996\u6761\u6D88\u606F\u7684\u53D1\u9001\u8005\uFF09\u7684\u6B21\u6570\uFF0C\u627E\u51FA\u8C01\u6700\u5E38\u5F00\u542F\u8BDD\u9898\u3002\u9700\u8981\u5DF2\u751F\u6210\u4F1A\u8BDD\u7D22\u5F15\u3002",
|
|
1154
|
+
parameters: {
|
|
1155
|
+
type: "object",
|
|
1156
|
+
properties: {
|
|
1157
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E", default: 30 },
|
|
1158
|
+
limit: { type: "number", description: "\u8FD4\u56DE\u524D\u591A\u5C11\u540D", default: 10 }
|
|
1159
|
+
},
|
|
1160
|
+
required: ["days"]
|
|
1161
|
+
},
|
|
1162
|
+
execution: {
|
|
1163
|
+
type: "sqlite",
|
|
1164
|
+
query: "SELECT COALESCE(m.group_nickname, m.account_name) AS name, COUNT(*) AS initiated_count FROM chat_session cs JOIN message_context mc ON mc.session_id = cs.id JOIN message msg ON msg.id = mc.message_id JOIN member m ON msg.sender_id = m.id WHERE msg.ts = cs.start_ts AND cs.start_ts > unixepoch('now', '-' || @days || ' days') GROUP BY msg.sender_id ORDER BY initiated_count DESC LIMIT @limit",
|
|
1165
|
+
rowTemplate: "{name}\uFF1A\u53D1\u8D77 {initiated_count} \u6B21\u8BDD\u9898",
|
|
1166
|
+
summaryTemplate: "\u8BDD\u9898\u53D1\u8D77\u8005 Top {rowCount}\uFF1A",
|
|
1167
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u4F1A\u8BDD\u8BB0\u5F55\uFF0C\u53EF\u80FD\u9700\u8981\u5148\u751F\u6210\u4F1A\u8BDD\u7D22\u5F15"
|
|
1168
|
+
}
|
|
1169
|
+
},
|
|
1170
|
+
{
|
|
1171
|
+
name: "activity_heatmap",
|
|
1172
|
+
description: "\u8FD4\u56DE \u661F\u671F\xD7\u5C0F\u65F6 \u7684\u6D88\u606F\u6570\u77E9\u9635\uFF0C\u9002\u5408\u751F\u6210\u6D3B\u8DC3\u5EA6\u70ED\u529B\u56FE\u3002weekday: 0=\u5468\u65E5, 1=\u5468\u4E00, ..., 6=\u5468\u516D\u3002",
|
|
1173
|
+
parameters: {
|
|
1174
|
+
type: "object",
|
|
1175
|
+
properties: {
|
|
1176
|
+
days: { type: "number", description: "\u7EDF\u8BA1\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E", default: 30 }
|
|
1177
|
+
},
|
|
1178
|
+
required: ["days"]
|
|
1179
|
+
},
|
|
1180
|
+
execution: {
|
|
1181
|
+
type: "sqlite",
|
|
1182
|
+
query: "SELECT CAST(strftime('%w', ts, 'unixepoch', 'localtime') AS INTEGER) AS weekday, CAST(strftime('%H', ts, 'unixepoch', 'localtime') AS INTEGER) AS hour, COUNT(*) AS msg_count FROM message WHERE ts > unixepoch('now', '-' || @days || ' days') GROUP BY weekday, hour ORDER BY weekday, hour",
|
|
1183
|
+
rowTemplate: "\u661F\u671F{weekday} {hour}:00 \u2014 {msg_count} \u6761",
|
|
1184
|
+
summaryTemplate: "\u6D3B\u8DC3\u5EA6\u70ED\u529B\u56FE\u6570\u636E\uFF08\u5171 {rowCount} \u4E2A\u65F6\u6BB5\u6709\u6D88\u606F\uFF09\uFF1A",
|
|
1185
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6CA1\u6709\u6D88\u606F\u8BB0\u5F55"
|
|
1186
|
+
}
|
|
1187
|
+
},
|
|
1188
|
+
// ==================== 客服分析 ====================
|
|
1189
|
+
{
|
|
1190
|
+
name: "unanswered_messages",
|
|
1191
|
+
description: "\u67E5\u627E\u8FD1 N \u5929\u5185\u672A\u88AB\u56DE\u590D\u7684\u6D88\u606F\uFF0C\u8FD9\u4E9B\u53EF\u80FD\u662F\u672A\u89E3\u51B3\u7684\u5BA2\u6237\u95EE\u9898\u3002\u4EC5\u7EDF\u8BA1\u6587\u672C\u6D88\u606F\u4E14\u5185\u5BB9\u8D85\u8FC7 10 \u5B57\u7684\uFF08\u8FC7\u6EE4\u7B80\u77ED\u5BD2\u6684\uFF09\u3002",
|
|
1192
|
+
parameters: {
|
|
1193
|
+
type: "object",
|
|
1194
|
+
properties: {
|
|
1195
|
+
days: { type: "number", description: "\u67E5\u627E\u6700\u8FD1\u591A\u5C11\u5929\u7684\u6570\u636E" },
|
|
1196
|
+
limit: { type: "number", description: "\u6700\u591A\u8FD4\u56DE\u591A\u5C11\u6761", default: 20 }
|
|
1197
|
+
},
|
|
1198
|
+
required: ["days"]
|
|
1199
|
+
},
|
|
1200
|
+
execution: {
|
|
1201
|
+
type: "sqlite",
|
|
1202
|
+
query: "SELECT COALESCE(m.group_nickname, m.account_name) AS sender_name, datetime(msg.ts, 'unixepoch', 'localtime') AS send_time, SUBSTR(msg.content, 1, 100) AS content_preview FROM message msg JOIN member m ON msg.sender_id = m.id WHERE msg.type = 0 AND msg.content IS NOT NULL AND LENGTH(msg.content) > 10 AND msg.ts > unixepoch('now', '-' || @days || ' days') AND NOT EXISTS (SELECT 1 FROM message reply WHERE reply.reply_to_message_id = CAST(msg.id AS TEXT)) AND NOT EXISTS (SELECT 1 FROM message next WHERE next.sender_id != msg.sender_id AND next.ts > msg.ts AND next.ts <= msg.ts + 1800) ORDER BY msg.ts DESC LIMIT @limit",
|
|
1203
|
+
rowTemplate: "[{send_time}] {sender_name}\uFF1A{content_preview}",
|
|
1204
|
+
summaryTemplate: "\u5171\u53D1\u73B0 {rowCount} \u6761\u53EF\u80FD\u672A\u88AB\u56DE\u590D\u7684\u6D88\u606F\uFF1A",
|
|
1205
|
+
fallback: "\u8BE5\u65F6\u95F4\u8303\u56F4\u5185\u6240\u6709\u6D88\u606F\u90FD\u5DF2\u5F97\u5230\u56DE\u590D\uFF0C\u670D\u52A1\u8D28\u91CF\u5F88\u597D\uFF01"
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
];
|
|
1209
|
+
|
|
1210
|
+
// ../../packages/tools/src/sql/executor.ts
|
|
1211
|
+
function formatRow(template, row) {
|
|
1212
|
+
return template.replace(/\{(\w+)\}/g, (_, col) => {
|
|
1213
|
+
const val = row[col];
|
|
1214
|
+
return val !== null && val !== void 0 ? String(val) : "";
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
function resolveTemplate(toolName, key, fallback, translateFn) {
|
|
1218
|
+
if (!translateFn) return fallback;
|
|
1219
|
+
const i18nKey = `ai.tools.${toolName}.${key}`;
|
|
1220
|
+
return translateFn(i18nKey) ?? fallback;
|
|
1221
|
+
}
|
|
1222
|
+
function createSqlToolDefinition(def) {
|
|
1223
|
+
return {
|
|
1224
|
+
name: def.name,
|
|
1225
|
+
description: def.description,
|
|
1226
|
+
inputSchema: def.parameters,
|
|
1227
|
+
category: "analysis",
|
|
1228
|
+
handler: async (params, context) => {
|
|
1229
|
+
const rows = await context.dataProvider.executeParameterizedSql(def.execution.query, params);
|
|
1230
|
+
const fallback = resolveTemplate(def.name, "fallback", def.execution.fallback, context.translateTemplate);
|
|
1231
|
+
if (!rows || rows.length === 0) {
|
|
1232
|
+
return {
|
|
1233
|
+
content: fallback,
|
|
1234
|
+
data: { rows: [], rowCount: 0 }
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
const rowTemplate = resolveTemplate(def.name, "rowTemplate", def.execution.rowTemplate, context.translateTemplate);
|
|
1238
|
+
const summaryTemplate = def.execution.summaryTemplate ? resolveTemplate(def.name, "summaryTemplate", def.execution.summaryTemplate, context.translateTemplate) : void 0;
|
|
1239
|
+
const lines = [];
|
|
1240
|
+
if (summaryTemplate) {
|
|
1241
|
+
lines.push(summaryTemplate.replace(/\{rowCount\}/g, String(rows.length)));
|
|
1242
|
+
lines.push("");
|
|
1243
|
+
}
|
|
1244
|
+
for (const row of rows) {
|
|
1245
|
+
lines.push(formatRow(rowTemplate, row));
|
|
1246
|
+
}
|
|
1247
|
+
return {
|
|
1248
|
+
content: lines.join("\n"),
|
|
1249
|
+
data: { rows, rowCount: rows.length }
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
}
|
|
1254
|
+
function createAllSqlToolDefinitions(defs) {
|
|
1255
|
+
return defs.map(createSqlToolDefinition);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// ../../packages/tools/src/registry.ts
|
|
1259
|
+
var AGENT_TOOL_REGISTRY = [
|
|
1260
|
+
// Core
|
|
1261
|
+
chatOverviewTool,
|
|
1262
|
+
searchMessagesTool,
|
|
1263
|
+
deepSearchMessagesTool,
|
|
1264
|
+
recentMessagesTool,
|
|
1265
|
+
getMessageContextTool,
|
|
1266
|
+
searchSessionsTool,
|
|
1267
|
+
getSessionMessagesTool,
|
|
1268
|
+
getMembersTool,
|
|
1269
|
+
// Analysis
|
|
1270
|
+
memberStatsTool,
|
|
1271
|
+
timeStatsTool,
|
|
1272
|
+
getMemberNameHistoryTool,
|
|
1273
|
+
getConversationBetweenTool,
|
|
1274
|
+
getSessionSummariesTool,
|
|
1275
|
+
responseTimeAnalysisTool,
|
|
1276
|
+
keywordFrequencyTool,
|
|
1277
|
+
// SQL
|
|
1278
|
+
sqlQueryTool,
|
|
1279
|
+
...createAllSqlToolDefinitions(SQL_TOOL_DEFS)
|
|
1280
|
+
];
|
|
1281
|
+
var MCP_TOOL_REGISTRY = [
|
|
1282
|
+
// MCP-specific: session discovery & schema
|
|
1283
|
+
sessionsListTool,
|
|
1284
|
+
sessionInfoTool,
|
|
1285
|
+
searchTool,
|
|
1286
|
+
schemaTool,
|
|
1287
|
+
// Full agent toolset
|
|
1288
|
+
...AGENT_TOOL_REGISTRY
|
|
1289
|
+
];
|
|
1290
|
+
|
|
1291
|
+
// ../../packages/tools/src/providers/core-data-provider.ts
|
|
1292
|
+
var CoreDataProvider = class {
|
|
1293
|
+
constructor(db) {
|
|
1294
|
+
this.db = db;
|
|
1295
|
+
}
|
|
1296
|
+
db;
|
|
1297
|
+
async searchMessages(keywords, options) {
|
|
1298
|
+
const keyword = keywords.join(" ");
|
|
1299
|
+
const result = searchMessagesLike(this.db, keyword, { limit: options?.limit ?? 50 });
|
|
1300
|
+
return {
|
|
1301
|
+
messages: result.messages.map((m) => ({
|
|
1302
|
+
id: m.id,
|
|
1303
|
+
senderId: m.senderId,
|
|
1304
|
+
senderName: m.senderName,
|
|
1305
|
+
senderPlatformId: m.senderPlatformId,
|
|
1306
|
+
content: m.content,
|
|
1307
|
+
timestamp: m.timestamp
|
|
1308
|
+
})),
|
|
1309
|
+
total: result.total ?? result.messages.length
|
|
1310
|
+
};
|
|
1311
|
+
}
|
|
1312
|
+
async deepSearchMessages(keywords, options) {
|
|
1313
|
+
return this.searchMessages(keywords, options);
|
|
1314
|
+
}
|
|
1315
|
+
async getSearchMessageContext(messageIds, contextBefore, contextAfter) {
|
|
1316
|
+
return getSearchMessageContext(this.db, messageIds, contextBefore, contextAfter);
|
|
1317
|
+
}
|
|
1318
|
+
async getRecentMessages(options) {
|
|
1319
|
+
const messages = getRecentMessages(this.db, { limit: options?.limit ?? 50 });
|
|
1320
|
+
return {
|
|
1321
|
+
messages: messages.map((m) => ({
|
|
1322
|
+
id: m.id,
|
|
1323
|
+
senderId: m.senderId,
|
|
1324
|
+
senderName: m.senderName,
|
|
1325
|
+
senderPlatformId: m.senderPlatformId,
|
|
1326
|
+
content: m.content,
|
|
1327
|
+
timestamp: m.timestamp
|
|
1328
|
+
})),
|
|
1329
|
+
total: messages.length
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
async getMessageContext(messageIds, contextSize) {
|
|
1333
|
+
return getMessageContext(this.db, messageIds, contextSize);
|
|
1334
|
+
}
|
|
1335
|
+
async getChatOverview(topN) {
|
|
1336
|
+
return getChatOverview(this.db, topN);
|
|
1337
|
+
}
|
|
1338
|
+
async getMembers() {
|
|
1339
|
+
return getMembersWithAliases(this.db);
|
|
1340
|
+
}
|
|
1341
|
+
async getMemberStats(options) {
|
|
1342
|
+
const top = options?.top ?? 20;
|
|
1343
|
+
const members = getMemberActivity(this.db, options?.timeFilter);
|
|
1344
|
+
return members.slice(0, top).map((m) => ({
|
|
1345
|
+
name: m.name,
|
|
1346
|
+
messageCount: m.messageCount,
|
|
1347
|
+
percentage: m.percentage
|
|
1348
|
+
}));
|
|
1349
|
+
}
|
|
1350
|
+
async getMemberNameHistory(memberId) {
|
|
1351
|
+
return getMemberNameHistory(this.db, memberId);
|
|
1352
|
+
}
|
|
1353
|
+
async getTimeStats(type, options) {
|
|
1354
|
+
const filter = options?.timeFilter;
|
|
1355
|
+
switch (type) {
|
|
1356
|
+
case "weekday":
|
|
1357
|
+
return getWeekdayActivity(this.db, filter);
|
|
1358
|
+
case "daily":
|
|
1359
|
+
return getDailyActivity(this.db, filter);
|
|
1360
|
+
case "hourly":
|
|
1361
|
+
default:
|
|
1362
|
+
return getHourlyActivity(this.db, filter);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
async searchSessions(keywords, timeFilter, limit, previewCount) {
|
|
1366
|
+
return searchSessions(this.db, keywords, timeFilter, limit, previewCount);
|
|
1367
|
+
}
|
|
1368
|
+
async getSessionMessages(chatSessionId, limit) {
|
|
1369
|
+
return getSessionMessages(this.db, chatSessionId, limit);
|
|
1370
|
+
}
|
|
1371
|
+
async getSessionSummaries(options) {
|
|
1372
|
+
return getSessionSummaries(this.db, options);
|
|
1373
|
+
}
|
|
1374
|
+
async getConversationBetween(memberId1, memberId2, timeFilter, limit) {
|
|
1375
|
+
return getConversationBetween(this.db, memberId1, memberId2, timeFilter, limit);
|
|
1376
|
+
}
|
|
1377
|
+
async executeSql(sql) {
|
|
1378
|
+
return executeReadonlySql(this.db, sql);
|
|
1379
|
+
}
|
|
1380
|
+
async executeParameterizedSql(query, params) {
|
|
1381
|
+
return executeParameterizedSql(this.db, query, params);
|
|
1382
|
+
}
|
|
1383
|
+
async getSchema() {
|
|
1384
|
+
return getDatabaseSchema(this.db);
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
export {
|
|
1389
|
+
AGENT_TOOL_REGISTRY,
|
|
1390
|
+
MCP_TOOL_REGISTRY,
|
|
1391
|
+
CoreDataProvider
|
|
1392
|
+
};
|
|
1393
|
+
//# sourceMappingURL=chunk-YAOFJ73U.mjs.map
|