@shareai-lab/kode-sdk 1.0.0-beta.9 → 2.7.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/LICENSE +21 -0
- package/README.md +115 -273
- package/README.zh-CN.md +114 -0
- package/dist/core/agent/breakpoint-manager.d.ts +16 -0
- package/dist/core/agent/breakpoint-manager.js +36 -0
- package/dist/core/agent/message-queue.d.ts +26 -0
- package/dist/core/agent/message-queue.js +57 -0
- package/dist/core/agent/permission-manager.d.ts +9 -0
- package/dist/core/agent/permission-manager.js +32 -0
- package/dist/core/agent/todo-manager.d.ts +26 -0
- package/dist/core/agent/todo-manager.js +91 -0
- package/dist/core/agent/tool-runner.d.ts +9 -0
- package/dist/core/agent/tool-runner.js +45 -0
- package/dist/core/agent.d.ts +228 -62
- package/dist/core/agent.js +1890 -615
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.js +2 -0
- package/dist/core/context-manager.d.ts +82 -0
- package/dist/core/context-manager.js +241 -0
- package/dist/core/errors.d.ts +22 -0
- package/dist/core/errors.js +49 -0
- package/dist/core/events.d.ts +41 -10
- package/dist/core/events.js +270 -68
- package/dist/core/file-pool.d.ts +41 -0
- package/dist/core/file-pool.js +102 -0
- package/dist/core/hooks.d.ts +3 -3
- package/dist/core/hooks.js +1 -1
- package/dist/core/permission-modes.d.ts +31 -0
- package/dist/core/permission-modes.js +61 -0
- package/dist/core/pool.d.ts +56 -13
- package/dist/core/pool.js +244 -34
- package/dist/core/room.d.ts +2 -2
- package/dist/core/room.js +10 -10
- package/dist/core/scheduler.d.ts +30 -23
- package/dist/core/scheduler.js +42 -168
- package/dist/core/skills/index.d.ts +10 -0
- package/dist/core/skills/index.js +20 -0
- package/dist/core/skills/management-manager.d.ts +130 -0
- package/dist/core/skills/management-manager.js +557 -0
- package/dist/core/skills/manager.d.ts +47 -0
- package/dist/core/skills/manager.js +243 -0
- package/dist/core/skills/operation-queue.d.ts +87 -0
- package/dist/core/skills/operation-queue.js +113 -0
- package/dist/core/skills/sandbox-file-manager.d.ts +82 -0
- package/dist/core/skills/sandbox-file-manager.js +183 -0
- package/dist/core/skills/types.d.ts +120 -0
- package/dist/core/skills/types.js +9 -0
- package/dist/core/skills/xml-generator.d.ts +13 -0
- package/dist/core/skills/xml-generator.js +70 -0
- package/dist/core/template.d.ts +57 -0
- package/dist/core/template.js +35 -0
- package/dist/core/time-bridge.d.ts +18 -0
- package/dist/core/time-bridge.js +100 -0
- package/dist/core/todo.d.ts +34 -0
- package/dist/core/todo.js +89 -0
- package/dist/core/types.d.ts +311 -114
- package/dist/core/types.js +1 -12
- package/dist/index.d.ts +47 -9
- package/dist/index.js +108 -15
- package/dist/infra/db/postgres/postgres-store.d.ts +97 -0
- package/dist/infra/db/postgres/postgres-store.js +1073 -0
- package/dist/infra/db/sqlite/sqlite-store.d.ts +84 -0
- package/dist/infra/db/sqlite/sqlite-store.js +800 -0
- package/dist/infra/e2b/e2b-fs.d.ts +29 -0
- package/dist/infra/e2b/e2b-fs.js +128 -0
- package/dist/infra/e2b/e2b-sandbox.d.ts +37 -0
- package/dist/infra/e2b/e2b-sandbox.js +156 -0
- package/dist/infra/e2b/e2b-template.d.ts +24 -0
- package/dist/infra/e2b/e2b-template.js +105 -0
- package/dist/infra/e2b/index.d.ts +4 -0
- package/dist/infra/e2b/index.js +9 -0
- package/dist/infra/e2b/types.d.ts +46 -0
- package/dist/infra/e2b/types.js +2 -0
- package/dist/infra/provider.d.ts +17 -58
- package/dist/infra/provider.js +65 -116
- package/dist/infra/providers/anthropic.d.ts +42 -0
- package/dist/infra/providers/anthropic.js +308 -0
- package/dist/infra/providers/core/errors.d.ts +230 -0
- package/dist/infra/providers/core/errors.js +353 -0
- package/dist/infra/providers/core/fork.d.ts +106 -0
- package/dist/infra/providers/core/fork.js +418 -0
- package/dist/infra/providers/core/index.d.ts +10 -0
- package/dist/infra/providers/core/index.js +76 -0
- package/dist/infra/providers/core/logger.d.ts +186 -0
- package/dist/infra/providers/core/logger.js +191 -0
- package/dist/infra/providers/core/retry.d.ts +62 -0
- package/dist/infra/providers/core/retry.js +189 -0
- package/dist/infra/providers/core/usage.d.ts +151 -0
- package/dist/infra/providers/core/usage.js +376 -0
- package/dist/infra/providers/gemini.d.ts +49 -0
- package/dist/infra/providers/gemini.js +493 -0
- package/dist/infra/providers/index.d.ts +25 -0
- package/dist/infra/providers/index.js +83 -0
- package/dist/infra/providers/openai.d.ts +123 -0
- package/dist/infra/providers/openai.js +662 -0
- package/dist/infra/providers/types.d.ts +334 -0
- package/dist/infra/providers/types.js +20 -0
- package/dist/infra/providers/utils.d.ts +53 -0
- package/dist/infra/providers/utils.js +400 -0
- package/dist/infra/sandbox-factory.d.ts +13 -0
- package/dist/infra/sandbox-factory.js +30 -0
- package/dist/infra/sandbox.d.ts +35 -6
- package/dist/infra/sandbox.js +174 -8
- package/dist/infra/store/factory.d.ts +45 -0
- package/dist/infra/store/factory.js +80 -0
- package/dist/infra/store/index.d.ts +3 -0
- package/dist/infra/store/index.js +26 -0
- package/dist/infra/store/json-store.d.ts +67 -0
- package/dist/infra/store/json-store.js +606 -0
- package/dist/infra/store/types.d.ts +342 -0
- package/dist/infra/store/types.js +2 -0
- package/dist/infra/store.d.ts +12 -32
- package/dist/infra/store.js +27 -130
- package/dist/tools/bash_kill/index.d.ts +1 -0
- package/dist/tools/bash_kill/index.js +35 -0
- package/dist/tools/bash_kill/prompt.d.ts +2 -0
- package/dist/tools/bash_kill/prompt.js +14 -0
- package/dist/tools/bash_logs/index.d.ts +1 -0
- package/dist/tools/bash_logs/index.js +40 -0
- package/dist/tools/bash_logs/prompt.d.ts +2 -0
- package/dist/tools/bash_logs/prompt.js +14 -0
- package/dist/tools/bash_run/index.d.ts +16 -0
- package/dist/tools/bash_run/index.js +61 -0
- package/dist/tools/bash_run/prompt.d.ts +2 -0
- package/dist/tools/bash_run/prompt.js +18 -0
- package/dist/tools/builtin.d.ts +7 -13
- package/dist/tools/builtin.js +19 -90
- package/dist/tools/define.d.ts +101 -0
- package/dist/tools/define.js +214 -0
- package/dist/tools/fs_edit/index.d.ts +1 -0
- package/dist/tools/fs_edit/index.js +62 -0
- package/dist/tools/fs_edit/prompt.d.ts +2 -0
- package/dist/tools/fs_edit/prompt.js +15 -0
- package/dist/tools/fs_glob/index.d.ts +1 -0
- package/dist/tools/fs_glob/index.js +40 -0
- package/dist/tools/fs_glob/prompt.d.ts +2 -0
- package/dist/tools/fs_glob/prompt.js +15 -0
- package/dist/tools/fs_grep/index.d.ts +1 -0
- package/dist/tools/fs_grep/index.js +66 -0
- package/dist/tools/fs_grep/prompt.d.ts +2 -0
- package/dist/tools/fs_grep/prompt.js +16 -0
- package/dist/tools/fs_multi_edit/index.d.ts +1 -0
- package/dist/tools/fs_multi_edit/index.js +106 -0
- package/dist/tools/fs_multi_edit/prompt.d.ts +2 -0
- package/dist/tools/fs_multi_edit/prompt.js +16 -0
- package/dist/tools/fs_read/index.d.ts +1 -0
- package/dist/tools/fs_read/index.js +40 -0
- package/dist/tools/fs_read/prompt.d.ts +2 -0
- package/dist/tools/fs_read/prompt.js +16 -0
- package/dist/tools/fs_write/index.d.ts +1 -0
- package/dist/tools/fs_write/index.js +40 -0
- package/dist/tools/fs_write/prompt.d.ts +2 -0
- package/dist/tools/fs_write/prompt.js +15 -0
- package/dist/tools/index.d.ts +11 -0
- package/dist/tools/index.js +61 -0
- package/dist/tools/mcp.d.ts +69 -0
- package/dist/tools/mcp.js +185 -0
- package/dist/tools/registry.d.ts +29 -0
- package/dist/tools/registry.js +26 -0
- package/dist/tools/scripts.d.ts +22 -0
- package/dist/tools/scripts.js +205 -0
- package/dist/tools/skills.d.ts +20 -0
- package/dist/tools/skills.js +115 -0
- package/dist/tools/task_run/index.d.ts +7 -0
- package/dist/tools/task_run/index.js +58 -0
- package/dist/tools/task_run/prompt.d.ts +5 -0
- package/dist/tools/task_run/prompt.js +25 -0
- package/dist/tools/todo_read/index.d.ts +1 -0
- package/dist/tools/todo_read/index.js +29 -0
- package/dist/tools/todo_read/prompt.d.ts +2 -0
- package/dist/tools/todo_read/prompt.js +18 -0
- package/dist/tools/todo_write/index.d.ts +1 -0
- package/dist/tools/todo_write/index.js +42 -0
- package/dist/tools/todo_write/prompt.d.ts +2 -0
- package/dist/tools/todo_write/prompt.js +23 -0
- package/dist/tools/tool.d.ts +43 -0
- package/dist/tools/tool.js +211 -0
- package/dist/tools/toolkit.d.ts +69 -0
- package/dist/tools/toolkit.js +98 -0
- package/dist/tools/type-inference.d.ts +127 -0
- package/dist/tools/type-inference.js +207 -0
- package/dist/utils/agent-id.d.ts +1 -0
- package/dist/utils/agent-id.js +28 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.js +44 -0
- package/dist/utils/session-id.js +16 -16
- package/package.json +35 -11
- package/dist/tools/bash.d.ts +0 -63
- package/dist/tools/bash.js +0 -92
- package/dist/tools/fs.d.ts +0 -96
- package/dist/tools/fs.js +0 -100
- package/dist/tools/task.d.ts +0 -38
- package/dist/tools/task.js +0 -45
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.processes = exports.BashRun = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const type_inference_1 = require("../type-inference");
|
|
7
|
+
const prompt_1 = require("./prompt");
|
|
8
|
+
const processes = new Map();
|
|
9
|
+
exports.processes = processes;
|
|
10
|
+
exports.BashRun = (0, tool_1.tool)({
|
|
11
|
+
name: 'bash_run',
|
|
12
|
+
description: prompt_1.DESCRIPTION,
|
|
13
|
+
parameters: zod_1.z.object({
|
|
14
|
+
cmd: zod_1.z.string().describe('Command to execute'),
|
|
15
|
+
timeout_ms: type_inference_1.patterns.optionalNumber('Timeout in milliseconds (default: 120000)'),
|
|
16
|
+
background: zod_1.z.boolean().optional().describe('Run in background and return shell_id'),
|
|
17
|
+
}),
|
|
18
|
+
async execute(args, ctx) {
|
|
19
|
+
const { cmd, timeout_ms = 120000, background = false } = args;
|
|
20
|
+
if (background) {
|
|
21
|
+
const id = `shell-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
22
|
+
const promise = ctx.sandbox.exec(cmd, { timeoutMs: timeout_ms });
|
|
23
|
+
const proc = {
|
|
24
|
+
id,
|
|
25
|
+
cmd,
|
|
26
|
+
startTime: Date.now(),
|
|
27
|
+
promise,
|
|
28
|
+
stdout: '',
|
|
29
|
+
stderr: '',
|
|
30
|
+
};
|
|
31
|
+
processes.set(id, proc);
|
|
32
|
+
promise.then((result) => {
|
|
33
|
+
proc.code = result.code;
|
|
34
|
+
proc.stdout = result.stdout;
|
|
35
|
+
proc.stderr = result.stderr;
|
|
36
|
+
}).catch((error) => {
|
|
37
|
+
proc.code = -1;
|
|
38
|
+
proc.stderr = error?.message || String(error);
|
|
39
|
+
});
|
|
40
|
+
return {
|
|
41
|
+
background: true,
|
|
42
|
+
shell_id: id,
|
|
43
|
+
message: `Background shell started: ${id}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const result = await ctx.sandbox.exec(cmd, { timeoutMs: timeout_ms });
|
|
48
|
+
const output = [result.stdout, result.stderr].filter(Boolean).join('\n').trim();
|
|
49
|
+
return {
|
|
50
|
+
background: false,
|
|
51
|
+
code: result.code,
|
|
52
|
+
output: output || '(no output)',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
metadata: {
|
|
57
|
+
readonly: false,
|
|
58
|
+
version: '1.0',
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
exports.BashRun.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DESCRIPTION = "Execute a bash command";
|
|
2
|
+
export declare const PROMPT = "Execute shell commands inside the sandbox environment.\n\nGuidelines:\n- Commands run with the sandbox's working directory and limited privileges.\n- Capture output responsibly; large outputs are truncated and saved to temp files.\n- Respect project policies: use fs_read for inspections where possible.\n- Request approval when running high-impact commands if required by policy.\n- Set \"background\" to true to run long-running processes and poll with bash_logs.\n\nSafety/Limitations:\n- Commands are sandboxed and cannot escape the workspace.\n- Dangerous commands may be blocked for security.\n- Timeout defaults to 120 seconds but can be configured.\n- Background processes must be explicitly killed with bash_kill.";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Execute a bash command';
|
|
5
|
+
exports.PROMPT = `Execute shell commands inside the sandbox environment.
|
|
6
|
+
|
|
7
|
+
Guidelines:
|
|
8
|
+
- Commands run with the sandbox's working directory and limited privileges.
|
|
9
|
+
- Capture output responsibly; large outputs are truncated and saved to temp files.
|
|
10
|
+
- Respect project policies: use fs_read for inspections where possible.
|
|
11
|
+
- Request approval when running high-impact commands if required by policy.
|
|
12
|
+
- Set "background" to true to run long-running processes and poll with bash_logs.
|
|
13
|
+
|
|
14
|
+
Safety/Limitations:
|
|
15
|
+
- Commands are sandboxed and cannot escape the workspace.
|
|
16
|
+
- Dangerous commands may be blocked for security.
|
|
17
|
+
- Timeout defaults to 120 seconds but can be configured.
|
|
18
|
+
- Background processes must be explicitly killed with bash_kill.`;
|
package/dist/tools/builtin.d.ts
CHANGED
|
@@ -1,15 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { AgentTemplate } from './
|
|
1
|
+
import { ToolInstance } from './registry';
|
|
2
|
+
import { AgentTemplate } from './task_run';
|
|
3
3
|
export declare const builtin: {
|
|
4
|
-
fs(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
allow?: RegExp[];
|
|
9
|
-
block?: RegExp[];
|
|
10
|
-
approval?: boolean;
|
|
11
|
-
}): Tool[];
|
|
12
|
-
task(opts?: {
|
|
13
|
-
subAgents?: AgentTemplate[];
|
|
14
|
-
}): Tool;
|
|
4
|
+
fs: () => ToolInstance[];
|
|
5
|
+
bash: () => ToolInstance[];
|
|
6
|
+
todo: () => ToolInstance[];
|
|
7
|
+
task: (templates?: AgentTemplate[]) => ToolInstance | null;
|
|
15
8
|
};
|
|
9
|
+
export { AgentTemplate };
|
package/dist/tools/builtin.js
CHANGED
|
@@ -1,97 +1,26 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.builtin = void 0;
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
4
|
+
const fs_read_1 = require("./fs_read");
|
|
5
|
+
const fs_write_1 = require("./fs_write");
|
|
6
|
+
const fs_edit_1 = require("./fs_edit");
|
|
7
|
+
const fs_glob_1 = require("./fs_glob");
|
|
8
|
+
const fs_grep_1 = require("./fs_grep");
|
|
9
|
+
const fs_multi_edit_1 = require("./fs_multi_edit");
|
|
10
|
+
const bash_run_1 = require("./bash_run");
|
|
11
|
+
const bash_logs_1 = require("./bash_logs");
|
|
12
|
+
const bash_kill_1 = require("./bash_kill");
|
|
13
|
+
const todo_read_1 = require("./todo_read");
|
|
14
|
+
const todo_write_1 = require("./todo_write");
|
|
15
|
+
const task_run_1 = require("./task_run");
|
|
7
16
|
exports.builtin = {
|
|
8
|
-
fs(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (call.args && typeof call.args === 'object' && 'path' in call.args) {
|
|
15
|
-
call.args.path = ctx.sandbox.fs.resolve(call.args.path);
|
|
16
|
-
if (!ctx.sandbox.fs.isInside(call.args.path)) {
|
|
17
|
-
return { decision: 'deny', reason: `Path outside sandbox: ${call.args.path}` };
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
postToolUse(outcome, ctx) {
|
|
22
|
-
const content = String(outcome.content || '');
|
|
23
|
-
if (content.length > 100000) {
|
|
24
|
-
const tempPath = ctx.sandbox.fs.temp(`tool-${outcome.id}.log`);
|
|
25
|
-
ctx.sandbox.fs.write(tempPath, content);
|
|
26
|
-
return {
|
|
27
|
-
update: {
|
|
28
|
-
content: content.slice(0, 100000) + `\n\n[Full output at ./${tempPath}]`,
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
return tool;
|
|
36
|
-
});
|
|
37
|
-
},
|
|
38
|
-
bash(opts) {
|
|
39
|
-
const tools = [new bash_1.BashRun(), new bash_1.BashLogs(), new bash_1.BashKill()];
|
|
40
|
-
if (opts?.allow || opts?.block || opts?.approval) {
|
|
41
|
-
return tools.map((tool) => {
|
|
42
|
-
if (tool.name === 'bash_run') {
|
|
43
|
-
return (0, fs_1.toolTune)(tool, {
|
|
44
|
-
preToolUse(call, ctx) {
|
|
45
|
-
const cmd = call.args.cmd;
|
|
46
|
-
if (opts.block) {
|
|
47
|
-
for (const pattern of opts.block) {
|
|
48
|
-
if (pattern.test(cmd)) {
|
|
49
|
-
return { decision: 'deny', reason: `Blocked command pattern: ${pattern}` };
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (opts.allow) {
|
|
54
|
-
let allowed = false;
|
|
55
|
-
for (const pattern of opts.allow) {
|
|
56
|
-
if (pattern.test(cmd)) {
|
|
57
|
-
allowed = true;
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (!allowed) {
|
|
62
|
-
return { decision: 'deny', reason: 'Command not in allow list' };
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
if (opts.approval) {
|
|
66
|
-
return { decision: 'ask', meta: { title: 'Bash Command Approval', cmd } };
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
postToolUse(outcome, ctx) {
|
|
70
|
-
const stdout = String(outcome.content?.stdout || '');
|
|
71
|
-
const stderr = String(outcome.content?.stderr || '');
|
|
72
|
-
const combined = stdout + stderr;
|
|
73
|
-
if (combined.length > 100000) {
|
|
74
|
-
const tempPath = ctx.sandbox.fs.temp(`bash-${outcome.id}.log`);
|
|
75
|
-
ctx.sandbox.fs.write(tempPath, combined);
|
|
76
|
-
return {
|
|
77
|
-
update: {
|
|
78
|
-
content: {
|
|
79
|
-
...outcome.content,
|
|
80
|
-
stdout: stdout.slice(0, 50000) + `\n\n[Full stdout at ./${tempPath}]`,
|
|
81
|
-
stderr: stderr.slice(0, 50000),
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
return tool;
|
|
90
|
-
});
|
|
17
|
+
fs: () => [fs_read_1.FsRead, fs_write_1.FsWrite, fs_edit_1.FsEdit, fs_glob_1.FsGlob, fs_grep_1.FsGrep, fs_multi_edit_1.FsMultiEdit],
|
|
18
|
+
bash: () => [bash_run_1.BashRun, bash_logs_1.BashLogs, bash_kill_1.BashKill],
|
|
19
|
+
todo: () => [todo_read_1.TodoRead, todo_write_1.TodoWrite],
|
|
20
|
+
task: (templates) => {
|
|
21
|
+
if (!templates || templates.length === 0) {
|
|
22
|
+
return null;
|
|
91
23
|
}
|
|
92
|
-
return
|
|
93
|
-
},
|
|
94
|
-
task(opts) {
|
|
95
|
-
return new task_1.TaskRun(opts?.subAgents || []);
|
|
24
|
+
return (0, task_run_1.createTaskRunTool)(templates);
|
|
96
25
|
},
|
|
97
26
|
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 简化的工具定义 API - 提供更好的开发体验
|
|
3
|
+
*
|
|
4
|
+
* 设计目标:
|
|
5
|
+
* 1. 自动从 TypeScript 类型生成 input_schema
|
|
6
|
+
* 2. 简化 metadata 为 readonly/noEffect 布尔值
|
|
7
|
+
* 3. 支持工具内发射自定义事件
|
|
8
|
+
*/
|
|
9
|
+
import { ToolContext } from '../core/types';
|
|
10
|
+
import { ToolInstance } from './registry';
|
|
11
|
+
export interface ToolAttributes {
|
|
12
|
+
/** 工具是否为只读(不修改任何状态) */
|
|
13
|
+
readonly?: boolean;
|
|
14
|
+
/** 工具是否无副作用(可安全重试) */
|
|
15
|
+
noEffect?: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface ParamDef {
|
|
18
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
19
|
+
description?: string;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
default?: any;
|
|
22
|
+
enum?: any[];
|
|
23
|
+
items?: ParamDef;
|
|
24
|
+
properties?: Record<string, ParamDef>;
|
|
25
|
+
}
|
|
26
|
+
export interface EnhancedToolContext extends ToolContext {
|
|
27
|
+
/** 发射自定义事件(会自动添加到 monitor 通道) */
|
|
28
|
+
emit(eventType: string, data?: any): void;
|
|
29
|
+
}
|
|
30
|
+
export interface SimpleToolDef<TArgs = any, TResult = any> {
|
|
31
|
+
/** 工具名称 */
|
|
32
|
+
name: string;
|
|
33
|
+
/** 工具描述 */
|
|
34
|
+
description: string;
|
|
35
|
+
/** 参数定义(可选,如果提供则自动生成 schema) */
|
|
36
|
+
params?: Record<string, ParamDef>;
|
|
37
|
+
/** 或者直接提供 JSON Schema(兼容老方式) */
|
|
38
|
+
input_schema?: any;
|
|
39
|
+
/** 工具属性 */
|
|
40
|
+
attributes?: ToolAttributes;
|
|
41
|
+
/** Prompt 说明书 */
|
|
42
|
+
prompt?: string;
|
|
43
|
+
/** 执行函数 */
|
|
44
|
+
exec(args: TArgs, ctx: EnhancedToolContext): Promise<TResult> | TResult;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 定义工具(简化版)
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const greet = defineTool({
|
|
52
|
+
* name: 'greet',
|
|
53
|
+
* description: 'Greet a person',
|
|
54
|
+
* params: {
|
|
55
|
+
* name: { type: 'string', description: 'Person name' },
|
|
56
|
+
* formal: { type: 'boolean', description: 'Use formal greeting', required: false }
|
|
57
|
+
* },
|
|
58
|
+
* attributes: { readonly: true, noEffect: true },
|
|
59
|
+
* async exec(args, ctx) {
|
|
60
|
+
* const greeting = args.formal ? `Good day, ${args.name}` : `Hi ${args.name}!`;
|
|
61
|
+
*
|
|
62
|
+
* // 自定义事件
|
|
63
|
+
* ctx.emit('greeting_sent', { name: args.name, greeting });
|
|
64
|
+
*
|
|
65
|
+
* return { greeting };
|
|
66
|
+
* }
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export declare function defineTool<TArgs = any, TResult = any>(def: SimpleToolDef<TArgs, TResult>, options?: {
|
|
71
|
+
autoRegister?: boolean;
|
|
72
|
+
}): ToolInstance;
|
|
73
|
+
/**
|
|
74
|
+
* 批量定义工具
|
|
75
|
+
*/
|
|
76
|
+
export declare function defineTools(defs: SimpleToolDef[]): ToolInstance[];
|
|
77
|
+
/**
|
|
78
|
+
* 工具装饰器(实验性 - 需要 experimentalDecorators)
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* class MyTools {
|
|
83
|
+
* @tool({
|
|
84
|
+
* description: 'Calculate sum',
|
|
85
|
+
* params: {
|
|
86
|
+
* a: { type: 'number' },
|
|
87
|
+
* b: { type: 'number' }
|
|
88
|
+
* },
|
|
89
|
+
* attributes: { readonly: true, noEffect: true }
|
|
90
|
+
* })
|
|
91
|
+
* async sum(args: { a: number; b: number }, ctx: EnhancedToolContext) {
|
|
92
|
+
* return args.a + args.b;
|
|
93
|
+
* }
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare function tool(config: Omit<SimpleToolDef, 'name' | 'exec'>): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
|
|
98
|
+
/**
|
|
99
|
+
* 从带装饰器的类提取所有工具
|
|
100
|
+
*/
|
|
101
|
+
export declare function extractTools(instance: any): ToolInstance[];
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 简化的工具定义 API - 提供更好的开发体验
|
|
4
|
+
*
|
|
5
|
+
* 设计目标:
|
|
6
|
+
* 1. 自动从 TypeScript 类型生成 input_schema
|
|
7
|
+
* 2. 简化 metadata 为 readonly/noEffect 布尔值
|
|
8
|
+
* 3. 支持工具内发射自定义事件
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.defineTool = defineTool;
|
|
12
|
+
exports.defineTools = defineTools;
|
|
13
|
+
exports.tool = tool;
|
|
14
|
+
exports.extractTools = extractTools;
|
|
15
|
+
const registry_1 = require("./registry");
|
|
16
|
+
/**
|
|
17
|
+
* 从参数定义自动生成 JSON Schema
|
|
18
|
+
*/
|
|
19
|
+
function generateSchema(params) {
|
|
20
|
+
if (!params) {
|
|
21
|
+
return { type: 'object', properties: {} };
|
|
22
|
+
}
|
|
23
|
+
const properties = {};
|
|
24
|
+
const required = [];
|
|
25
|
+
for (const [key, def] of Object.entries(params)) {
|
|
26
|
+
const prop = { type: def.type };
|
|
27
|
+
if (def.description)
|
|
28
|
+
prop.description = def.description;
|
|
29
|
+
if (def.enum)
|
|
30
|
+
prop.enum = def.enum;
|
|
31
|
+
if (def.default !== undefined)
|
|
32
|
+
prop.default = def.default;
|
|
33
|
+
if (def.type === 'array' && def.items) {
|
|
34
|
+
prop.items = generateSchemaProp(def.items);
|
|
35
|
+
}
|
|
36
|
+
if (def.type === 'object' && def.properties) {
|
|
37
|
+
const nested = generateSchema(def.properties);
|
|
38
|
+
prop.properties = nested.properties;
|
|
39
|
+
if (nested.required?.length > 0) {
|
|
40
|
+
prop.required = nested.required;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
properties[key] = prop;
|
|
44
|
+
if (def.required !== false) { // default required
|
|
45
|
+
required.push(key);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties,
|
|
51
|
+
...(required.length > 0 ? { required } : {}),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function generateSchemaProp(def) {
|
|
55
|
+
const prop = { type: def.type };
|
|
56
|
+
if (def.description)
|
|
57
|
+
prop.description = def.description;
|
|
58
|
+
if (def.enum)
|
|
59
|
+
prop.enum = def.enum;
|
|
60
|
+
if (def.type === 'array' && def.items) {
|
|
61
|
+
prop.items = generateSchemaProp(def.items);
|
|
62
|
+
}
|
|
63
|
+
if (def.type === 'object' && def.properties) {
|
|
64
|
+
const nested = generateSchema(def.properties);
|
|
65
|
+
prop.properties = nested.properties;
|
|
66
|
+
if (nested.required?.length > 0) {
|
|
67
|
+
prop.required = nested.required;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return prop;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* 定义工具(简化版)
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* const greet = defineTool({
|
|
78
|
+
* name: 'greet',
|
|
79
|
+
* description: 'Greet a person',
|
|
80
|
+
* params: {
|
|
81
|
+
* name: { type: 'string', description: 'Person name' },
|
|
82
|
+
* formal: { type: 'boolean', description: 'Use formal greeting', required: false }
|
|
83
|
+
* },
|
|
84
|
+
* attributes: { readonly: true, noEffect: true },
|
|
85
|
+
* async exec(args, ctx) {
|
|
86
|
+
* const greeting = args.formal ? `Good day, ${args.name}` : `Hi ${args.name}!`;
|
|
87
|
+
*
|
|
88
|
+
* // 自定义事件
|
|
89
|
+
* ctx.emit('greeting_sent', { name: args.name, greeting });
|
|
90
|
+
*
|
|
91
|
+
* return { greeting };
|
|
92
|
+
* }
|
|
93
|
+
* });
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
function defineTool(def, options) {
|
|
97
|
+
// 自动生成 schema 或使用提供的
|
|
98
|
+
const input_schema = def.input_schema || generateSchema(def.params);
|
|
99
|
+
const toolInstance = {
|
|
100
|
+
name: def.name,
|
|
101
|
+
description: def.description,
|
|
102
|
+
input_schema,
|
|
103
|
+
prompt: def.prompt,
|
|
104
|
+
async exec(args, ctx) {
|
|
105
|
+
// 增强上下文,添加 emit 方法
|
|
106
|
+
const enhancedCtx = {
|
|
107
|
+
...ctx,
|
|
108
|
+
emit(eventType, data) {
|
|
109
|
+
// 发射自定义事件到 monitor 通道
|
|
110
|
+
ctx.agent?.events?.emitMonitor({
|
|
111
|
+
type: 'tool_custom_event',
|
|
112
|
+
toolName: def.name,
|
|
113
|
+
eventType,
|
|
114
|
+
data,
|
|
115
|
+
timestamp: Date.now(),
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
return await def.exec(args, enhancedCtx);
|
|
120
|
+
},
|
|
121
|
+
toDescriptor() {
|
|
122
|
+
const metadata = {
|
|
123
|
+
tuned: false,
|
|
124
|
+
};
|
|
125
|
+
// 转换简化的 attributes 为内部 metadata
|
|
126
|
+
if (def.attributes?.readonly) {
|
|
127
|
+
metadata.access = 'read';
|
|
128
|
+
metadata.mutates = false;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
metadata.access = 'write';
|
|
132
|
+
metadata.mutates = true;
|
|
133
|
+
}
|
|
134
|
+
if (def.attributes?.noEffect !== undefined) {
|
|
135
|
+
metadata.safe = def.attributes.noEffect;
|
|
136
|
+
}
|
|
137
|
+
if (def.prompt) {
|
|
138
|
+
metadata.prompt = def.prompt;
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
source: 'registered',
|
|
142
|
+
name: def.name,
|
|
143
|
+
registryId: def.name,
|
|
144
|
+
metadata,
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
};
|
|
148
|
+
// 自动注册到全局 registry (支持 Resume)
|
|
149
|
+
if (options?.autoRegister !== false) {
|
|
150
|
+
registry_1.globalToolRegistry.register(def.name, (_config) => {
|
|
151
|
+
// 工厂函数:根据 config 重建工具实例
|
|
152
|
+
// 注意:使用 autoRegister: false 避免重复注册
|
|
153
|
+
return defineTool(def, { autoRegister: false });
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return toolInstance;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* 批量定义工具
|
|
160
|
+
*/
|
|
161
|
+
function defineTools(defs) {
|
|
162
|
+
return defs.map((def) => defineTool(def));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 工具装饰器(实验性 - 需要 experimentalDecorators)
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```ts
|
|
169
|
+
* class MyTools {
|
|
170
|
+
* @tool({
|
|
171
|
+
* description: 'Calculate sum',
|
|
172
|
+
* params: {
|
|
173
|
+
* a: { type: 'number' },
|
|
174
|
+
* b: { type: 'number' }
|
|
175
|
+
* },
|
|
176
|
+
* attributes: { readonly: true, noEffect: true }
|
|
177
|
+
* })
|
|
178
|
+
* async sum(args: { a: number; b: number }, ctx: EnhancedToolContext) {
|
|
179
|
+
* return args.a + args.b;
|
|
180
|
+
* }
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
function tool(config) {
|
|
185
|
+
return function (target, propertyKey, descriptor) {
|
|
186
|
+
const originalMethod = descriptor.value;
|
|
187
|
+
// 存储工具配置到类的元数据
|
|
188
|
+
if (!target.constructor._toolConfigs) {
|
|
189
|
+
target.constructor._toolConfigs = new Map();
|
|
190
|
+
}
|
|
191
|
+
target.constructor._toolConfigs.set(propertyKey, {
|
|
192
|
+
...config,
|
|
193
|
+
name: propertyKey,
|
|
194
|
+
exec: originalMethod,
|
|
195
|
+
});
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* 从带装饰器的类提取所有工具
|
|
200
|
+
*/
|
|
201
|
+
function extractTools(instance) {
|
|
202
|
+
const configs = instance.constructor._toolConfigs;
|
|
203
|
+
if (!configs)
|
|
204
|
+
return [];
|
|
205
|
+
const tools = [];
|
|
206
|
+
for (const [_methodName, config] of configs) {
|
|
207
|
+
tools.push(defineTool({
|
|
208
|
+
...config,
|
|
209
|
+
exec: config.exec.bind(instance),
|
|
210
|
+
}, { autoRegister: true } // 装饰器定义的工具也自动注册
|
|
211
|
+
));
|
|
212
|
+
}
|
|
213
|
+
return tools;
|
|
214
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FsEdit: import("..").ToolInstance;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FsEdit = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const type_inference_1 = require("../type-inference");
|
|
7
|
+
const prompt_1 = require("./prompt");
|
|
8
|
+
exports.FsEdit = (0, tool_1.tool)({
|
|
9
|
+
name: 'fs_edit',
|
|
10
|
+
description: prompt_1.DESCRIPTION,
|
|
11
|
+
parameters: zod_1.z.object({
|
|
12
|
+
path: type_inference_1.patterns.filePath('Path to file within the sandbox'),
|
|
13
|
+
old_string: zod_1.z.string().describe('String to replace'),
|
|
14
|
+
new_string: zod_1.z.string().describe('Replacement string'),
|
|
15
|
+
replace_all: zod_1.z.boolean().optional().describe('Replace all occurrences (default: false)'),
|
|
16
|
+
}),
|
|
17
|
+
async execute(args, ctx) {
|
|
18
|
+
const { path, old_string, new_string, replace_all = false } = args;
|
|
19
|
+
const content = await ctx.sandbox.fs.read(path);
|
|
20
|
+
if (replace_all) {
|
|
21
|
+
const occurrences = content.split(old_string).length - 1;
|
|
22
|
+
if (occurrences === 0) {
|
|
23
|
+
return { ok: false, error: 'old_string not found in file' };
|
|
24
|
+
}
|
|
25
|
+
const updated = content.split(old_string).join(new_string);
|
|
26
|
+
await ctx.sandbox.fs.write(path, updated);
|
|
27
|
+
await ctx.services?.filePool?.recordEdit(path);
|
|
28
|
+
return {
|
|
29
|
+
ok: true,
|
|
30
|
+
path,
|
|
31
|
+
replacements: occurrences,
|
|
32
|
+
lines: updated.split('\n').length,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
const occurrences = content.split(old_string).length - 1;
|
|
37
|
+
if (occurrences === 0) {
|
|
38
|
+
return { ok: false, error: 'old_string not found in file' };
|
|
39
|
+
}
|
|
40
|
+
if (occurrences > 1) {
|
|
41
|
+
return {
|
|
42
|
+
ok: false,
|
|
43
|
+
error: `old_string appears ${occurrences} times; set replace_all=true or provide more specific text`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const updated = content.replace(old_string, new_string);
|
|
47
|
+
await ctx.sandbox.fs.write(path, updated);
|
|
48
|
+
await ctx.services?.filePool?.recordEdit(path);
|
|
49
|
+
return {
|
|
50
|
+
ok: true,
|
|
51
|
+
path,
|
|
52
|
+
replacements: 1,
|
|
53
|
+
lines: updated.split('\n').length,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
metadata: {
|
|
58
|
+
readonly: false,
|
|
59
|
+
version: '1.0',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
exports.FsEdit.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DESCRIPTION = "Edit a file by replacing old_string with new_string";
|
|
2
|
+
export declare const PROMPT = "Use this tool for precise in-place edits.\n\nGuidelines:\n- Provide a unique \"old_string\" snippet to replace. If multiple matches exist, set \"replace_all\" to true.\n- Combine with fs_read to confirm the current file state before editing.\n- The tool integrates with FilePool to ensure the file has not changed externally.\n- If old_string is not unique, the tool will reject the operation unless replace_all is true.\n\nSafety/Limitations:\n- Single replacements require exact unique matches to avoid unintended changes.\n- Freshness validation prevents conflicts with external modifications.";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMPT = exports.DESCRIPTION = void 0;
|
|
4
|
+
exports.DESCRIPTION = 'Edit a file by replacing old_string with new_string';
|
|
5
|
+
exports.PROMPT = `Use this tool for precise in-place edits.
|
|
6
|
+
|
|
7
|
+
Guidelines:
|
|
8
|
+
- Provide a unique "old_string" snippet to replace. If multiple matches exist, set "replace_all" to true.
|
|
9
|
+
- Combine with fs_read to confirm the current file state before editing.
|
|
10
|
+
- The tool integrates with FilePool to ensure the file has not changed externally.
|
|
11
|
+
- If old_string is not unique, the tool will reject the operation unless replace_all is true.
|
|
12
|
+
|
|
13
|
+
Safety/Limitations:
|
|
14
|
+
- Single replacements require exact unique matches to avoid unintended changes.
|
|
15
|
+
- Freshness validation prevents conflicts with external modifications.`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FsGlob: import("..").ToolInstance;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FsGlob = void 0;
|
|
4
|
+
const tool_1 = require("../tool");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const type_inference_1 = require("../type-inference");
|
|
7
|
+
const prompt_1 = require("./prompt");
|
|
8
|
+
exports.FsGlob = (0, tool_1.tool)({
|
|
9
|
+
name: 'fs_glob',
|
|
10
|
+
description: prompt_1.DESCRIPTION,
|
|
11
|
+
parameters: zod_1.z.object({
|
|
12
|
+
pattern: zod_1.z.string().describe('Glob pattern to match'),
|
|
13
|
+
cwd: type_inference_1.patterns.optionalString('Optional directory to resolve from'),
|
|
14
|
+
dot: zod_1.z.boolean().optional().describe('Include dotfiles (default: false)'),
|
|
15
|
+
limit: type_inference_1.patterns.optionalNumber('Maximum number of results (default: 200)'),
|
|
16
|
+
}),
|
|
17
|
+
async execute(args, ctx) {
|
|
18
|
+
const { pattern, cwd, dot = false, limit = 200 } = args;
|
|
19
|
+
const matches = await ctx.sandbox.fs.glob(pattern, {
|
|
20
|
+
cwd,
|
|
21
|
+
dot,
|
|
22
|
+
absolute: false,
|
|
23
|
+
});
|
|
24
|
+
const truncated = matches.length > limit;
|
|
25
|
+
const results = matches.slice(0, limit);
|
|
26
|
+
return {
|
|
27
|
+
ok: true,
|
|
28
|
+
pattern,
|
|
29
|
+
cwd: cwd || '.',
|
|
30
|
+
truncated,
|
|
31
|
+
count: matches.length,
|
|
32
|
+
matches: results,
|
|
33
|
+
};
|
|
34
|
+
},
|
|
35
|
+
metadata: {
|
|
36
|
+
readonly: true,
|
|
37
|
+
version: '1.0',
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
exports.FsGlob.prompt = prompt_1.PROMPT;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const DESCRIPTION = "List files matching glob patterns";
|
|
2
|
+
export declare const PROMPT = "Use this tool to locate files with glob patterns (e.g. \"src/**/*.ts\").\n\nGuidelines:\n- It respects sandbox boundaries and returns relative paths by default.\n- Use standard glob syntax: * (any chars), ** (recursive directories), ? (single char).\n- Set \"dot\" to true to include hidden files (starting with .).\n- Results are limited to prevent overwhelming responses.\n\nSafety/Limitations:\n- All paths are restricted to the sandbox root directory.\n- Large result sets are truncated with a warning.";
|