@opentiny/next-sdk 0.2.2 → 0.2.4
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/README.md +635 -5
- package/agent/AgentModelProvider.ts +108 -65
- package/agent/type.ts +1 -1
- package/agent/utils/getAISDKTools.ts +2 -2
- package/dist/agent/AgentModelProvider.d.ts +5 -5
- package/dist/agent/type.d.ts +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.es.dev.js +12181 -9736
- package/dist/index.es.js +22179 -20013
- package/dist/index.js +2176 -923
- package/dist/index.umd.dev.js +12210 -9766
- package/dist/index.umd.js +92 -79
- package/dist/{mcpsdk@1.25.2.dev.js → mcpsdk@1.25.3.dev.js} +3 -1
- package/dist/{mcpsdk@1.25.2.es.dev.js → mcpsdk@1.25.3.es.dev.js} +3 -1
- package/dist/{mcpsdk@1.25.2.es.js → mcpsdk@1.25.3.es.js} +1855 -1855
- package/dist/{mcpsdk@1.25.2.js → mcpsdk@1.25.3.js} +13 -13
- package/dist/remoter/createRemoter.d.ts +7 -2
- package/dist/skills/index.d.ts +54 -0
- package/dist/webagent.dev.js +22244 -16351
- package/dist/webagent.es.dev.js +21932 -16038
- package/dist/webagent.es.js +24792 -20100
- package/dist/webagent.js +73 -65
- package/dist/webmcp-full.dev.js +3 -1
- package/dist/webmcp-full.es.dev.js +3 -1
- package/dist/webmcp-full.es.js +523 -523
- package/dist/webmcp-full.js +9 -9
- package/index.ts +14 -0
- package/package.json +21 -6
- package/remoter/createRemoter.ts +75 -40
- package/skills/index.ts +141 -0
package/index.ts
CHANGED
|
@@ -38,3 +38,17 @@ export { getAISDKTools } from './agent/utils/getAISDKTools'
|
|
|
38
38
|
// 方便的二维码类
|
|
39
39
|
export { QrCode, type QrCodeOption } from './remoter/QrCode'
|
|
40
40
|
export type * from './agent/type'
|
|
41
|
+
|
|
42
|
+
// Web 端 Skill 公共能力:解析 skill 文档、生成 systemPrompt、内置 list_skills / get_skill_content 工具
|
|
43
|
+
export {
|
|
44
|
+
getSkillOverviews,
|
|
45
|
+
formatSkillsForSystemPrompt,
|
|
46
|
+
getSkillMdPaths,
|
|
47
|
+
getSkillMdContent,
|
|
48
|
+
getMainSkillPaths,
|
|
49
|
+
getMainSkillPathByName,
|
|
50
|
+
parseSkillFrontMatter,
|
|
51
|
+
createSkillTools,
|
|
52
|
+
type SkillMeta,
|
|
53
|
+
type SkillToolsSet
|
|
54
|
+
} from './skills/index'
|
package/package.json
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opentiny/next-sdk",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"homepage": "https://docs.opentiny.design/next-sdk/guide/",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git@github.com:opentiny/next-sdk.git"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/opentiny/next-sdk/issues"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"next-sdk",
|
|
15
|
+
"opentiny",
|
|
16
|
+
"mcp",
|
|
17
|
+
"sdk",
|
|
18
|
+
"agent"
|
|
19
|
+
],
|
|
5
20
|
"license": "MIT",
|
|
6
21
|
"author": "Chunhui Mo",
|
|
7
22
|
"main": "dist/index.js",
|
|
8
23
|
"module": "dist/index.js",
|
|
9
24
|
"types": "dist/index.d.ts",
|
|
10
|
-
"description": "
|
|
25
|
+
"description": "A frontend intelligent application development toolkit designed to simplify WebAgent integration and usage, supporting multiple programming languages and frontend frameworks to help developers rapidly implement intelligent features",
|
|
11
26
|
"dependencies": {
|
|
12
27
|
"@modelcontextprotocol/sdk": "~1.25.2",
|
|
13
28
|
"@opentiny/next": "^0.3.2",
|
|
14
|
-
"@ai-sdk/openai": "^
|
|
29
|
+
"@ai-sdk/openai": "^3.0.0",
|
|
15
30
|
"@ai-sdk/deepseek": "1.0.30",
|
|
16
|
-
"@ai-sdk/provider": "^
|
|
17
|
-
"@ai-sdk/mcp": "^0.0
|
|
31
|
+
"@ai-sdk/provider": "^3.0.0",
|
|
32
|
+
"@ai-sdk/mcp": "^1.0.0",
|
|
18
33
|
"qrcode": "^1.5.4",
|
|
19
34
|
"zod": "^3.25.76",
|
|
20
35
|
"ajv": "^8.17.1",
|
|
21
|
-
"ai": "
|
|
36
|
+
"ai": "^6.0.0"
|
|
22
37
|
},
|
|
23
38
|
"devDependencies": {
|
|
24
39
|
"typescript": "~5.9.3",
|
package/remoter/createRemoter.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { QrCode } from './QrCode'
|
|
2
|
-
import { Tooltip } from './tooltips'
|
|
3
|
-
import chat from './svgs/chat.svg?url'
|
|
4
|
-
import scan from './svgs/scan.svg?url'
|
|
5
|
-
import link from './svgs/link.svg?url'
|
|
6
|
-
import qrCode from './svgs/qrcode.svg?url'
|
|
7
|
-
import iconCopy from './svgs/icon-copy.svg?url'
|
|
8
|
-
|
|
9
|
-
const DEFAULT_REMOTE_URL = 'https://
|
|
2
|
+
import { Tooltip } from './tooltips'
|
|
3
|
+
import chat from './svgs/chat.svg?url'
|
|
4
|
+
import scan from './svgs/scan.svg?url'
|
|
5
|
+
import link from './svgs/link.svg?url'
|
|
6
|
+
import qrCode from './svgs/qrcode.svg?url'
|
|
7
|
+
import iconCopy from './svgs/icon-copy.svg?url'
|
|
8
|
+
|
|
9
|
+
const DEFAULT_REMOTE_URL = 'https://chat.opentiny.design'
|
|
10
10
|
const DEFAULT_QR_CODE_URL = 'https://ai.opentiny.design/next-remoter'
|
|
11
|
+
const DEFAULT_LOGO_URL = 'https://ai.opentiny.design/next-remoter/svgs/logo-next-no-bg-left.svg'
|
|
11
12
|
|
|
12
13
|
/** 菜单项配置接口 */
|
|
13
14
|
export interface MenuItemConfig {
|
|
@@ -20,7 +21,7 @@ export interface MenuItemConfig {
|
|
|
20
21
|
/** 菜单文字颜色 */
|
|
21
22
|
active?: boolean
|
|
22
23
|
/** 识别码 */
|
|
23
|
-
know?: boolean
|
|
24
|
+
know?: boolean
|
|
24
25
|
/** 菜单项描述 */
|
|
25
26
|
desc?: string
|
|
26
27
|
/** 菜单项提示 */
|
|
@@ -42,8 +43,10 @@ export interface FloatingBlockOptions {
|
|
|
42
43
|
sessionId: string
|
|
43
44
|
/** 菜单项配置 */
|
|
44
45
|
menuItems?: MenuItemConfig[]
|
|
45
|
-
/** 遥控端页面地址,默认为: https://
|
|
46
|
+
/** 遥控端页面地址,默认为: https://chat.opentiny.design */
|
|
46
47
|
remoteUrl?: string
|
|
48
|
+
/** 悬浮Logo的url地址,默认为: https://ai.opentiny.design/next-remoter/svgs/logo-next-no-bg-left.svg */
|
|
49
|
+
logoUrl?: string
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
// 动作类型
|
|
@@ -83,7 +86,7 @@ const getDefaultMenuItems = (options: FloatingBlockOptions): MenuItemConfig[] =>
|
|
|
83
86
|
know: true,
|
|
84
87
|
showCopyIcon: true,
|
|
85
88
|
icon: scan
|
|
86
|
-
}
|
|
89
|
+
}
|
|
87
90
|
]
|
|
88
91
|
}
|
|
89
92
|
|
|
@@ -93,6 +96,8 @@ class FloatingBlock {
|
|
|
93
96
|
private floatingBlock!: HTMLDivElement
|
|
94
97
|
private dropdownMenu!: HTMLDivElement
|
|
95
98
|
private menuItems: MenuItemConfig[]
|
|
99
|
+
/** 即将关闭dropdown的定时器 */
|
|
100
|
+
private closingTimer = 0
|
|
96
101
|
|
|
97
102
|
// 计算 sessionPrefix 属性
|
|
98
103
|
private get sessionPrefix(): string {
|
|
@@ -107,34 +112,37 @@ class FloatingBlock {
|
|
|
107
112
|
this.options = {
|
|
108
113
|
...options,
|
|
109
114
|
qrCodeUrl: options.qrCodeUrl || DEFAULT_QR_CODE_URL,
|
|
110
|
-
remoteUrl: options.remoteUrl || DEFAULT_REMOTE_URL
|
|
115
|
+
remoteUrl: options.remoteUrl || DEFAULT_REMOTE_URL,
|
|
116
|
+
logoUrl: options.logoUrl || DEFAULT_LOGO_URL
|
|
111
117
|
}
|
|
112
118
|
|
|
113
|
-
//
|
|
114
|
-
|
|
119
|
+
// 合并默认菜单项配置和用户配置。 用户不传入任何menu时, 则不自动合并默认菜单了,即不渲染任何菜单。
|
|
120
|
+
if (options.menuItems && options.menuItems.length === 0) {
|
|
121
|
+
this.menuItems = []
|
|
122
|
+
} else {
|
|
123
|
+
this.menuItems = this.mergeMenuItems(options.menuItems)
|
|
124
|
+
}
|
|
115
125
|
|
|
116
126
|
this.init()
|
|
117
127
|
}
|
|
118
128
|
|
|
119
129
|
private getImageUrl = (asset: string | undefined): HTMLImageElement | undefined => {
|
|
120
|
-
if (!asset) return
|
|
121
|
-
const img = new Image()
|
|
122
|
-
img.src = asset
|
|
123
|
-
return img
|
|
130
|
+
if (!asset) return
|
|
131
|
+
const img = new Image()
|
|
132
|
+
img.src = asset
|
|
133
|
+
return img
|
|
124
134
|
}
|
|
125
135
|
|
|
126
136
|
private renderItem = (): void => {
|
|
127
137
|
this.menuItems
|
|
128
138
|
.filter((item) => item.show !== false) // 过滤掉show为false的菜单项
|
|
129
|
-
.map(
|
|
130
|
-
(item)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
);
|
|
139
|
+
.map((item) => {
|
|
140
|
+
const wrapper = document.getElementById(`tiny-remoter-icon-item-${item.action}`) as HTMLDivElement
|
|
141
|
+
if (!wrapper) return
|
|
142
|
+
wrapper.innerHTML = ''
|
|
143
|
+
const img = this.getImageUrl(item.icon)
|
|
144
|
+
if (img) wrapper.appendChild(img)
|
|
145
|
+
})
|
|
138
146
|
}
|
|
139
147
|
|
|
140
148
|
/**
|
|
@@ -174,7 +182,7 @@ class FloatingBlock {
|
|
|
174
182
|
this.floatingBlock.className = 'tiny-remoter-floating-block'
|
|
175
183
|
this.floatingBlock.innerHTML = `
|
|
176
184
|
<div class="tiny-remoter-floating-block__icon">
|
|
177
|
-
<img style="display: block; width: 56px;" src="${
|
|
185
|
+
<img style="display: block; width: 56px;" src="${this.options.logoUrl}" alt="icon" />
|
|
178
186
|
</div>
|
|
179
187
|
`
|
|
180
188
|
|
|
@@ -211,13 +219,14 @@ class FloatingBlock {
|
|
|
211
219
|
<div class="tiny-remoter-dropdown-item__desc-wrapper">
|
|
212
220
|
<div class="tiny-remoter-dropdown-item__desc ${item.active ? 'tiny-remoter-dropdown-item__desc--active' : ''} ${item.know ? 'tiny-remoter-dropdown-item__desc--know' : ''}">${item.desc}</div>
|
|
213
221
|
<div>
|
|
214
|
-
${
|
|
215
|
-
|
|
222
|
+
${
|
|
223
|
+
item.showCopyIcon
|
|
224
|
+
? `
|
|
216
225
|
<div class="tiny-remoter-copy-icon" id="${item.action}" data-action="${item.action}">
|
|
217
226
|
<img src="${iconCopy}"/>
|
|
218
227
|
</div>
|
|
219
228
|
`
|
|
220
|
-
|
|
229
|
+
: ''
|
|
221
230
|
}
|
|
222
231
|
</div>
|
|
223
232
|
</div>
|
|
@@ -234,11 +243,33 @@ class FloatingBlock {
|
|
|
234
243
|
this.readyTips(`remote-url`)
|
|
235
244
|
}
|
|
236
245
|
|
|
237
|
-
|
|
238
246
|
private bindEvents(): void {
|
|
239
247
|
// 绑定浮动块点击事件
|
|
240
248
|
this.floatingBlock.addEventListener('click', () => {
|
|
241
|
-
this.
|
|
249
|
+
this.showAIChat()
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
// 浮动块悬浮处理
|
|
253
|
+
this.floatingBlock.addEventListener('mouseenter', () => {
|
|
254
|
+
this.openDropdown()
|
|
255
|
+
|
|
256
|
+
if (this.closingTimer) {
|
|
257
|
+
window.clearTimeout(this.closingTimer)
|
|
258
|
+
this.closingTimer = 0
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
this.floatingBlock.addEventListener('mouseleave', () => {
|
|
262
|
+
this.shouldCloseDropdown()
|
|
263
|
+
})
|
|
264
|
+
// 悬浮菜单进入,则阻止关闭
|
|
265
|
+
this.dropdownMenu.addEventListener('mouseenter', (e: Event) => {
|
|
266
|
+
if (this.closingTimer) {
|
|
267
|
+
window.clearTimeout(this.closingTimer)
|
|
268
|
+
this.closingTimer = 0
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
this.dropdownMenu.addEventListener('mouseleave', (e: Event) => {
|
|
272
|
+
this.shouldCloseDropdown()
|
|
242
273
|
})
|
|
243
274
|
|
|
244
275
|
// 绑定菜单项点击事件
|
|
@@ -280,20 +311,24 @@ class FloatingBlock {
|
|
|
280
311
|
})
|
|
281
312
|
}
|
|
282
313
|
|
|
283
|
-
private
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
this.openDropdown()
|
|
314
|
+
private openDropdown(): void {
|
|
315
|
+
// 没有menuItems,则返回
|
|
316
|
+
if (!this.menuItems || (this.menuItems && this.menuItems.length === 0)) {
|
|
317
|
+
return
|
|
288
318
|
}
|
|
289
|
-
}
|
|
290
319
|
|
|
291
|
-
private openDropdown(): void {
|
|
292
320
|
this.isExpanded = true
|
|
293
321
|
this.floatingBlock.classList.add('expanded')
|
|
294
322
|
this.dropdownMenu.classList.add('show')
|
|
295
323
|
}
|
|
296
324
|
|
|
325
|
+
private shouldCloseDropdown() {
|
|
326
|
+
this.closingTimer = window.setTimeout(() => {
|
|
327
|
+
this.closeDropdown()
|
|
328
|
+
}, 300)
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/** 真正的立即关闭 */
|
|
297
332
|
private closeDropdown(): void {
|
|
298
333
|
this.isExpanded = false
|
|
299
334
|
this.floatingBlock.classList.remove('expanded')
|
package/skills/index.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web 端 Skill 公共能力模块(next-sdk)
|
|
3
|
+
* - 提供解析、概况、systemPrompt 拼接、按路径/名称查文档
|
|
4
|
+
* - 提供 createSkillTools:供 remoter 注入 get_skill_content 工具,大模型可按需加载技能文档
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { tool } from 'ai'
|
|
8
|
+
import { z } from 'zod'
|
|
9
|
+
|
|
10
|
+
/** 主 SKILL.md 路径格式:仅匹配一级子目录下的 SKILL.md,如 ./calculator/SKILL.md */
|
|
11
|
+
const MAIN_SKILL_PATH_REG = /^\.\/[^/]+\/SKILL\.md$/
|
|
12
|
+
|
|
13
|
+
/** 从 front matter 中提取 name 和 description 的正则(--- 与 --- 之间) */
|
|
14
|
+
const FRONT_MATTER_BLOCK_REG = /^---\s*\n([\s\S]+?)\s*\n---/
|
|
15
|
+
|
|
16
|
+
/** 单个技能的概况信息(从主 SKILL.md 的 front matter 提取) */
|
|
17
|
+
export interface SkillMeta {
|
|
18
|
+
/** 技能名称,与 skill 目录名一致 */
|
|
19
|
+
name: string
|
|
20
|
+
/** 技能描述,用于 systemPrompt */
|
|
21
|
+
description: string
|
|
22
|
+
/** 主 SKILL.md 相对路径,如 ./calculator/SKILL.md */
|
|
23
|
+
path: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* 从主 SKILL.md 的 YAML front matter 中用正则提取 name、description
|
|
28
|
+
*/
|
|
29
|
+
export function parseSkillFrontMatter(content: string): { name: string; description: string } | null {
|
|
30
|
+
// 先提取 --- 之间的文本块
|
|
31
|
+
const blockMatch = content.match(FRONT_MATTER_BLOCK_REG)
|
|
32
|
+
if (!blockMatch?.[1]) return null
|
|
33
|
+
const block = blockMatch[1]
|
|
34
|
+
|
|
35
|
+
// 分别匹配 name 和 description 字段(支持任意顺序)
|
|
36
|
+
const nameMatch = block.match(/^name:\s*(.+)$/m)
|
|
37
|
+
const descMatch = block.match(/^description:\s*(.+)$/m)
|
|
38
|
+
|
|
39
|
+
const name = nameMatch?.[1]?.trim()
|
|
40
|
+
const description = descMatch?.[1]?.trim()
|
|
41
|
+
|
|
42
|
+
return name && description ? { name, description } : null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 获取所有「主 SKILL.md」的路径(一级子目录下的 SKILL.md)
|
|
47
|
+
*/
|
|
48
|
+
export function getMainSkillPaths(modules: Record<string, string>): string[] {
|
|
49
|
+
return Object.keys(modules).filter((path) => MAIN_SKILL_PATH_REG.test(path))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 获取所有技能的概况列表(name、description、path),用于 systemPrompt 或列表展示
|
|
54
|
+
*/
|
|
55
|
+
export function getSkillOverviews(modules: Record<string, string>): SkillMeta[] {
|
|
56
|
+
const mainPaths = getMainSkillPaths(modules)
|
|
57
|
+
const list: SkillMeta[] = []
|
|
58
|
+
for (const path of mainPaths) {
|
|
59
|
+
const content = modules[path]
|
|
60
|
+
if (!content) continue
|
|
61
|
+
const parsed = parseSkillFrontMatter(content)
|
|
62
|
+
if (!parsed) continue
|
|
63
|
+
list.push({
|
|
64
|
+
name: parsed.name,
|
|
65
|
+
description: parsed.description,
|
|
66
|
+
path
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
return list
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 格式化为大模型 systemPrompt 可用的技能说明文本
|
|
74
|
+
* @param skills 不传则需由调用方传入从 getSkillOverviews 得到的结果
|
|
75
|
+
*/
|
|
76
|
+
export function formatSkillsForSystemPrompt(skills: SkillMeta[]): string {
|
|
77
|
+
if (skills.length === 0) return ''
|
|
78
|
+
const lines = skills.map((s) => `- **${s.name}**: ${s.description}`)
|
|
79
|
+
return `## 可用技能\n\n${lines.join('\n')}\n\n当需要用到某技能时,请使用 get_skill_content 工具获取该技能的完整文档内容。`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 获取所有已加载的 md 文件路径(含主 SKILL.md 与 reference 等)
|
|
84
|
+
*/
|
|
85
|
+
export function getSkillMdPaths(modules: Record<string, string>): string[] {
|
|
86
|
+
return Object.keys(modules)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 根据相对路径获取某个 md 文档的原始内容
|
|
91
|
+
*/
|
|
92
|
+
export function getSkillMdContent(modules: Record<string, string>, path: string): string | undefined {
|
|
93
|
+
return modules[path]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 根据技能 name 查找其主 SKILL.md 的路径(name 与目录名一致)
|
|
98
|
+
*/
|
|
99
|
+
export function getMainSkillPathByName(modules: Record<string, string>, name: string): string | undefined {
|
|
100
|
+
return getMainSkillPaths(modules).find((p) => p.startsWith(`./${name}/SKILL.md`))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ============ 内置工具:供 remoter 注入,替代业界 skill 中「读取文档」的操作 ============
|
|
104
|
+
|
|
105
|
+
/** AI SDK Tool 类型,用于 extraTools 合并,不写死泛型避免与 ai 包版本强绑定 */
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
107
|
+
export type SkillToolsSet = Record<string, any>
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 根据 skillMdModules 创建供 AI 调用的工具集
|
|
111
|
+
* - get_skill_content: 按技能名或路径获取完整文档内容,便于大模型自动识别并加载技能
|
|
112
|
+
* remoter 可将返回的 tools 合并进 extraTools 注入 agent
|
|
113
|
+
*/
|
|
114
|
+
export function createSkillTools(modules: Record<string, string>): SkillToolsSet {
|
|
115
|
+
const getSkillContent = tool({
|
|
116
|
+
description:
|
|
117
|
+
'根据技能名称或文档路径获取该技能的完整 Markdown 文档内容。传入 skillName(如 calculator)或 path(如 ./calculator/SKILL.md)',
|
|
118
|
+
inputSchema: z.object({
|
|
119
|
+
skillName: z.string().optional().describe('技能名称,与目录名一致,如 calculator'),
|
|
120
|
+
path: z.string().optional().describe('文档相对路径,如 ./calculator/SKILL.md 或 ./product-guide/reference/xxx.md')
|
|
121
|
+
}),
|
|
122
|
+
execute: (args: { skillName?: string; path?: string }) => {
|
|
123
|
+
const { skillName, path: pathArg } = args
|
|
124
|
+
let content: string | undefined
|
|
125
|
+
if (pathArg) {
|
|
126
|
+
content = getSkillMdContent(modules, pathArg)
|
|
127
|
+
} else if (skillName) {
|
|
128
|
+
const mainPath = getMainSkillPathByName(modules, skillName)
|
|
129
|
+
content = mainPath ? getSkillMdContent(modules, mainPath) : undefined
|
|
130
|
+
}
|
|
131
|
+
if (content === undefined) {
|
|
132
|
+
return { error: '未找到对应技能文档', skillName: skillName ?? pathArg }
|
|
133
|
+
}
|
|
134
|
+
return { content, path: pathArg ?? getMainSkillPathByName(modules, skillName!) }
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
get_skill_content: getSkillContent
|
|
140
|
+
}
|
|
141
|
+
}
|