@shareai-lab/kode-sdk 2.7.2 → 2.7.3
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 +3 -0
- package/README.zh-CN.md +3 -0
- package/dist/core/agent.d.ts +7 -0
- package/dist/core/agent.js +100 -7
- package/dist/core/skills/management-manager.d.ts +93 -60
- package/dist/core/skills/management-manager.js +661 -391
- package/dist/core/skills/manager.d.ts +4 -0
- package/dist/core/skills/manager.js +39 -16
- package/dist/core/skills/types.d.ts +12 -0
- package/dist/core/types.d.ts +9 -1
- package/dist/infra/providers/anthropic.js +16 -0
- package/dist/infra/providers/gemini.js +32 -4
- package/dist/infra/providers/openai.js +27 -3
- package/dist/infra/providers/types.d.ts +35 -1
- package/dist/infra/providers/utils.d.ts +19 -1
- package/dist/infra/providers/utils.js +81 -1
- package/dist/infra/store/json-store.js +2 -1
- package/dist/tools/skills.js +2 -2
- package/dist/tools/type-inference.d.ts +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -142,9 +142,12 @@ See [docs/en/guides/architecture.md](./docs/en/guides/architecture.md) for detai
|
|
|
142
142
|
| **Guides** | |
|
|
143
143
|
| [Events](./docs/en/guides/events.md) | Three-channel event system |
|
|
144
144
|
| [Tools](./docs/en/guides/tools.md) | Built-in tools & custom tools |
|
|
145
|
+
| [Skills](./docs/en/guides/skills.md) | Skills system for reusable prompts |
|
|
145
146
|
| [Providers](./docs/en/guides/providers.md) | Model provider configuration |
|
|
146
147
|
| [Database](./docs/en/guides/database.md) | SQLite/PostgreSQL persistence |
|
|
147
148
|
| [Resume & Fork](./docs/en/guides/resume-fork.md) | Crash recovery & branching |
|
|
149
|
+
| **Project** | |
|
|
150
|
+
| [Contribution Guide](./docs/en/contribution.md) | How to contribute |
|
|
148
151
|
| **Reference** | |
|
|
149
152
|
| [API Reference](./docs/en/reference/api.md) | Complete API documentation |
|
|
150
153
|
| [Examples](./docs/en/examples/playbooks.md) | All examples explained |
|
package/README.zh-CN.md
CHANGED
|
@@ -102,9 +102,12 @@ npm run example:room # 多Agent协作
|
|
|
102
102
|
| **使用指南** | |
|
|
103
103
|
| [事件系统](./docs/zh-CN/guides/events.md) | 三通道事件系统 |
|
|
104
104
|
| [工具系统](./docs/zh-CN/guides/tools.md) | 内置工具与自定义工具 |
|
|
105
|
+
| [Skills 系统](./docs/zh-CN/guides/skills.md) | Skills 可复用提示词系统 |
|
|
105
106
|
| [Provider 配置](./docs/zh-CN/guides/providers.md) | 模型 Provider 配置 |
|
|
106
107
|
| [数据库存储](./docs/zh-CN/guides/database.md) | SQLite/PostgreSQL 持久化 |
|
|
107
108
|
| [恢复与分叉](./docs/zh-CN/guides/resume-fork.md) | 崩溃恢复与分支 |
|
|
109
|
+
| **项目** | |
|
|
110
|
+
| [贡献指南](./docs/zh-CN/contribution.md) | 提交 PR 的要求与流程 |
|
|
108
111
|
| **参考** | |
|
|
109
112
|
| [API 参考](./docs/zh-CN/reference/api.md) | 完整 API 文档 |
|
|
110
113
|
| [示例集](./docs/zh-CN/examples/playbooks.md) | 所有示例详解 |
|
package/dist/core/agent.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { SandboxFactory } from '../infra/sandbox-factory';
|
|
|
9
9
|
import { ModelProvider, ModelConfig } from '../infra/provider';
|
|
10
10
|
import { ToolRegistry, ToolInstance, ToolDescriptor } from '../tools/registry';
|
|
11
11
|
import { ContextManagerOptions } from './context-manager';
|
|
12
|
+
import { ResumeError } from './errors';
|
|
12
13
|
import { SendOptions as QueueSendOptions } from './agent/message-queue';
|
|
13
14
|
export interface ModelFactory {
|
|
14
15
|
(config: ModelConfig): ModelProvider;
|
|
@@ -180,6 +181,12 @@ export declare class Agent {
|
|
|
180
181
|
strategy?: ResumeStrategy;
|
|
181
182
|
overrides?: Partial<AgentConfig>;
|
|
182
183
|
}): Promise<Agent>;
|
|
184
|
+
static resumeOrCreate(agentId: string, config: AgentConfig, deps: AgentDependencies, opts?: {
|
|
185
|
+
autoRun?: boolean;
|
|
186
|
+
strategy?: ResumeStrategy;
|
|
187
|
+
overrides?: Partial<AgentConfig>;
|
|
188
|
+
onCorrupted?: (agentId: string, error: ResumeError) => Promise<void> | void;
|
|
189
|
+
}): Promise<Agent>;
|
|
183
190
|
private ensureProcessing;
|
|
184
191
|
private runStep;
|
|
185
192
|
private executeTools;
|
package/dist/core/agent.js
CHANGED
|
@@ -200,7 +200,7 @@ class Agent {
|
|
|
200
200
|
: template.sandbox;
|
|
201
201
|
const sandbox = typeof config.sandbox === 'object' && 'exec' in config.sandbox
|
|
202
202
|
? config.sandbox
|
|
203
|
-
: deps.sandboxFactory.
|
|
203
|
+
: await deps.sandboxFactory.createAsync(sandboxConfig || { kind: 'local', workDir: process.cwd() });
|
|
204
204
|
const model = config.model
|
|
205
205
|
? config.model
|
|
206
206
|
: config.modelConfig
|
|
@@ -541,7 +541,7 @@ class Agent {
|
|
|
541
541
|
}
|
|
542
542
|
let sandbox;
|
|
543
543
|
try {
|
|
544
|
-
sandbox = deps.sandboxFactory.
|
|
544
|
+
sandbox = await deps.sandboxFactory.createAsync(metadata.sandboxConfig || { kind: 'local', workDir: process.cwd() });
|
|
545
545
|
}
|
|
546
546
|
catch (error) {
|
|
547
547
|
throw new errors_1.ResumeError('SANDBOX_INIT_FAILED', error?.message || 'Failed to create sandbox');
|
|
@@ -653,6 +653,30 @@ class Agent {
|
|
|
653
653
|
const overrides = opts?.overrides ?? {};
|
|
654
654
|
return Agent.resume(agentId, { ...baseConfig, ...overrides }, deps, opts);
|
|
655
655
|
}
|
|
656
|
+
static async resumeOrCreate(agentId, config, deps, opts) {
|
|
657
|
+
try {
|
|
658
|
+
return await Agent.resumeFromStore(agentId, deps, opts);
|
|
659
|
+
}
|
|
660
|
+
catch (error) {
|
|
661
|
+
if (!(error instanceof errors_1.ResumeError)) {
|
|
662
|
+
throw error;
|
|
663
|
+
}
|
|
664
|
+
switch (error.code) {
|
|
665
|
+
case 'AGENT_NOT_FOUND':
|
|
666
|
+
return Agent.create({ ...config, agentId }, deps);
|
|
667
|
+
case 'CORRUPTED_DATA': {
|
|
668
|
+
if (opts?.onCorrupted) {
|
|
669
|
+
await opts.onCorrupted(agentId, error);
|
|
670
|
+
}
|
|
671
|
+
const store = Agent.requireStore(deps);
|
|
672
|
+
await store.delete(agentId);
|
|
673
|
+
return Agent.create({ ...config, agentId }, deps);
|
|
674
|
+
}
|
|
675
|
+
default:
|
|
676
|
+
throw error;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
656
680
|
ensureProcessing() {
|
|
657
681
|
// 检查是否超时
|
|
658
682
|
if (this.processingPromise) {
|
|
@@ -1231,7 +1255,7 @@ class Agent {
|
|
|
1231
1255
|
'application/pdf',
|
|
1232
1256
|
];
|
|
1233
1257
|
for (const block of blocks) {
|
|
1234
|
-
if (block.type === 'image' || block.type === 'audio' || block.type === 'file') {
|
|
1258
|
+
if (block.type === 'image' || block.type === 'audio' || block.type === 'video' || block.type === 'file') {
|
|
1235
1259
|
const url = block.url;
|
|
1236
1260
|
const fileId = block.file_id;
|
|
1237
1261
|
const base64 = block.base64;
|
|
@@ -1277,12 +1301,81 @@ class Agent {
|
|
|
1277
1301
|
}
|
|
1278
1302
|
async resolveMultimodalBlocks(blocks) {
|
|
1279
1303
|
const model = this.model;
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1304
|
+
const config = this.model.toConfig();
|
|
1305
|
+
const provider = config.provider;
|
|
1306
|
+
const multimodal = config.multimodal || {};
|
|
1307
|
+
// Check provider capabilities for audio/video
|
|
1308
|
+
const supportsAudio = provider === 'gemini' || provider === 'openai';
|
|
1309
|
+
const supportsVideo = provider === 'gemini';
|
|
1284
1310
|
const resolved = [];
|
|
1285
1311
|
for (const block of blocks) {
|
|
1312
|
+
// Handle audio block with callback fallback
|
|
1313
|
+
if (block.type === 'audio') {
|
|
1314
|
+
if (!supportsAudio && multimodal.audio?.customTranscriber) {
|
|
1315
|
+
try {
|
|
1316
|
+
const transcript = await multimodal.audio.customTranscriber({
|
|
1317
|
+
base64: block.base64,
|
|
1318
|
+
url: block.url,
|
|
1319
|
+
mimeType: block.mime_type,
|
|
1320
|
+
});
|
|
1321
|
+
resolved.push({ type: 'text', text: `[Audio Transcript]: ${transcript}` });
|
|
1322
|
+
continue;
|
|
1323
|
+
}
|
|
1324
|
+
catch (error) {
|
|
1325
|
+
this.events.emitMonitor({
|
|
1326
|
+
channel: 'monitor',
|
|
1327
|
+
type: 'error',
|
|
1328
|
+
severity: 'warn',
|
|
1329
|
+
phase: 'system',
|
|
1330
|
+
message: 'audio transcription failed, falling back to placeholder',
|
|
1331
|
+
detail: { error: error?.message || String(error) },
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
// If supported or no callback, pass through (provider will handle or degrade)
|
|
1336
|
+
resolved.push(block);
|
|
1337
|
+
continue;
|
|
1338
|
+
}
|
|
1339
|
+
// Handle video block with callback fallback
|
|
1340
|
+
if (block.type === 'video') {
|
|
1341
|
+
if (!supportsVideo && multimodal.video?.customFrameExtractor) {
|
|
1342
|
+
try {
|
|
1343
|
+
const frames = await multimodal.video.customFrameExtractor({
|
|
1344
|
+
base64: block.base64,
|
|
1345
|
+
url: block.url,
|
|
1346
|
+
mimeType: block.mime_type,
|
|
1347
|
+
});
|
|
1348
|
+
// Add all extracted frames as image blocks
|
|
1349
|
+
for (const frame of frames) {
|
|
1350
|
+
resolved.push({
|
|
1351
|
+
type: 'image',
|
|
1352
|
+
base64: frame.base64,
|
|
1353
|
+
mime_type: frame.mimeType,
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
resolved.push({ type: 'text', text: `[Video: ${frames.length} frames extracted]` });
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
catch (error) {
|
|
1360
|
+
this.events.emitMonitor({
|
|
1361
|
+
channel: 'monitor',
|
|
1362
|
+
type: 'error',
|
|
1363
|
+
severity: 'warn',
|
|
1364
|
+
phase: 'system',
|
|
1365
|
+
message: 'video frame extraction failed, falling back to placeholder',
|
|
1366
|
+
detail: { error: error?.message || String(error) },
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
// If supported or no callback, pass through (provider will handle or degrade)
|
|
1371
|
+
resolved.push(block);
|
|
1372
|
+
continue;
|
|
1373
|
+
}
|
|
1374
|
+
// Handle image and file uploads (existing logic)
|
|
1375
|
+
if (typeof model.uploadFile !== 'function') {
|
|
1376
|
+
resolved.push(block);
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1286
1379
|
if ((block.type === 'image' || block.type === 'file') &&
|
|
1287
1380
|
block.base64 &&
|
|
1288
1381
|
block.mime_type &&
|
|
@@ -1,120 +1,144 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 技能管理器模块(路径1 - 技能管理)
|
|
3
3
|
*
|
|
4
4
|
* 设计原则 (UNIX哲学):
|
|
5
|
-
* - 简洁:
|
|
6
|
-
* - 模块化:
|
|
7
|
-
* - 隔离: 与Agent
|
|
5
|
+
* - 简洁: 只负责技能文件系统的管理操作
|
|
6
|
+
* - 模块化: 单一职责,易于测试和维护
|
|
7
|
+
* - 隔离: 与Agent运行时完全隔离,不参与Agent使用
|
|
8
8
|
*
|
|
9
9
|
* ⚠️ 重要说明:
|
|
10
|
-
* - 此模块专门用于路径1
|
|
11
|
-
* - 与路径2
|
|
10
|
+
* - 此模块专门用于路径1(技能管理)
|
|
11
|
+
* - 与路径2(Agent运行时)完全独立
|
|
12
12
|
* - 请勿与SkillsManager混淆
|
|
13
|
+
*
|
|
14
|
+
* @see docs/skills-management-implementation-plan.md
|
|
13
15
|
*/
|
|
14
|
-
import {
|
|
15
|
-
import type { SkillInfo, SkillDetail, SkillFileTree, CreateSkillOptions, ArchivedSkillInfo } from './types';
|
|
16
|
-
import { SandboxFactory } from '../../infra/sandbox-factory';
|
|
16
|
+
import type { SkillInfo, ArchivedSkillInfo } from './types';
|
|
17
17
|
/**
|
|
18
18
|
* 技能管理器类
|
|
19
19
|
*
|
|
20
20
|
* 职责:
|
|
21
|
-
* -
|
|
22
|
-
* - 协调OperationQueue、SandboxFileManager进行文件系统操作
|
|
21
|
+
* - 提供所有技能管理操作的统一接口(导入、复制、重命名、归档、导出)
|
|
23
22
|
* - 处理业务逻辑和权限验证
|
|
23
|
+
* - 所有操作严格遵循Specification.md规范
|
|
24
24
|
* - ❌ 不参与Agent运行时
|
|
25
25
|
* - ❌ 不提供技能加载、扫描等Agent使用的功能
|
|
26
26
|
*/
|
|
27
27
|
export declare class SkillsManagementManager {
|
|
28
|
-
private skillsManager;
|
|
29
|
-
private operationQueue;
|
|
30
|
-
private sandboxFileManager;
|
|
31
28
|
private skillsDir;
|
|
32
29
|
private archivedDir;
|
|
33
|
-
constructor(skillsDir: string,
|
|
30
|
+
constructor(skillsDir: string, archivedDir?: string);
|
|
34
31
|
/**
|
|
35
|
-
*
|
|
32
|
+
* 1. 列出在线技能
|
|
33
|
+
* 扫描skills目录,排除.archived子目录
|
|
34
|
+
* 返回技能清单及其元数据信息
|
|
36
35
|
*/
|
|
37
36
|
listSkills(): Promise<SkillInfo[]>;
|
|
38
37
|
/**
|
|
39
|
-
*
|
|
40
|
-
* @param
|
|
38
|
+
* 2. 安装新技能
|
|
39
|
+
* @param source 技能来源(名称/GitHub仓库/Git URL/本地路径)
|
|
40
|
+
* @param onProgress 可选的进度回调函数,用于实时传递安装日志
|
|
41
|
+
* 执行命令: npx -y ai-agent-skills install --agent project [source]
|
|
42
|
+
* 直接安装到.skills目录
|
|
41
43
|
*/
|
|
42
|
-
|
|
44
|
+
installSkill(source: string, onProgress?: (data: {
|
|
45
|
+
type: 'log' | 'error';
|
|
46
|
+
message: string;
|
|
47
|
+
}) => void): Promise<void>;
|
|
43
48
|
/**
|
|
44
|
-
*
|
|
49
|
+
* 3. 列出归档技能
|
|
50
|
+
* 扫描.archived目录
|
|
51
|
+
* 返回归档技能清单及其元数据信息
|
|
45
52
|
*/
|
|
46
53
|
listArchivedSkills(): Promise<ArchivedSkillInfo[]>;
|
|
47
54
|
/**
|
|
48
|
-
*
|
|
55
|
+
* 4. 导入技能
|
|
56
|
+
* @param zipFilePath zip文件路径
|
|
57
|
+
* @param originalFileName 原始上传文件名(可选,用于无嵌套目录时的技能命名)
|
|
58
|
+
* 验证SKILL.md格式,解压并放置在在线技能目录中
|
|
59
|
+
*
|
|
60
|
+
* 检测逻辑:
|
|
61
|
+
* - 如果解压后根目录直接包含SKILL.md,视为无嵌套目录,使用originalFileName作为技能名称
|
|
62
|
+
* - 如果根目录不包含SKILL.md但包含多个子目录,每个子目录都有SKILL.md,则批量导入
|
|
63
|
+
*/
|
|
64
|
+
importSkill(zipFilePath: string, originalFileName?: string): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* 5. 复制技能
|
|
49
67
|
* @param skillName 技能名称
|
|
50
|
-
*
|
|
68
|
+
* 新技能名称: {原技能名称}-{XXXXXXXX}
|
|
51
69
|
*/
|
|
52
|
-
|
|
70
|
+
copySkill(skillName: string): Promise<string>;
|
|
53
71
|
/**
|
|
54
|
-
* 重命名技能
|
|
55
|
-
* @param oldName
|
|
56
|
-
* @param newName
|
|
72
|
+
* 6. 重命名技能
|
|
73
|
+
* @param oldName 旧技能文件夹名称
|
|
74
|
+
* @param newName 新技能文件夹名称
|
|
75
|
+
* 不支持操作归档技能
|
|
57
76
|
*/
|
|
58
77
|
renameSkill(oldName: string, newName: string): Promise<void>;
|
|
59
78
|
/**
|
|
60
|
-
*
|
|
79
|
+
* 7. 在线技能转归档
|
|
61
80
|
* @param skillName 技能名称
|
|
62
|
-
*
|
|
63
|
-
|
|
64
|
-
|
|
81
|
+
* 归档名称: {原技能名称}-{XXXXXXXX}
|
|
82
|
+
*/
|
|
83
|
+
archiveSkill(skillName: string): Promise<void>;
|
|
84
|
+
/**
|
|
85
|
+
* 8. 归档技能转在线
|
|
86
|
+
* @param archivedSkillName archived中的技能名称(含后缀)
|
|
87
|
+
* 移入前检测重名
|
|
65
88
|
*/
|
|
66
|
-
|
|
89
|
+
unarchiveSkill(archivedSkillName: string): Promise<void>;
|
|
67
90
|
/**
|
|
68
|
-
*
|
|
91
|
+
* 9. 查看在线技能内容
|
|
69
92
|
* @param skillName 技能名称
|
|
93
|
+
* 返回SKILL.md完整内容(包含frontmatter和正文)
|
|
70
94
|
*/
|
|
71
|
-
|
|
95
|
+
getOnlineSkillContent(skillName: string): Promise<string>;
|
|
72
96
|
/**
|
|
73
|
-
*
|
|
74
|
-
* @param archivedSkillName
|
|
97
|
+
* 10. 查看归档技能内容
|
|
98
|
+
* @param archivedSkillName 归档技能名称(含8位后缀)
|
|
99
|
+
* 返回SKILL.md完整内容(包含frontmatter和正文)
|
|
75
100
|
*/
|
|
76
|
-
|
|
101
|
+
getArchivedSkillContent(archivedSkillName: string): Promise<string>;
|
|
77
102
|
/**
|
|
78
|
-
*
|
|
103
|
+
* 11. 查看在线技能文件目录结构
|
|
79
104
|
* @param skillName 技能名称
|
|
105
|
+
* 返回JSON格式的目录树结构
|
|
80
106
|
*/
|
|
81
|
-
|
|
107
|
+
getOnlineSkillStructure(skillName: string): Promise<object>;
|
|
82
108
|
/**
|
|
83
|
-
*
|
|
109
|
+
* 12. 查看归档技能文件目录结构
|
|
110
|
+
* @param archivedSkillName 归档技能名称(含8位后缀)
|
|
111
|
+
* 返回JSON格式的目录树结构
|
|
84
112
|
*/
|
|
85
|
-
|
|
86
|
-
length: number;
|
|
87
|
-
processing: boolean;
|
|
88
|
-
tasks: OperationTask[];
|
|
89
|
-
};
|
|
113
|
+
getArchivedSkillStructure(archivedSkillName: string): Promise<object>;
|
|
90
114
|
/**
|
|
91
|
-
*
|
|
115
|
+
* 13. 导出技能
|
|
116
|
+
* @param skillName 技能名称(在线或归档)
|
|
117
|
+
* @param isArchived 是否为归档技能
|
|
118
|
+
* 使用系统zip命令打包,放入临时目录
|
|
92
119
|
*/
|
|
93
|
-
|
|
120
|
+
exportSkill(skillName: string, isArchived: boolean): Promise<string>;
|
|
94
121
|
/**
|
|
95
|
-
*
|
|
122
|
+
* 递归构建目录树
|
|
96
123
|
*/
|
|
97
|
-
private
|
|
124
|
+
private buildDirectoryTree;
|
|
98
125
|
/**
|
|
99
|
-
*
|
|
126
|
+
* 解析SKILL.md的YAML frontmatter
|
|
100
127
|
*/
|
|
101
|
-
private
|
|
128
|
+
private parseSkillMd;
|
|
102
129
|
/**
|
|
103
|
-
*
|
|
130
|
+
* 验证SKILL.md格式(遵循Specification.md规范)
|
|
104
131
|
*/
|
|
105
|
-
private
|
|
132
|
+
private validateSkillMd;
|
|
106
133
|
/**
|
|
107
|
-
*
|
|
134
|
+
* 生成8位随机后缀
|
|
135
|
+
* 规则: uuidv4 → sha256 → 全小写 → 取前8位
|
|
108
136
|
*/
|
|
109
|
-
private
|
|
137
|
+
private generateRandomSuffix;
|
|
110
138
|
/**
|
|
111
139
|
* 验证技能名称
|
|
112
140
|
*/
|
|
113
141
|
private isValidSkillName;
|
|
114
|
-
/**
|
|
115
|
-
* 生成SKILL.md内容
|
|
116
|
-
*/
|
|
117
|
-
private generateSkillMd;
|
|
118
142
|
/**
|
|
119
143
|
* 检查文件是否存在
|
|
120
144
|
*/
|
|
@@ -124,7 +148,16 @@ export declare class SkillsManagementManager {
|
|
|
124
148
|
*/
|
|
125
149
|
private safeGetFileStat;
|
|
126
150
|
/**
|
|
127
|
-
*
|
|
151
|
+
* 解压zip文件
|
|
152
|
+
*/
|
|
153
|
+
private extractZip;
|
|
154
|
+
/**
|
|
155
|
+
* 跨平台的安全重命名方法
|
|
156
|
+
* Windows上使用"复制-删除"方式避免EPERM错误
|
|
157
|
+
*/
|
|
158
|
+
private safeRename;
|
|
159
|
+
/**
|
|
160
|
+
* 创建zip文件
|
|
128
161
|
*/
|
|
129
|
-
private
|
|
162
|
+
private createZip;
|
|
130
163
|
}
|