@opentiny/next-sdk 0.2.7 → 0.2.9
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/agent/AgentModelProvider.ts +22 -10
- package/dist/agent/AgentModelProvider.d.ts +3 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.es.dev.js +476 -23
- package/dist/index.es.js +6622 -6273
- package/dist/index.js +2120 -1771
- package/dist/index.umd.dev.js +476 -23
- package/dist/index.umd.js +217 -49
- package/dist/{page-tool-bridge.d.ts → page-tools/bridge.d.ts} +34 -42
- package/dist/page-tools/effects.d.ts +36 -0
- package/dist/remoter/createRemoter.d.ts +2 -0
- package/dist/skills/index.d.ts +2 -1
- package/dist/webagent.dev.js +31 -7
- package/dist/webagent.es.dev.js +31 -7
- package/dist/webagent.es.js +33 -17
- package/dist/webagent.js +3 -3
- package/index.ts +1 -1
- package/package.json +1 -1
- package/{page-tool-bridge.ts → page-tools/bridge.ts} +170 -95
- package/page-tools/effects.ts +343 -0
- package/remoter/createRemoter.ts +25 -11
- package/skills/index.ts +109 -12
package/remoter/createRemoter.ts
CHANGED
|
@@ -159,18 +159,17 @@ class FloatingBlock {
|
|
|
159
159
|
return getDefaultMenuItems(this.options)
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
return getDefaultMenuItems(this.options)
|
|
163
|
-
.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
show: userItem.show !== undefined ? userItem.show : defaultItem.show
|
|
170
|
-
}
|
|
162
|
+
return getDefaultMenuItems(this.options).map((defaultItem) => {
|
|
163
|
+
const userItem = userMenuItems.find((item) => item.action === defaultItem.action)
|
|
164
|
+
if (userItem) {
|
|
165
|
+
return {
|
|
166
|
+
...defaultItem,
|
|
167
|
+
...userItem,
|
|
168
|
+
show: userItem.show !== undefined ? userItem.show : defaultItem.show
|
|
171
169
|
}
|
|
172
|
-
|
|
173
|
-
|
|
170
|
+
}
|
|
171
|
+
return defaultItem
|
|
172
|
+
})
|
|
174
173
|
}
|
|
175
174
|
|
|
176
175
|
private init(): void {
|
|
@@ -913,6 +912,21 @@ class FloatingBlock {
|
|
|
913
912
|
this.dropdownMenu.parentNode.removeChild(this.dropdownMenu)
|
|
914
913
|
}
|
|
915
914
|
}
|
|
915
|
+
|
|
916
|
+
// 隐藏组件
|
|
917
|
+
public hide(): void {
|
|
918
|
+
if (this.floatingBlock) {
|
|
919
|
+
this.floatingBlock.style.display = 'none'
|
|
920
|
+
}
|
|
921
|
+
this.closeDropdown()
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// 显示组件
|
|
925
|
+
public show(): void {
|
|
926
|
+
if (this.floatingBlock) {
|
|
927
|
+
this.floatingBlock.style.display = 'flex'
|
|
928
|
+
}
|
|
929
|
+
}
|
|
916
930
|
}
|
|
917
931
|
|
|
918
932
|
// 导出组件
|
package/skills/index.ts
CHANGED
|
@@ -115,15 +115,44 @@ export function getSkillMdPaths(modules: Record<string, string>): string[] {
|
|
|
115
115
|
*/
|
|
116
116
|
export function getSkillMdContent(modules: Record<string, string>, path: string): string | undefined {
|
|
117
117
|
const normalized = normalizeSkillModuleKeys(modules)
|
|
118
|
-
|
|
118
|
+
|
|
119
|
+
// 1. 尝试原有的严格匹配
|
|
120
|
+
const exactMatch = normalized[path]
|
|
121
|
+
if (exactMatch) return exactMatch
|
|
122
|
+
|
|
123
|
+
// 2. 降级匹配:如果严格匹配完整路径未找到
|
|
124
|
+
// 则尝试寻找后缀能够匹配上的真实文件路径。
|
|
125
|
+
// 去除开头的 '.' 或 './' 以精确匹配结尾部分的路径。
|
|
126
|
+
const suffix = path.replace(/^\.?\//, '/')
|
|
127
|
+
const matchingKey = Object.keys(normalized).find((key) => key.endsWith(suffix))
|
|
128
|
+
return matchingKey ? normalized[matchingKey] : undefined
|
|
119
129
|
}
|
|
120
130
|
|
|
121
131
|
/**
|
|
122
|
-
* 根据技能 name 查找其主 SKILL.md
|
|
132
|
+
* 根据技能 name 查找其主 SKILL.md 的路径
|
|
133
|
+
* 支持匹配目录名(如 ecommerce)或 SKILL.md 内 frontmatter 定义的 name
|
|
123
134
|
* - 依赖 getMainSkillPaths,内部已做 normalize
|
|
124
135
|
*/
|
|
125
136
|
export function getMainSkillPathByName(modules: Record<string, string>, name: string): string | undefined {
|
|
126
|
-
|
|
137
|
+
const normalizedModules = normalizeSkillModuleKeys(modules)
|
|
138
|
+
const paths = getMainSkillPaths(normalizedModules)
|
|
139
|
+
|
|
140
|
+
// 1. 先尝试按目录名精确匹配 (兼容老逻辑)
|
|
141
|
+
const dirMatch = paths.find((p) => p.startsWith(`./${name}/SKILL.md`))
|
|
142
|
+
if (dirMatch) return dirMatch
|
|
143
|
+
|
|
144
|
+
// 2. 如果按目录名找不到,则解析内容按 frontmatter 的 name 匹配
|
|
145
|
+
for (const p of paths) {
|
|
146
|
+
const content = normalizedModules[p]
|
|
147
|
+
if (content) {
|
|
148
|
+
const parsed = parseSkillFrontMatter(content)
|
|
149
|
+
if (parsed && parsed.name === name) {
|
|
150
|
+
return p
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return undefined
|
|
127
156
|
}
|
|
128
157
|
|
|
129
158
|
// ============ 内置工具:供 remoter 注入,替代业界 skill 中「读取文档」的操作 ============
|
|
@@ -134,8 +163,22 @@ export type SkillToolsSet = Record<string, any>
|
|
|
134
163
|
|
|
135
164
|
// 提升为模块级常量:避免 tool() 推断 PARAMETERS 泛型时递归展开 Zod 链导致"类型实例化过深"
|
|
136
165
|
const SKILL_INPUT_SCHEMA = z.object({
|
|
137
|
-
skillName: z
|
|
138
|
-
|
|
166
|
+
skillName: z
|
|
167
|
+
.string()
|
|
168
|
+
.optional()
|
|
169
|
+
.describe(
|
|
170
|
+
'进入某个技能的主入口名称。优先匹配技能的目录名(如 ecommerce),或者技能的中文名称(如"客户价保单创建及审核")。'
|
|
171
|
+
),
|
|
172
|
+
path: z
|
|
173
|
+
.string()
|
|
174
|
+
.optional()
|
|
175
|
+
.describe('你想查阅的文档的路径。如 ./calculator/SKILL.md 或从其他文档里看到的相对路径 ./reference/inventory.md。'),
|
|
176
|
+
currentPath: z
|
|
177
|
+
.string()
|
|
178
|
+
.optional()
|
|
179
|
+
.describe(
|
|
180
|
+
'你当前正在阅读的文档路径(如果有)。比如你刚刚读取了 ./ecommerce/SKILL.md,请把这个路径原样传回来,这样系统才能根据你的相对路径准确找到下一份文件。'
|
|
181
|
+
)
|
|
139
182
|
})
|
|
140
183
|
|
|
141
184
|
/**
|
|
@@ -145,23 +188,77 @@ const SKILL_INPUT_SCHEMA = z.object({
|
|
|
145
188
|
*/
|
|
146
189
|
export function createSkillTools(modules: Record<string, string>): SkillToolsSet {
|
|
147
190
|
const normalizedModules = normalizeSkillModuleKeys(modules)
|
|
191
|
+
|
|
192
|
+
// @ts-ignore ai package 的 tool() 函数类型推断存在"类型实例化过深"的已知限制,无法正确推断包含复杂 Zod 链的 schema
|
|
148
193
|
const getSkillContent = tool({
|
|
149
194
|
description:
|
|
150
|
-
'
|
|
195
|
+
'根据技能名称或文档路径获取该技能的完整文档内容。如果你想根据相对路径查阅文件,请务必同时提供你当前所在的文件路径 currentPath。',
|
|
151
196
|
inputSchema: SKILL_INPUT_SCHEMA,
|
|
152
|
-
execute: (args: { skillName?: string; path?: string }): Record<string, unknown> => {
|
|
153
|
-
const { skillName, path: pathArg } = args
|
|
197
|
+
execute: (args: { skillName?: string; path?: string; currentPath?: string }): Record<string, unknown> => {
|
|
198
|
+
const { skillName, path: pathArg, currentPath: currentPathArg } = args
|
|
154
199
|
let content: string | undefined
|
|
200
|
+
let resolvedPath = ''
|
|
201
|
+
|
|
155
202
|
if (pathArg) {
|
|
156
|
-
|
|
203
|
+
// 使用明确提供的当前阅读上下文作为基准路径(默认在根目录)
|
|
204
|
+
let basePathContext = '.'
|
|
205
|
+
if (currentPathArg) {
|
|
206
|
+
// 提取出当前文档所在的目录
|
|
207
|
+
// 比如 ./ecommerce/SKILL.md -> ./ecommerce
|
|
208
|
+
const lastSlashIndex = currentPathArg.lastIndexOf('/')
|
|
209
|
+
if (lastSlashIndex >= 0) {
|
|
210
|
+
basePathContext = currentPathArg.slice(0, lastSlashIndex)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 尝试 1:按照大模型当前提供的上下文进行标准相对路径解析
|
|
215
|
+
const dummyBase = `http://localhost/${basePathContext}/`
|
|
216
|
+
const url = new URL(pathArg, dummyBase)
|
|
217
|
+
resolvedPath = '.' + url.pathname
|
|
218
|
+
content = getSkillMdContent(normalizedModules, resolvedPath)
|
|
219
|
+
|
|
220
|
+
// 尝试 2:如果大模型忘了传正确的 currentPath,或者是强行传错,做个智能根目录回退
|
|
221
|
+
if (content === undefined && (pathArg.startsWith('./') || pathArg.startsWith('../')) && currentPathArg) {
|
|
222
|
+
const baseParts = currentPathArg.split('/')
|
|
223
|
+
if (baseParts.length >= 2) {
|
|
224
|
+
const skillRoot = baseParts[1]
|
|
225
|
+
const fallbackDummyBase = `http://localhost/${skillRoot}/`
|
|
226
|
+
const fallbackUrl = new URL(pathArg, fallbackDummyBase)
|
|
227
|
+
const fallbackPath = '.' + fallbackUrl.pathname
|
|
228
|
+
content = getSkillMdContent(normalizedModules, fallbackPath)
|
|
229
|
+
if (content) {
|
|
230
|
+
resolvedPath = fallbackPath
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 尝试 3:后缀自动降级匹配修正
|
|
236
|
+
if (content && !normalizedModules[resolvedPath]) {
|
|
237
|
+
const suffix = resolvedPath.replace(/^\.?\//, '/')
|
|
238
|
+
const matchingKey = Object.keys(normalizedModules).find((key) => key.endsWith(suffix))
|
|
239
|
+
if (matchingKey) {
|
|
240
|
+
resolvedPath = matchingKey
|
|
241
|
+
}
|
|
242
|
+
}
|
|
157
243
|
} else if (skillName) {
|
|
158
244
|
const mainPath = getMainSkillPathByName(normalizedModules, skillName)
|
|
159
|
-
|
|
245
|
+
if (mainPath) {
|
|
246
|
+
resolvedPath = mainPath
|
|
247
|
+
content = getSkillMdContent(normalizedModules, mainPath)
|
|
248
|
+
}
|
|
160
249
|
}
|
|
250
|
+
|
|
161
251
|
if (content === undefined) {
|
|
162
|
-
return {
|
|
252
|
+
return {
|
|
253
|
+
error: '未找到对应技能文档',
|
|
254
|
+
skillName,
|
|
255
|
+
path: pathArg,
|
|
256
|
+
providedCurrentPath: currentPathArg,
|
|
257
|
+
attemptedPath: resolvedPath
|
|
258
|
+
}
|
|
163
259
|
}
|
|
164
|
-
|
|
260
|
+
|
|
261
|
+
return { content, path: resolvedPath }
|
|
165
262
|
}
|
|
166
263
|
})
|
|
167
264
|
|