@templmf/temp-solf-lmf 0.0.137 → 0.0.139
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/confMCP.js +551 -0
- package/confluenceTools.json +151 -0
- package/langgraphConfluenceTools.js +324 -0
- package/package.json +1 -1
- package/.tiktoken_cache/gpt2.json +0 -1
- package/demo.js +0 -77
package/confMCP.js
ADDED
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import LRUCache from "lru-cache";
|
|
5
|
+
import { htmlToText } from "html-to-text";
|
|
6
|
+
import BM25 from "wink-bm25-text-search";
|
|
7
|
+
|
|
8
|
+
const server = new Server({
|
|
9
|
+
name: "confluence-7.4.7",
|
|
10
|
+
version: "1.0.0"
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const baseURL = process.env.CONFLUENCE_BASE_URL;
|
|
14
|
+
const authorization = process.env.CONFLUENCE_AUTHORIZATION;
|
|
15
|
+
|
|
16
|
+
if (!baseURL || !authorization) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"CONFLUENCE_BASE_URL and CONFLUENCE_AUTHORIZATION are required"
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const client = axios.create({
|
|
23
|
+
baseURL,
|
|
24
|
+
timeout: 30000,
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: authorization,
|
|
27
|
+
Accept: "application/json"
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const pageCache = new LRUCache({
|
|
32
|
+
max: 100,
|
|
33
|
+
ttl: 1000 * 60 * 10
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
function stripHtml(html = "") {
|
|
37
|
+
return html
|
|
38
|
+
.replace(/<[^>]+>/g, " ")
|
|
39
|
+
.replace(/\s+/g, " ")
|
|
40
|
+
.trim();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function buildCql({
|
|
44
|
+
keywords = [],
|
|
45
|
+
spaces = [],
|
|
46
|
+
contributors = []
|
|
47
|
+
}) {
|
|
48
|
+
const clauses = [];
|
|
49
|
+
|
|
50
|
+
if (spaces.length) {
|
|
51
|
+
clauses.push(
|
|
52
|
+
"(" +
|
|
53
|
+
spaces
|
|
54
|
+
.map((v) => `space="${v}"`)
|
|
55
|
+
.join(" OR ") +
|
|
56
|
+
")"
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (contributors.length) {
|
|
61
|
+
clauses.push(
|
|
62
|
+
"(" +
|
|
63
|
+
contributors
|
|
64
|
+
.map((v) => `contributor="${v}"`)
|
|
65
|
+
.join(" OR ") +
|
|
66
|
+
")"
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (keywords.length) {
|
|
71
|
+
clauses.push(
|
|
72
|
+
"(" +
|
|
73
|
+
keywords
|
|
74
|
+
.map((v) => `text~"${v}"`)
|
|
75
|
+
.join(" OR ") +
|
|
76
|
+
")"
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return clauses.join(" AND ");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function getPageById(pageId) {
|
|
84
|
+
const cached = pageCache.get(pageId);
|
|
85
|
+
|
|
86
|
+
if (cached) {
|
|
87
|
+
return cached;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const { data } = await client.get(
|
|
91
|
+
`/rest/api/content/${pageId}`,
|
|
92
|
+
{
|
|
93
|
+
params: {
|
|
94
|
+
expand: "body.storage,version,space"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const result = {
|
|
100
|
+
id: data.id,
|
|
101
|
+
title: data.title,
|
|
102
|
+
space: data.space?.key,
|
|
103
|
+
version: data.version?.number,
|
|
104
|
+
url: `${baseURL}${data._links?.webui}`,
|
|
105
|
+
content: data.body?.storage?.value || ""
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
pageCache.set(pageId, result);
|
|
109
|
+
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function getPageByTitle(
|
|
114
|
+
title,
|
|
115
|
+
space
|
|
116
|
+
) {
|
|
117
|
+
const params = {
|
|
118
|
+
title,
|
|
119
|
+
expand: "body.storage"
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (space) {
|
|
123
|
+
params.spaceKey = space;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const { data } = await client.get(
|
|
127
|
+
"/rest/api/content",
|
|
128
|
+
{
|
|
129
|
+
params
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const page = data.results?.[0];
|
|
134
|
+
|
|
135
|
+
if (!page) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
id: page.id,
|
|
141
|
+
title: page.title,
|
|
142
|
+
url: `${baseURL}${page._links?.webui}`
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async function getSpaces() {
|
|
147
|
+
const { data } = await client.get(
|
|
148
|
+
"/rest/api/space"
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return data.results.map((v) => ({
|
|
152
|
+
key: v.key,
|
|
153
|
+
name: v.name
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function searchPages({
|
|
158
|
+
keywords,
|
|
159
|
+
spaces = [],
|
|
160
|
+
contributors = [],
|
|
161
|
+
limit = 10
|
|
162
|
+
}) {
|
|
163
|
+
const cql = buildCql({
|
|
164
|
+
keywords,
|
|
165
|
+
spaces,
|
|
166
|
+
contributors
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const { data } = await client.get(
|
|
170
|
+
"/rest/api/search",
|
|
171
|
+
{
|
|
172
|
+
params: {
|
|
173
|
+
cql,
|
|
174
|
+
limit
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
return data.results.map((item) => ({
|
|
180
|
+
pageId: item.content?.id,
|
|
181
|
+
title: item.title,
|
|
182
|
+
url: `${baseURL}${item.url}`
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
server.registerTool(
|
|
187
|
+
"get_page_by_id",
|
|
188
|
+
{
|
|
189
|
+
title: "Get Page By Id",
|
|
190
|
+
description:
|
|
191
|
+
"Get Confluence page content by page id",
|
|
192
|
+
inputSchema: {
|
|
193
|
+
pageId: z.string()
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
async ({ pageId }) => {
|
|
197
|
+
return await getPageById(pageId);
|
|
198
|
+
}
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
server.registerTool(
|
|
202
|
+
"get_page_by_title",
|
|
203
|
+
{
|
|
204
|
+
title: "Get Page By Title",
|
|
205
|
+
description:
|
|
206
|
+
"Find page by title",
|
|
207
|
+
inputSchema: {
|
|
208
|
+
title: z.string(),
|
|
209
|
+
space: z.string().optional()
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
async ({ title, space }) => {
|
|
213
|
+
return await getPageByTitle(
|
|
214
|
+
title,
|
|
215
|
+
space
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
);
|
|
219
|
+
|
|
220
|
+
server.registerTool(
|
|
221
|
+
"get_spaces",
|
|
222
|
+
{
|
|
223
|
+
title: "Get Spaces",
|
|
224
|
+
description:
|
|
225
|
+
"List all spaces"
|
|
226
|
+
},
|
|
227
|
+
async () => {
|
|
228
|
+
return await getSpaces();
|
|
229
|
+
}
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
server.registerTool(
|
|
233
|
+
"search_pages",
|
|
234
|
+
{
|
|
235
|
+
title: "Search Pages",
|
|
236
|
+
description:
|
|
237
|
+
"Search pages by keywords, spaces and contributors",
|
|
238
|
+
inputSchema: {
|
|
239
|
+
keywords: z
|
|
240
|
+
.array(z.string())
|
|
241
|
+
.min(1),
|
|
242
|
+
|
|
243
|
+
spaces: z
|
|
244
|
+
.array(z.string())
|
|
245
|
+
.optional(),
|
|
246
|
+
|
|
247
|
+
contributors: z
|
|
248
|
+
.array(z.string())
|
|
249
|
+
.optional(),
|
|
250
|
+
|
|
251
|
+
limit: z.number().default(10)
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
async (args) => {
|
|
255
|
+
return await searchPages(args);
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
async function getChildren(pageId) {
|
|
260
|
+
const { data } = await client.get(
|
|
261
|
+
`/rest/api/content/${pageId}/child/page`
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
return data.results.map((v) => ({
|
|
265
|
+
id: v.id,
|
|
266
|
+
title: v.title
|
|
267
|
+
}));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function buildTree(pageId, depth) {
|
|
271
|
+
const page = await getPageById(pageId);
|
|
272
|
+
|
|
273
|
+
if (depth <= 0) {
|
|
274
|
+
return {
|
|
275
|
+
id: page.id,
|
|
276
|
+
title: page.title
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const children = await getChildren(pageId);
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
id: page.id,
|
|
284
|
+
title: page.title,
|
|
285
|
+
children: await Promise.all(
|
|
286
|
+
children.map((v) =>
|
|
287
|
+
buildTree(v.id, depth - 1)
|
|
288
|
+
)
|
|
289
|
+
)
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function chunkText(
|
|
294
|
+
text,
|
|
295
|
+
size = 1200,
|
|
296
|
+
overlap = 200
|
|
297
|
+
) {
|
|
298
|
+
const chunks = [];
|
|
299
|
+
|
|
300
|
+
let start = 0;
|
|
301
|
+
|
|
302
|
+
while (start < text.length) {
|
|
303
|
+
chunks.push(
|
|
304
|
+
text.slice(start, start + size)
|
|
305
|
+
);
|
|
306
|
+
|
|
307
|
+
start += size - overlap;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return chunks;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function buildQueries(question) {
|
|
314
|
+
const queries = [question];
|
|
315
|
+
|
|
316
|
+
queries.push(
|
|
317
|
+
...question
|
|
318
|
+
.split(/[ ,,、]/)
|
|
319
|
+
.map((v) => v.trim())
|
|
320
|
+
.filter(Boolean)
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
return [...new Set(queries)];
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async function hybridSearch({
|
|
327
|
+
question,
|
|
328
|
+
spaces,
|
|
329
|
+
contributors,
|
|
330
|
+
maxPages = 10
|
|
331
|
+
}) {
|
|
332
|
+
const queries = buildQueries(question);
|
|
333
|
+
|
|
334
|
+
const weights = [
|
|
335
|
+
1,
|
|
336
|
+
0.8,
|
|
337
|
+
0.6,
|
|
338
|
+
0.4,
|
|
339
|
+
0.2
|
|
340
|
+
];
|
|
341
|
+
|
|
342
|
+
const scoreMap = new Map();
|
|
343
|
+
|
|
344
|
+
for (let i = 0; i < queries.length; i++) {
|
|
345
|
+
const pages = await searchPages({
|
|
346
|
+
keywords: [queries[i]],
|
|
347
|
+
spaces,
|
|
348
|
+
contributors,
|
|
349
|
+
limit: 20
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
for (const page of pages) {
|
|
353
|
+
const old =
|
|
354
|
+
scoreMap.get(page.pageId) || {
|
|
355
|
+
...page,
|
|
356
|
+
score: 0
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
old.score += weights[i] || 0.1;
|
|
360
|
+
|
|
361
|
+
scoreMap.set(page.pageId, old);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
return [...scoreMap.values()]
|
|
366
|
+
.sort((a, b) => b.score - a.score)
|
|
367
|
+
.slice(0, maxPages);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
async function askConfluence({
|
|
371
|
+
question,
|
|
372
|
+
spaces,
|
|
373
|
+
contributors,
|
|
374
|
+
maxPages = 10,
|
|
375
|
+
maxChunks = 15
|
|
376
|
+
}) {
|
|
377
|
+
const pages = await hybridSearch({
|
|
378
|
+
question,
|
|
379
|
+
spaces,
|
|
380
|
+
contributors,
|
|
381
|
+
maxPages
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
const documents = [];
|
|
385
|
+
|
|
386
|
+
for (const page of pages) {
|
|
387
|
+
const detail = await getPageById(
|
|
388
|
+
page.pageId
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
const text = htmlToText(
|
|
392
|
+
detail.content,
|
|
393
|
+
{
|
|
394
|
+
wordwrap: false
|
|
395
|
+
}
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
const chunks = chunkText(text);
|
|
399
|
+
|
|
400
|
+
chunks.forEach((chunk) => {
|
|
401
|
+
documents.push({
|
|
402
|
+
pageId: detail.id,
|
|
403
|
+
title: detail.title,
|
|
404
|
+
url: detail.url,
|
|
405
|
+
chunk
|
|
406
|
+
});
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const engine = BM25();
|
|
411
|
+
|
|
412
|
+
engine.defineConfig({
|
|
413
|
+
fldWeights: {
|
|
414
|
+
chunk: 1
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
engine.definePrepTasks([]);
|
|
419
|
+
|
|
420
|
+
engine.defineField("chunk");
|
|
421
|
+
|
|
422
|
+
engine.defineRef("id");
|
|
423
|
+
|
|
424
|
+
engine.configure();
|
|
425
|
+
|
|
426
|
+
documents.forEach((doc, index) => {
|
|
427
|
+
engine.addDoc(index, {
|
|
428
|
+
chunk: doc.chunk
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
engine.consolidate();
|
|
433
|
+
|
|
434
|
+
const results = engine.search(
|
|
435
|
+
question,
|
|
436
|
+
maxChunks
|
|
437
|
+
);
|
|
438
|
+
|
|
439
|
+
return results.map((v) => {
|
|
440
|
+
const doc = documents[v[0]];
|
|
441
|
+
|
|
442
|
+
return {
|
|
443
|
+
title: doc.title,
|
|
444
|
+
url: doc.url,
|
|
445
|
+
score: v[1],
|
|
446
|
+
content: doc.chunk
|
|
447
|
+
};
|
|
448
|
+
});
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
async function exploreConfluence(
|
|
452
|
+
topic
|
|
453
|
+
) {
|
|
454
|
+
const pages = await searchPages({
|
|
455
|
+
keywords: [topic],
|
|
456
|
+
limit: 5
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const result = [];
|
|
460
|
+
|
|
461
|
+
for (const page of pages) {
|
|
462
|
+
const children = await getChildren(
|
|
463
|
+
page.pageId
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
result.push({
|
|
467
|
+
page,
|
|
468
|
+
children
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
server.registerTool(
|
|
476
|
+
"get_children",
|
|
477
|
+
{
|
|
478
|
+
title: "Get Children",
|
|
479
|
+
description:
|
|
480
|
+
"Get child pages",
|
|
481
|
+
inputSchema: {
|
|
482
|
+
pageId: z.string()
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
async ({ pageId }) =>
|
|
486
|
+
getChildren(pageId)
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
server.registerTool(
|
|
490
|
+
"get_page_tree",
|
|
491
|
+
{
|
|
492
|
+
title: "Get Page Tree",
|
|
493
|
+
description:
|
|
494
|
+
"Get page tree recursively",
|
|
495
|
+
inputSchema: {
|
|
496
|
+
rootPageId: z.string(),
|
|
497
|
+
depth: z.number().default(2)
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
async ({
|
|
501
|
+
rootPageId,
|
|
502
|
+
depth
|
|
503
|
+
}) =>
|
|
504
|
+
buildTree(rootPageId, depth)
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
server.registerTool(
|
|
508
|
+
"ask_confluence",
|
|
509
|
+
{
|
|
510
|
+
title: "Ask Confluence",
|
|
511
|
+
description:
|
|
512
|
+
"Retrieve relevant contexts from Confluence",
|
|
513
|
+
|
|
514
|
+
inputSchema: {
|
|
515
|
+
question: z.string(),
|
|
516
|
+
|
|
517
|
+
spaces: z
|
|
518
|
+
.array(z.string())
|
|
519
|
+
.optional(),
|
|
520
|
+
|
|
521
|
+
contributors: z
|
|
522
|
+
.array(z.string())
|
|
523
|
+
.optional(),
|
|
524
|
+
|
|
525
|
+
maxPages: z
|
|
526
|
+
.number()
|
|
527
|
+
.default(10),
|
|
528
|
+
|
|
529
|
+
maxChunks: z
|
|
530
|
+
.number()
|
|
531
|
+
.default(15)
|
|
532
|
+
}
|
|
533
|
+
},
|
|
534
|
+
async (args) =>
|
|
535
|
+
askConfluence(args)
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
server.registerTool(
|
|
539
|
+
"explore_confluence",
|
|
540
|
+
{
|
|
541
|
+
title: "Explore Topic",
|
|
542
|
+
description:
|
|
543
|
+
"Explore topic related pages",
|
|
544
|
+
|
|
545
|
+
inputSchema: {
|
|
546
|
+
topic: z.string()
|
|
547
|
+
}
|
|
548
|
+
},
|
|
549
|
+
async ({ topic }) =>
|
|
550
|
+
exploreConfluence(topic)
|
|
551
|
+
);
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tools": [
|
|
3
|
+
{
|
|
4
|
+
"name": "get_page_by_id",
|
|
5
|
+
"description": "根据页面 ID 获取 Confluence 页面内容",
|
|
6
|
+
"parameters": [
|
|
7
|
+
{
|
|
8
|
+
"name": "pageId",
|
|
9
|
+
"type": "string",
|
|
10
|
+
"required": true,
|
|
11
|
+
"description": "Confluence 页面 ID"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "get_page_by_title",
|
|
17
|
+
"description": "根据标题查找页面",
|
|
18
|
+
"parameters": [
|
|
19
|
+
{
|
|
20
|
+
"name": "title",
|
|
21
|
+
"type": "string",
|
|
22
|
+
"required": true,
|
|
23
|
+
"description": "要查找的页面标题"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "space",
|
|
27
|
+
"type": "string",
|
|
28
|
+
"required": false,
|
|
29
|
+
"description": "空间标识,缩小搜索范围(如 DEV, OPS)"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "get_spaces",
|
|
35
|
+
"description": "列出所有空间",
|
|
36
|
+
"parameters": []
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "search_pages",
|
|
40
|
+
"description": "按关键词、空间和贡献者搜索页面",
|
|
41
|
+
"parameters": [
|
|
42
|
+
{
|
|
43
|
+
"name": "keywords",
|
|
44
|
+
"type": "array<string>",
|
|
45
|
+
"required": true,
|
|
46
|
+
"description": "要在页面内容中搜索的关键词"
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"name": "spaces",
|
|
50
|
+
"type": "array<string>",
|
|
51
|
+
"required": false,
|
|
52
|
+
"description": "按空间标识过滤"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"name": "contributors",
|
|
56
|
+
"type": "array<string>",
|
|
57
|
+
"required": false,
|
|
58
|
+
"description": "按贡献者用户名过滤"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"name": "limit",
|
|
62
|
+
"type": "number",
|
|
63
|
+
"required": false,
|
|
64
|
+
"default": 10,
|
|
65
|
+
"description": "最大返回结果数"
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"name": "get_children",
|
|
71
|
+
"description": "获取指定页面的子页面",
|
|
72
|
+
"parameters": [
|
|
73
|
+
{
|
|
74
|
+
"name": "pageId",
|
|
75
|
+
"type": "string",
|
|
76
|
+
"required": true,
|
|
77
|
+
"description": "父页面 ID"
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"name": "get_page_tree",
|
|
83
|
+
"description": "递归获取页面树",
|
|
84
|
+
"parameters": [
|
|
85
|
+
{
|
|
86
|
+
"name": "rootPageId",
|
|
87
|
+
"type": "string",
|
|
88
|
+
"required": true,
|
|
89
|
+
"description": "根页面 ID"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"name": "depth",
|
|
93
|
+
"type": "number",
|
|
94
|
+
"required": false,
|
|
95
|
+
"default": 2,
|
|
96
|
+
"description": "递归深度"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "ask_confluence",
|
|
102
|
+
"description": "使用混合搜索 + BM25 重排序检索 Confluence 相关内容",
|
|
103
|
+
"parameters": [
|
|
104
|
+
{
|
|
105
|
+
"name": "question",
|
|
106
|
+
"type": "string",
|
|
107
|
+
"required": true,
|
|
108
|
+
"description": "自然语言问题,用于搜索 Confluence"
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"name": "spaces",
|
|
112
|
+
"type": "array<string>",
|
|
113
|
+
"required": false,
|
|
114
|
+
"description": "按空间标识过滤"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"name": "contributors",
|
|
118
|
+
"type": "array<string>",
|
|
119
|
+
"required": false,
|
|
120
|
+
"description": "按贡献者用户名过滤"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"name": "maxPages",
|
|
124
|
+
"type": "number",
|
|
125
|
+
"required": false,
|
|
126
|
+
"default": 10,
|
|
127
|
+
"description": "在分块前最多获取的页面数"
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
"name": "maxChunks",
|
|
131
|
+
"type": "number",
|
|
132
|
+
"required": false,
|
|
133
|
+
"default": 15,
|
|
134
|
+
"description": "BM25 重排序后返回的最大文本块数"
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
"name": "explore_confluence",
|
|
140
|
+
"description": "探索与主题相关的页面及其子页面",
|
|
141
|
+
"parameters": [
|
|
142
|
+
{
|
|
143
|
+
"name": "topic",
|
|
144
|
+
"type": "string",
|
|
145
|
+
"required": true,
|
|
146
|
+
"description": "要探索的主题关键词"
|
|
147
|
+
}
|
|
148
|
+
]
|
|
149
|
+
}
|
|
150
|
+
]
|
|
151
|
+
}
|