c0de-agent 0.0.0 → 1.1.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 +101 -0
- package/dist/cli/commands/acp.d.ts +19 -0
- package/dist/cli/commands/acp.js +50 -0
- package/dist/cli/commands/chat.d.ts +13 -0
- package/dist/cli/commands/chat.js +26 -0
- package/dist/cli/commands/config.d.ts +17 -0
- package/dist/cli/commands/config.js +77 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.js +14 -0
- package/dist/cli/commands/plugin.d.ts +11 -0
- package/dist/cli/commands/plugin.js +31 -0
- package/dist/cli/commands/serve.d.ts +18 -0
- package/dist/cli/commands/serve.js +35 -0
- package/dist/cli/commands/update.d.ts +24 -0
- package/dist/cli/commands/update.js +40 -0
- package/dist/cli/deps.d.ts +30 -0
- package/dist/cli/deps.js +70 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +155 -0
- package/dist/cli/modes/acp.d.ts +18 -0
- package/dist/cli/modes/acp.js +57 -0
- package/dist/cli/modes/print.d.ts +16 -0
- package/dist/cli/modes/print.js +30 -0
- package/dist/cli/parser.d.ts +19 -0
- package/dist/cli/parser.js +28 -0
- package/dist/cli/utils/output.d.ts +11 -0
- package/dist/cli/utils/output.js +23 -0
- package/dist/cli/utils/prompt.d.ts +12 -0
- package/dist/cli/utils/prompt.js +18 -0
- package/dist/core/agent.d.ts +12 -0
- package/dist/core/agent.js +100 -0
- package/dist/core/agents/builtin.d.ts +6 -0
- package/dist/core/agents/builtin.js +76 -0
- package/dist/core/agents/discovery.d.ts +6 -0
- package/dist/core/agents/discovery.js +96 -0
- package/dist/core/agents/index.d.ts +6 -0
- package/dist/core/agents/index.js +4 -0
- package/dist/core/agents/parallel.d.ts +13 -0
- package/dist/core/agents/parallel.js +37 -0
- package/dist/core/agents/registry.d.ts +4 -0
- package/dist/core/agents/registry.js +23 -0
- package/dist/core/agents/types.d.ts +37 -0
- package/dist/core/agents/types.js +1 -0
- package/dist/core/compact.d.ts +11 -0
- package/dist/core/compact.js +31 -0
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.js +85 -0
- package/dist/core/context.d.ts +23 -0
- package/dist/core/context.js +93 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +11 -0
- package/dist/core/loop.d.ts +35 -0
- package/dist/core/loop.js +915 -0
- package/dist/core/metrics.d.ts +27 -0
- package/dist/core/metrics.js +94 -0
- package/dist/core/prompt-registry.d.ts +21 -0
- package/dist/core/prompt-registry.js +200 -0
- package/dist/core/prompt.d.ts +11 -0
- package/dist/core/prompt.js +13 -0
- package/dist/core/secret.d.ts +12 -0
- package/dist/core/secret.js +51 -0
- package/dist/core/slash.d.ts +15 -0
- package/dist/core/slash.js +113 -0
- package/dist/core/steering.d.ts +8 -0
- package/dist/core/steering.js +15 -0
- package/dist/core/title.d.ts +42 -0
- package/dist/core/title.js +116 -0
- package/dist/core/tool-exec.d.ts +20 -0
- package/dist/core/tool-exec.js +64 -0
- package/dist/core/types.d.ts +97 -0
- package/dist/core/types.js +1 -0
- package/dist/core/worktree.d.ts +24 -0
- package/dist/core/worktree.js +70 -0
- package/dist/dap/index.d.ts +6 -0
- package/dist/dap/index.js +4 -0
- package/dist/dap/protocol.d.ts +40 -0
- package/dist/dap/protocol.js +132 -0
- package/dist/dap/session.d.ts +23 -0
- package/dist/dap/session.js +130 -0
- package/dist/dap/transport.d.ts +8 -0
- package/dist/dap/transport.js +30 -0
- package/dist/dap/types.d.ts +50 -0
- package/dist/dap/types.js +2 -0
- package/dist/db/client.d.ts +22 -0
- package/dist/db/client.js +39 -0
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.js +4 -0
- package/dist/db/migrate.d.ts +9 -0
- package/dist/db/migrate.js +15 -0
- package/dist/db/schema.d.ts +965 -0
- package/dist/db/schema.js +112 -0
- package/dist/db/types.d.ts +11 -0
- package/dist/db/types.js +1 -0
- package/dist/llm/index.d.ts +13 -0
- package/dist/llm/index.js +8 -0
- package/dist/llm/protocols/openai-compat.d.ts +139 -0
- package/dist/llm/protocols/openai-compat.js +214 -0
- package/dist/llm/protocols/utils/index.d.ts +2 -0
- package/dist/llm/protocols/utils/index.js +2 -0
- package/dist/llm/protocols/utils/lifecycle.d.ts +23 -0
- package/dist/llm/protocols/utils/lifecycle.js +46 -0
- package/dist/llm/protocols/utils/tool-stream.d.ts +46 -0
- package/dist/llm/protocols/utils/tool-stream.js +94 -0
- package/dist/llm/provider-error.d.ts +5 -0
- package/dist/llm/provider-error.js +33 -0
- package/dist/llm/provider.d.ts +32 -0
- package/dist/llm/provider.js +195 -0
- package/dist/llm/registry.d.ts +44 -0
- package/dist/llm/registry.js +107 -0
- package/dist/llm/retry.d.ts +37 -0
- package/dist/llm/retry.js +82 -0
- package/dist/llm/routing.d.ts +36 -0
- package/dist/llm/routing.js +53 -0
- package/dist/llm/schema/errors.d.ts +88 -0
- package/dist/llm/schema/errors.js +33 -0
- package/dist/llm/schema/events.d.ts +135 -0
- package/dist/llm/schema/events.js +35 -0
- package/dist/llm/schema/ids.d.ts +22 -0
- package/dist/llm/schema/ids.js +3 -0
- package/dist/llm/schema/index.d.ts +5 -0
- package/dist/llm/schema/index.js +5 -0
- package/dist/llm/schema/messages.d.ts +97 -0
- package/dist/llm/schema/messages.js +18 -0
- package/dist/llm/schema/options.d.ts +54 -0
- package/dist/llm/schema/options.js +54 -0
- package/dist/llm/token.d.ts +2 -0
- package/dist/llm/token.js +13 -0
- package/dist/llm/transport.d.ts +31 -0
- package/dist/llm/transport.js +165 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +3 -0
- package/dist/plugins/builtin.d.ts +6 -0
- package/dist/plugins/builtin.js +54 -0
- package/dist/plugins/hooks.d.ts +3 -0
- package/dist/plugins/hooks.js +79 -0
- package/dist/plugins/index.d.ts +9 -0
- package/dist/plugins/index.js +8 -0
- package/dist/plugins/init.d.ts +23 -0
- package/dist/plugins/init.js +30 -0
- package/dist/plugins/lifecycle.d.ts +6 -0
- package/dist/plugins/lifecycle.js +74 -0
- package/dist/plugins/loader.d.ts +16 -0
- package/dist/plugins/loader.js +69 -0
- package/dist/plugins/logger.d.ts +4 -0
- package/dist/plugins/logger.js +31 -0
- package/dist/plugins/registry.d.ts +7 -0
- package/dist/plugins/registry.js +24 -0
- package/dist/plugins/types.d.ts +113 -0
- package/dist/plugins/types.js +1 -0
- package/dist/project/detect.d.ts +4 -0
- package/dist/project/detect.js +131 -0
- package/dist/project/index.d.ts +4 -0
- package/dist/project/index.js +2 -0
- package/dist/project/project.d.ts +23 -0
- package/dist/project/project.js +87 -0
- package/dist/project/resolve.d.ts +8 -0
- package/dist/project/resolve.js +81 -0
- package/dist/server/agent-manager.d.ts +34 -0
- package/dist/server/agent-manager.js +62 -0
- package/dist/server/app.d.ts +5 -0
- package/dist/server/app.js +78 -0
- package/dist/server/context.d.ts +20 -0
- package/dist/server/context.js +49 -0
- package/dist/server/dev.d.ts +14 -0
- package/dist/server/dev.js +148 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +7 -0
- package/dist/server/middleware/auth.d.ts +15 -0
- package/dist/server/middleware/auth.js +29 -0
- package/dist/server/middleware/cors.d.ts +16 -0
- package/dist/server/middleware/cors.js +44 -0
- package/dist/server/middleware/error.d.ts +15 -0
- package/dist/server/middleware/error.js +11 -0
- package/dist/server/permission/interactive.d.ts +24 -0
- package/dist/server/permission/interactive.js +56 -0
- package/dist/server/permission/store.d.ts +32 -0
- package/dist/server/permission/store.js +56 -0
- package/dist/server/routes/agent.d.ts +4 -0
- package/dist/server/routes/agent.js +19 -0
- package/dist/server/routes/catalog.d.ts +42 -0
- package/dist/server/routes/catalog.js +194 -0
- package/dist/server/routes/chat.d.ts +8 -0
- package/dist/server/routes/chat.js +318 -0
- package/dist/server/routes/commands.d.ts +5 -0
- package/dist/server/routes/commands.js +17 -0
- package/dist/server/routes/config.d.ts +4 -0
- package/dist/server/routes/config.js +27 -0
- package/dist/server/routes/files.d.ts +4 -0
- package/dist/server/routes/files.js +183 -0
- package/dist/server/routes/filesystem.d.ts +29 -0
- package/dist/server/routes/filesystem.js +108 -0
- package/dist/server/routes/health.d.ts +3 -0
- package/dist/server/routes/health.js +13 -0
- package/dist/server/routes/permissions.d.ts +5 -0
- package/dist/server/routes/permissions.js +23 -0
- package/dist/server/routes/project.d.ts +4 -0
- package/dist/server/routes/project.js +51 -0
- package/dist/server/routes/provider.d.ts +16 -0
- package/dist/server/routes/provider.js +66 -0
- package/dist/server/routes/session.d.ts +4 -0
- package/dist/server/routes/session.js +204 -0
- package/dist/server/routes/terminal.d.ts +5 -0
- package/dist/server/routes/terminal.js +66 -0
- package/dist/server/routes/tool.d.ts +4 -0
- package/dist/server/routes/tool.js +28 -0
- package/dist/server/routes/update.d.ts +14 -0
- package/dist/server/routes/update.js +49 -0
- package/dist/server/server.d.ts +56 -0
- package/dist/server/server.js +269 -0
- package/dist/server/terminal/pty-manager.d.ts +53 -0
- package/dist/server/terminal/pty-manager.js +160 -0
- package/dist/server/types.d.ts +76 -0
- package/dist/server/types.js +2 -0
- package/dist/server/util/safe-path.d.ts +7 -0
- package/dist/server/util/safe-path.js +7 -0
- package/dist/session/archive.d.ts +15 -0
- package/dist/session/archive.js +129 -0
- package/dist/session/branch.d.ts +9 -0
- package/dist/session/branch.js +63 -0
- package/dist/session/compaction.d.ts +33 -0
- package/dist/session/compaction.js +261 -0
- package/dist/session/context.d.ts +16 -0
- package/dist/session/context.js +173 -0
- package/dist/session/index.d.ts +10 -0
- package/dist/session/index.js +10 -0
- package/dist/session/message.d.ts +22 -0
- package/dist/session/message.js +145 -0
- package/dist/session/session.d.ts +37 -0
- package/dist/session/session.js +144 -0
- package/dist/session/shake.d.ts +66 -0
- package/dist/session/shake.js +304 -0
- package/dist/session/snapshot.d.ts +11 -0
- package/dist/session/snapshot.js +60 -0
- package/dist/session/squash.d.ts +9 -0
- package/dist/session/squash.js +88 -0
- package/dist/session/token.d.ts +10 -0
- package/dist/session/token.js +33 -0
- package/dist/session/types.d.ts +122 -0
- package/dist/session/types.js +1 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/types/agent.d.ts +229 -0
- package/dist/shared/types/agent.js +1 -0
- package/dist/shared/types/base.d.ts +32 -0
- package/dist/shared/types/base.js +1 -0
- package/dist/shared/types/config.d.ts +114 -0
- package/dist/shared/types/config.js +1 -0
- package/dist/shared/types/index.d.ts +6 -0
- package/dist/shared/types/index.js +1 -0
- package/dist/shared/types/llm.d.ts +123 -0
- package/dist/shared/types/llm.js +1 -0
- package/dist/shared/types/message.d.ts +71 -0
- package/dist/shared/types/message.js +1 -0
- package/dist/shared/types/tool.d.ts +137 -0
- package/dist/shared/types/tool.js +1 -0
- package/dist/shared/utils/path.d.ts +15 -0
- package/dist/shared/utils/path.js +23 -0
- package/dist/shared/utils.d.ts +5 -0
- package/dist/shared/utils.js +10 -0
- package/dist/tools/builtin/bash.d.ts +12 -0
- package/dist/tools/builtin/bash.js +121 -0
- package/dist/tools/builtin/dap.d.ts +23 -0
- package/dist/tools/builtin/dap.js +231 -0
- package/dist/tools/builtin/edit.d.ts +12 -0
- package/dist/tools/builtin/edit.js +151 -0
- package/dist/tools/builtin/glob.d.ts +11 -0
- package/dist/tools/builtin/glob.js +120 -0
- package/dist/tools/builtin/grep.d.ts +6 -0
- package/dist/tools/builtin/grep.js +141 -0
- package/dist/tools/builtin/read.d.ts +6 -0
- package/dist/tools/builtin/read.js +73 -0
- package/dist/tools/builtin/resolvers.d.ts +12 -0
- package/dist/tools/builtin/resolvers.js +79 -0
- package/dist/tools/builtin/task.d.ts +9 -0
- package/dist/tools/builtin/task.js +100 -0
- package/dist/tools/builtin/write.d.ts +6 -0
- package/dist/tools/builtin/write.js +36 -0
- package/dist/tools/builtin/yield.d.ts +9 -0
- package/dist/tools/builtin/yield.js +40 -0
- package/dist/tools/executor.d.ts +9 -0
- package/dist/tools/executor.js +54 -0
- package/dist/tools/hashline/index.d.ts +2 -0
- package/dist/tools/hashline/index.js +3 -0
- package/dist/tools/hashline/patch.d.ts +48 -0
- package/dist/tools/hashline/patch.js +201 -0
- package/dist/tools/index.d.ts +30 -0
- package/dist/tools/index.js +55 -0
- package/dist/tools/permission.d.ts +13 -0
- package/dist/tools/permission.js +39 -0
- package/dist/tools/registry.d.ts +15 -0
- package/dist/tools/registry.js +54 -0
- package/dist/tools/resolver.d.ts +15 -0
- package/dist/tools/resolver.js +47 -0
- package/dist/tools/truncate.d.ts +8 -0
- package/dist/tools/truncate.js +50 -0
- package/dist/tools/types.d.ts +101 -0
- package/dist/tools/types.js +1 -0
- package/dist/tools/validate.d.ts +8 -0
- package/dist/tools/validate.js +130 -0
- package/dist/tools/websearch/fetch.d.ts +11 -0
- package/dist/tools/websearch/fetch.js +21 -0
- package/dist/tools/websearch/index.d.ts +19 -0
- package/dist/tools/websearch/index.js +78 -0
- package/dist/tools/websearch/providers/brave.d.ts +5 -0
- package/dist/tools/websearch/providers/brave.js +53 -0
- package/dist/tools/websearch/providers/duckduckgo.d.ts +3 -0
- package/dist/tools/websearch/providers/duckduckgo.js +75 -0
- package/dist/tools/websearch/providers/tavily.d.ts +11 -0
- package/dist/tools/websearch/providers/tavily.js +89 -0
- package/dist/tools/websearch/types.d.ts +51 -0
- package/dist/tools/websearch/types.js +18 -0
- package/dist/tools/websearch/websearch.d.ts +10 -0
- package/dist/tools/websearch/websearch.js +48 -0
- package/dist/update/index.d.ts +10 -0
- package/dist/update/index.js +6 -0
- package/dist/update/ipc.d.ts +15 -0
- package/dist/update/ipc.js +41 -0
- package/dist/update/scheduler.d.ts +34 -0
- package/dist/update/scheduler.js +57 -0
- package/dist/update/snapshot.d.ts +39 -0
- package/dist/update/snapshot.js +99 -0
- package/dist/update/updater.d.ts +48 -0
- package/dist/update/updater.js +83 -0
- package/dist/update/version.d.ts +18 -0
- package/dist/update/version.js +49 -0
- package/drizzle/0000_magical_nightshade.sql +55 -0
- package/drizzle/0001_chemical_doctor_faustus.sql +13 -0
- package/drizzle/0002_amusing_micromacro.sql +12 -0
- package/drizzle/0003_regular_purifiers.sql +2 -0
- package/drizzle/meta/0000_snapshot.json +448 -0
- package/drizzle/meta/0001_snapshot.json +539 -0
- package/drizzle/meta/0002_snapshot.json +633 -0
- package/drizzle/meta/0003_snapshot.json +645 -0
- package/drizzle/meta/_journal.json +34 -0
- package/package.json +108 -8
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* task 工具:按 agent 类型派发子 agent。
|
|
3
|
+
*
|
|
4
|
+
* 两种形态:单任务(subagent_type + prompt)或批量并行(subagent_type + context + tasks[])。
|
|
5
|
+
* 依赖反转:实际子 agent 运行由 host(core loop 的 runSubAgent)通过 ctx.runSubAgent 执行。
|
|
6
|
+
* permission: auto(子 agent 是隔离 session,不扩宽父权限)。
|
|
7
|
+
*/
|
|
8
|
+
export const taskTool = {
|
|
9
|
+
name: 'task',
|
|
10
|
+
description: 'Launch specialized sub-agents to handle delegated tasks. Specify subagent_type to select a specialist (e.g. researcher for read-only investigation, coder for implementation, reviewer for code review). Launch multiple agents concurrently by using the batch form with tasks[]. The sub-agent runs in an isolated session with its own context. When done, the sub-agent returns its result via the yield tool.',
|
|
11
|
+
parameters: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
subagent_type: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: "The specialist agent type (e.g. researcher, coder, reviewer). Defaults to 'general'.",
|
|
17
|
+
},
|
|
18
|
+
description: { type: 'string', description: 'Short label for the task (display only).' },
|
|
19
|
+
prompt: { type: 'string', description: 'Self-contained assignment (single-task mode).' },
|
|
20
|
+
model: { type: 'string', description: 'Optional model override.' },
|
|
21
|
+
background: { type: 'boolean', description: 'Run in background (default false).' },
|
|
22
|
+
context: { type: 'string', description: 'Shared context (batch mode).' },
|
|
23
|
+
tasks: {
|
|
24
|
+
type: 'array',
|
|
25
|
+
items: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
description: { type: 'string' },
|
|
29
|
+
role: { type: 'string', description: 'Specialist role for this sub-task.' },
|
|
30
|
+
assignment: { type: 'string' },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
description: 'Parallel sub-tasks (batch mode).',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
required: ['prompt'],
|
|
37
|
+
anyOf: [{ required: ['prompt'] }, { required: ['context', 'tasks'] }],
|
|
38
|
+
},
|
|
39
|
+
permission: 'auto',
|
|
40
|
+
execute: async (input, ctx) => {
|
|
41
|
+
if (!ctx.runSubAgent) {
|
|
42
|
+
return {
|
|
43
|
+
_tag: 'error',
|
|
44
|
+
error: 'task tool unavailable: no sub-agent runner is wired into this context',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const inp = input;
|
|
48
|
+
// 批量模式
|
|
49
|
+
if ('tasks' in inp && Array.isArray(inp.tasks) && inp.tasks.length > 0) {
|
|
50
|
+
const agentType = inp.subagent_type ?? 'general';
|
|
51
|
+
const results = [];
|
|
52
|
+
for (const item of inp.tasks) {
|
|
53
|
+
const req = {
|
|
54
|
+
agentType,
|
|
55
|
+
prompt: item.assignment,
|
|
56
|
+
...(item.description ? { description: item.description } : {}),
|
|
57
|
+
...(item.role ? { role: item.role } : {}),
|
|
58
|
+
...(inp.context ? { context: inp.context } : {}),
|
|
59
|
+
};
|
|
60
|
+
const res = await ctx.runSubAgent(req);
|
|
61
|
+
if (res._tag === 'error') {
|
|
62
|
+
return { _tag: 'error', error: `Sub-agent failed: ${res.error}` };
|
|
63
|
+
}
|
|
64
|
+
const label = item.description ?? item.role ?? 'task';
|
|
65
|
+
if (res._tag === 'running') {
|
|
66
|
+
results.push(`[${label}] background started (jobId: ${res.jobId})`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
results.push(`[${label}] ${res.output}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { _tag: 'success', output: results.join('\n\n') };
|
|
73
|
+
}
|
|
74
|
+
// 单任务模式
|
|
75
|
+
const single = inp;
|
|
76
|
+
const req = {
|
|
77
|
+
agentType: single.subagent_type ?? 'general',
|
|
78
|
+
prompt: single.prompt,
|
|
79
|
+
...(single.description ? { description: single.description } : {}),
|
|
80
|
+
...(single.model ? { model: single.model } : {}),
|
|
81
|
+
...(single.background ? { background: true } : {}),
|
|
82
|
+
};
|
|
83
|
+
const result = await ctx.runSubAgent(req);
|
|
84
|
+
if (result._tag === 'error') {
|
|
85
|
+
return { _tag: 'error', error: `Sub-agent failed: ${result.error}` };
|
|
86
|
+
}
|
|
87
|
+
if (result._tag === 'running') {
|
|
88
|
+
return {
|
|
89
|
+
_tag: 'success',
|
|
90
|
+
output: `Background task started (jobId: ${result.jobId}). You will be notified on completion.`,
|
|
91
|
+
metadata: { sessionId: result.sessionId, background: true, jobId: result.jobId },
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
_tag: 'success',
|
|
96
|
+
output: result.output,
|
|
97
|
+
metadata: { sessionId: result.sessionId, ...(result.data ? { data: result.data } : {}) },
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { safeResolve } from '../../shared/utils/path.js';
|
|
4
|
+
/**
|
|
5
|
+
* write tool: create or overwrite a file.
|
|
6
|
+
* Permission: ask (modifies filesystem).
|
|
7
|
+
*/
|
|
8
|
+
export const writeTool = {
|
|
9
|
+
name: 'write',
|
|
10
|
+
description: 'Create or overwrite a file with the given content. Creates parent directories.',
|
|
11
|
+
parameters: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
path: { type: 'string', description: 'File path (relative to cwd or absolute).' },
|
|
15
|
+
content: { type: 'string', description: 'Content to write.' },
|
|
16
|
+
},
|
|
17
|
+
required: ['path', 'content'],
|
|
18
|
+
},
|
|
19
|
+
permission: 'ask',
|
|
20
|
+
execute: async (input, ctx) => {
|
|
21
|
+
const { path, content } = input;
|
|
22
|
+
const fullPath = safeResolve(ctx.cwd, path);
|
|
23
|
+
if (fullPath === null) {
|
|
24
|
+
return { _tag: 'error', error: `Path "${path}" escapes the working directory` };
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
await mkdir(dirname(fullPath), { recursive: true });
|
|
28
|
+
await writeFile(fullPath, content, 'utf-8');
|
|
29
|
+
return { _tag: 'success', output: `Wrote ${content.length} bytes to ${path}` };
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
33
|
+
return { _tag: 'error', error: `Failed to write "${path}": ${message}` };
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolDef } from '../../shared/types/tool.js';
|
|
2
|
+
/**
|
|
3
|
+
* yield 工具:子 agent 专用,提交结构化最终结果。
|
|
4
|
+
*
|
|
5
|
+
* 这是子 agent 返回结果的唯一方式。调用后,runSubAgent 的 collectYield
|
|
6
|
+
* 回调收集结果,子 agent loop 检测到 yield 后优雅终止。
|
|
7
|
+
* 主 agent 不注册此工具。permission: auto(纯结果收集,不改外部状态)。
|
|
8
|
+
*/
|
|
9
|
+
export declare const yieldTool: ToolDef;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* yield 工具:子 agent 专用,提交结构化最终结果。
|
|
3
|
+
*
|
|
4
|
+
* 这是子 agent 返回结果的唯一方式。调用后,runSubAgent 的 collectYield
|
|
5
|
+
* 回调收集结果,子 agent loop 检测到 yield 后优雅终止。
|
|
6
|
+
* 主 agent 不注册此工具。permission: auto(纯结果收集,不改外部状态)。
|
|
7
|
+
*/
|
|
8
|
+
export const yieldTool = {
|
|
9
|
+
name: 'yield',
|
|
10
|
+
description: 'Submit your final structured result. This is the ONLY way to return a result from a sub-agent task. Call this once when your work is complete.',
|
|
11
|
+
parameters: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
data: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
description: 'Your structured result. Must match the outputSchema if the agent declared one.',
|
|
17
|
+
},
|
|
18
|
+
type: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
description: 'Optional section label for incremental yields.',
|
|
21
|
+
},
|
|
22
|
+
status: {
|
|
23
|
+
type: 'string',
|
|
24
|
+
enum: ['success', 'aborted'],
|
|
25
|
+
description: 'Outcome status. Use "aborted" if blocked.',
|
|
26
|
+
},
|
|
27
|
+
error: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'If blocked (status=aborted), describe what you tried and the exact blocker.',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
required: ['data'],
|
|
33
|
+
},
|
|
34
|
+
permission: 'auto',
|
|
35
|
+
execute: async (input, ctx) => {
|
|
36
|
+
const { data } = input;
|
|
37
|
+
ctx.collectYield?.(data);
|
|
38
|
+
return { _tag: 'success', output: 'Result submitted.' };
|
|
39
|
+
},
|
|
40
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolContext, ToolResult } from '../shared/types/tool.js';
|
|
2
|
+
import type { PermissionChecker, ToolRegistry } from './types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Execute a tool by name with full pipeline:
|
|
5
|
+
* find tool → validate input → check permission → execute → truncate output.
|
|
6
|
+
*
|
|
7
|
+
* Returns the ToolResult. Never throws — all errors become { _tag: 'error' }.
|
|
8
|
+
*/
|
|
9
|
+
export declare function executeTool(registry: ToolRegistry, name: string, input: unknown, ctx: ToolContext, permissionChecker: PermissionChecker): Promise<ToolResult>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getTool } from './registry.js';
|
|
2
|
+
import { truncateOutput } from './truncate.js';
|
|
3
|
+
import { validateInput } from './validate.js';
|
|
4
|
+
/**
|
|
5
|
+
* Execute a tool by name with full pipeline:
|
|
6
|
+
* find tool → validate input → check permission → execute → truncate output.
|
|
7
|
+
*
|
|
8
|
+
* Returns the ToolResult. Never throws — all errors become { _tag: 'error' }.
|
|
9
|
+
*/
|
|
10
|
+
export async function executeTool(registry, name, input, ctx, permissionChecker) {
|
|
11
|
+
// 0. Check abort signal
|
|
12
|
+
if (ctx.abort.aborted) {
|
|
13
|
+
return { _tag: 'error', error: 'Operation aborted before execution' };
|
|
14
|
+
}
|
|
15
|
+
// 1. Find tool
|
|
16
|
+
const tool = getTool(registry, name, { config: {}, cwd: ctx.cwd });
|
|
17
|
+
if (!tool) {
|
|
18
|
+
return { _tag: 'error', error: `Tool not found: ${name}` };
|
|
19
|
+
}
|
|
20
|
+
// 2. Validate input against JSON Schema
|
|
21
|
+
const validation = validateInput(tool.parameters, input);
|
|
22
|
+
if (!validation.valid) {
|
|
23
|
+
return { _tag: 'error', error: `Invalid input for "${name}": ${validation.error}` };
|
|
24
|
+
}
|
|
25
|
+
// 3. Check permission
|
|
26
|
+
const permission = await permissionChecker.check(tool, input, ctx);
|
|
27
|
+
if (permission._tag === 'deny') {
|
|
28
|
+
return { _tag: 'error', error: `Permission denied: ${permission.reason}` };
|
|
29
|
+
}
|
|
30
|
+
if (permission._tag === 'ask') {
|
|
31
|
+
return { _tag: 'permission_required', reason: permission.reason };
|
|
32
|
+
}
|
|
33
|
+
// 4. Execute
|
|
34
|
+
try {
|
|
35
|
+
const result = await tool.execute(input, ctx);
|
|
36
|
+
// 5. Truncate large output
|
|
37
|
+
if (result._tag === 'success') {
|
|
38
|
+
const truncated = truncateOutput(result.output);
|
|
39
|
+
if (truncated.truncated) {
|
|
40
|
+
return {
|
|
41
|
+
_tag: 'truncated',
|
|
42
|
+
output: truncated.output,
|
|
43
|
+
truncated: true,
|
|
44
|
+
totalLines: truncated.totalLines,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
return { _tag: 'error', error: `Tool "${name}" failed: ${message}` };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
type PatchOp = {
|
|
2
|
+
_tag: 'SWAP';
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
content: string;
|
|
6
|
+
} | {
|
|
7
|
+
_tag: 'DEL';
|
|
8
|
+
start: number;
|
|
9
|
+
end: number;
|
|
10
|
+
} | {
|
|
11
|
+
_tag: 'INS_PRE';
|
|
12
|
+
line: number;
|
|
13
|
+
content: string;
|
|
14
|
+
} | {
|
|
15
|
+
_tag: 'INS_POST';
|
|
16
|
+
line: number;
|
|
17
|
+
content: string;
|
|
18
|
+
} | {
|
|
19
|
+
_tag: 'INS_HEAD';
|
|
20
|
+
content: string;
|
|
21
|
+
} | {
|
|
22
|
+
_tag: 'INS_TAIL';
|
|
23
|
+
content: string;
|
|
24
|
+
};
|
|
25
|
+
type ParsedPatch = {
|
|
26
|
+
path: string;
|
|
27
|
+
hash: string;
|
|
28
|
+
operations: PatchOp[];
|
|
29
|
+
};
|
|
30
|
+
type ApplyResult = {
|
|
31
|
+
_tag: 'success';
|
|
32
|
+
content: string;
|
|
33
|
+
} | {
|
|
34
|
+
_tag: 'hash_mismatch';
|
|
35
|
+
expected: string;
|
|
36
|
+
actual: string;
|
|
37
|
+
} | {
|
|
38
|
+
_tag: 'line_not_found';
|
|
39
|
+
operation: PatchOp;
|
|
40
|
+
};
|
|
41
|
+
/** 4 位 hex 内容哈希(sha256 取前 4 位)。与 session 快照哈希算法同源。 */
|
|
42
|
+
declare function computeHash(content: string): string;
|
|
43
|
+
/** 解析补丁文本为一个或多个 ParsedPatch(按 `[path#hash]` 头分块)。 */
|
|
44
|
+
declare function parsePatch(input: string): ParsedPatch[];
|
|
45
|
+
/** 应用一个补丁到文件内容。先校验哈希,再按锚点降序应用操作。 */
|
|
46
|
+
declare function applyPatch(file: string, patch: ParsedPatch): ApplyResult;
|
|
47
|
+
export type { ApplyResult, ParsedPatch, PatchOp };
|
|
48
|
+
export { applyPatch, computeHash, parsePatch };
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
// ── computeHash ──────────────────────────────────────────
|
|
3
|
+
/** 4 位 hex 内容哈希(sha256 取前 4 位)。与 session 快照哈希算法同源。 */
|
|
4
|
+
function computeHash(content) {
|
|
5
|
+
return createHash('sha256').update(content).digest('hex').slice(0, 4);
|
|
6
|
+
}
|
|
7
|
+
// ── parsePatch ───────────────────────────────────────────
|
|
8
|
+
const HEADER_RE = /^\[(.+?)#([0-9a-fA-F]+)\]\s*$/;
|
|
9
|
+
/** 解析一个 `[path#hash]` 块内的操作序列。lines 为该块头之后的行。 */
|
|
10
|
+
function parseOps(lines) {
|
|
11
|
+
const ops = [];
|
|
12
|
+
let i = 0;
|
|
13
|
+
while (i < lines.length) {
|
|
14
|
+
const line = lines[i];
|
|
15
|
+
if (!line || line.trim() === '') {
|
|
16
|
+
i++;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
const tokens = line.split(/\s+/);
|
|
20
|
+
const head = tokens[0];
|
|
21
|
+
if (!head)
|
|
22
|
+
throw new Error('hashline: empty operation line');
|
|
23
|
+
// 收集到下一个分隔符 `---`(或块尾)的内容行
|
|
24
|
+
const collectContent = () => {
|
|
25
|
+
const body = [];
|
|
26
|
+
let j = i + 1;
|
|
27
|
+
while (j < lines.length && lines[j] !== '---') {
|
|
28
|
+
body.push(lines[j] ?? '');
|
|
29
|
+
j++;
|
|
30
|
+
}
|
|
31
|
+
return { content: body.join('\n'), next: j + 1 };
|
|
32
|
+
};
|
|
33
|
+
// 无内容体(DEL)也吃掉到 `---`
|
|
34
|
+
const skipToSeparator = () => {
|
|
35
|
+
let j = i + 1;
|
|
36
|
+
while (j < lines.length && lines[j] !== '---')
|
|
37
|
+
j++;
|
|
38
|
+
return j + 1;
|
|
39
|
+
};
|
|
40
|
+
if (head === 'SWAP') {
|
|
41
|
+
const [s, e] = parseRange(tokens[1]);
|
|
42
|
+
const { content, next } = collectContent();
|
|
43
|
+
ops.push({ _tag: 'SWAP', start: s, end: e ?? s, content });
|
|
44
|
+
i = next;
|
|
45
|
+
}
|
|
46
|
+
else if (head === 'DEL') {
|
|
47
|
+
const [s, e] = parseRange(tokens[1]);
|
|
48
|
+
ops.push({ _tag: 'DEL', start: s, end: e ?? s });
|
|
49
|
+
i = skipToSeparator();
|
|
50
|
+
}
|
|
51
|
+
else if (head === 'INS.PRE') {
|
|
52
|
+
const { content, next } = collectContent();
|
|
53
|
+
ops.push({ _tag: 'INS_PRE', line: Number(tokens[1]), content });
|
|
54
|
+
i = next;
|
|
55
|
+
}
|
|
56
|
+
else if (head === 'INS.POST') {
|
|
57
|
+
const { content, next } = collectContent();
|
|
58
|
+
ops.push({ _tag: 'INS_POST', line: Number(tokens[1]), content });
|
|
59
|
+
i = next;
|
|
60
|
+
}
|
|
61
|
+
else if (head === 'INS.HEAD') {
|
|
62
|
+
const { content, next } = collectContent();
|
|
63
|
+
ops.push({ _tag: 'INS_HEAD', content });
|
|
64
|
+
i = next;
|
|
65
|
+
}
|
|
66
|
+
else if (head === 'INS.TAIL') {
|
|
67
|
+
const { content, next } = collectContent();
|
|
68
|
+
ops.push({ _tag: 'INS_TAIL', content });
|
|
69
|
+
i = next;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error(`hashline: unknown operation "${head}"`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return ops;
|
|
76
|
+
}
|
|
77
|
+
/** 解析 `start` 或 `start-end`,返回 [start, end?](1-indexed)。 */
|
|
78
|
+
function parseRange(spec) {
|
|
79
|
+
if (!spec)
|
|
80
|
+
throw new Error('hashline: missing line range');
|
|
81
|
+
if (spec.includes('-')) {
|
|
82
|
+
const [a, b] = spec.split('-');
|
|
83
|
+
return [Number(a), Number(b)];
|
|
84
|
+
}
|
|
85
|
+
return [Number(spec), undefined];
|
|
86
|
+
}
|
|
87
|
+
/** 解析补丁文本为一个或多个 ParsedPatch(按 `[path#hash]` 头分块)。 */
|
|
88
|
+
function parsePatch(input) {
|
|
89
|
+
const lines = input.split('\n');
|
|
90
|
+
const patches = [];
|
|
91
|
+
let i = 0;
|
|
92
|
+
while (i < lines.length) {
|
|
93
|
+
const line = lines[i];
|
|
94
|
+
if (!line || line.trim() === '') {
|
|
95
|
+
i++;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const m = HEADER_RE.exec(line);
|
|
99
|
+
if (!m)
|
|
100
|
+
throw new Error(`hashline: malformed header "${line}"`);
|
|
101
|
+
const path = m[1] ?? '';
|
|
102
|
+
const hash = m[2] ?? '';
|
|
103
|
+
const block = lines.slice(i + 1);
|
|
104
|
+
const endIdx = block.indexOf(''); // 块以空行或文件尾分隔(其实下一头才分隔)
|
|
105
|
+
// 操作持续到下一个头或文件尾:找到下一个 HEADER_RE 匹配行
|
|
106
|
+
let nextHead = block.length;
|
|
107
|
+
for (let k = 0; k < block.length; k++) {
|
|
108
|
+
if (HEADER_RE.test((block[k] ?? '').trim())) {
|
|
109
|
+
nextHead = k;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
void endIdx;
|
|
114
|
+
const opsLines = block.slice(0, nextHead);
|
|
115
|
+
patches.push({ path, hash, operations: parseOps(opsLines) });
|
|
116
|
+
i = i + 1 + nextHead;
|
|
117
|
+
}
|
|
118
|
+
return patches;
|
|
119
|
+
}
|
|
120
|
+
// ── applyPatch ───────────────────────────────────────────
|
|
121
|
+
/** 每个操作基于原文件的"锚点行号",用于排序使从后往前应用。 */
|
|
122
|
+
function anchor(op, lineCount) {
|
|
123
|
+
switch (op._tag) {
|
|
124
|
+
case 'SWAP':
|
|
125
|
+
case 'DEL':
|
|
126
|
+
return op.start;
|
|
127
|
+
case 'INS_PRE':
|
|
128
|
+
return op.line;
|
|
129
|
+
case 'INS_POST':
|
|
130
|
+
return op.line + 1;
|
|
131
|
+
case 'INS_HEAD':
|
|
132
|
+
return 1;
|
|
133
|
+
case 'INS_TAIL':
|
|
134
|
+
return lineCount + 1;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
/** 校验操作的行号范围是否落在 [1, lineCount]。 */
|
|
138
|
+
function inBounds(op, lineCount) {
|
|
139
|
+
switch (op._tag) {
|
|
140
|
+
case 'SWAP':
|
|
141
|
+
case 'DEL':
|
|
142
|
+
return op.start >= 1 && op.end <= lineCount && op.start <= op.end;
|
|
143
|
+
case 'INS_PRE':
|
|
144
|
+
case 'INS_POST':
|
|
145
|
+
return op.line >= 1 && op.line <= lineCount;
|
|
146
|
+
case 'INS_HEAD':
|
|
147
|
+
case 'INS_TAIL':
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** 应用一个补丁到文件内容。先校验哈希,再按锚点降序应用操作。 */
|
|
152
|
+
function applyPatch(file, patch) {
|
|
153
|
+
const actual = computeHash(file);
|
|
154
|
+
if (actual !== patch.hash) {
|
|
155
|
+
return { _tag: 'hash_mismatch', expected: patch.hash, actual };
|
|
156
|
+
}
|
|
157
|
+
// 末尾换行保留策略:按 \n 拆分,末尾空串代表文件以换行结尾。
|
|
158
|
+
const hadTrailingNewline = file.endsWith('\n');
|
|
159
|
+
const src = hadTrailingNewline ? file.slice(0, -1) : file;
|
|
160
|
+
const lines = src.split('\n');
|
|
161
|
+
const lineCount = lines.length;
|
|
162
|
+
// 先全部校验范围,任一越界即 line_not_found(保持原文件不变)
|
|
163
|
+
for (const op of patch.operations) {
|
|
164
|
+
if (!inBounds(op, lineCount)) {
|
|
165
|
+
return { _tag: 'line_not_found', operation: op };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// 按锚点降序应用:高行号先改,低行号锚点不受影响
|
|
169
|
+
const ordered = [...patch.operations].sort((a, b) => {
|
|
170
|
+
const lineCountFinal = lineCount;
|
|
171
|
+
return anchor(b, lineCountFinal) - anchor(a, lineCountFinal);
|
|
172
|
+
});
|
|
173
|
+
for (const op of ordered) {
|
|
174
|
+
const contentLines = 'content' in op && op.content !== '' ? op.content.split('\n') : [];
|
|
175
|
+
switch (op._tag) {
|
|
176
|
+
case 'SWAP':
|
|
177
|
+
lines.splice(op.start - 1, op.end - op.start + 1, ...contentLines);
|
|
178
|
+
break;
|
|
179
|
+
case 'DEL':
|
|
180
|
+
lines.splice(op.start - 1, op.end - op.start + 1);
|
|
181
|
+
break;
|
|
182
|
+
case 'INS_PRE':
|
|
183
|
+
lines.splice(op.line - 1, 0, ...contentLines);
|
|
184
|
+
break;
|
|
185
|
+
case 'INS_POST':
|
|
186
|
+
lines.splice(op.line, 0, ...contentLines);
|
|
187
|
+
break;
|
|
188
|
+
case 'INS_HEAD':
|
|
189
|
+
lines.unshift(...contentLines);
|
|
190
|
+
break;
|
|
191
|
+
case 'INS_TAIL':
|
|
192
|
+
lines.push(...contentLines);
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
let result = lines.join('\n');
|
|
197
|
+
if (hadTrailingNewline)
|
|
198
|
+
result += '\n';
|
|
199
|
+
return { _tag: 'success', content: result };
|
|
200
|
+
}
|
|
201
|
+
export { applyPatch, computeHash, parsePatch };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type { JSONSchema } from '../shared/types/base.js';
|
|
2
|
+
export type { ChatTool } from '../shared/types/llm.js';
|
|
3
|
+
export type { ToolContext, ToolDef, ToolExecutor, ToolMode, ToolPermission, ToolResult, } from '../shared/types/tool.js';
|
|
4
|
+
export { bashTool } from './builtin/bash.js';
|
|
5
|
+
export { dapTools } from './builtin/dap.js';
|
|
6
|
+
export { editTool } from './builtin/edit.js';
|
|
7
|
+
export { globTool, globToRegex } from './builtin/glob.js';
|
|
8
|
+
export { grepTool } from './builtin/grep.js';
|
|
9
|
+
export { readTool } from './builtin/read.js';
|
|
10
|
+
export { createDefaultURLRegistry, createFileResolver, createSkillResolver, } from './builtin/resolvers.js';
|
|
11
|
+
export { taskTool } from './builtin/task.js';
|
|
12
|
+
export { writeTool } from './builtin/write.js';
|
|
13
|
+
export { yieldTool } from './builtin/yield.js';
|
|
14
|
+
export { executeTool } from './executor.js';
|
|
15
|
+
export { autoAllowChecker, createPermissionChecker } from './permission.js';
|
|
16
|
+
export { createToolRegistry, getTool, getToolSchemas, listTools, registerTool, registerToolFactory, } from './registry.js';
|
|
17
|
+
export { DEFAULT_TRUNCATE_OPTIONS, truncateOutput } from './truncate.js';
|
|
18
|
+
export type { BashInput, EditInput, GlobInput, GrepInput, GrepMatch, PermissionChecker, PermissionResult, ReadInput, ToolFactory, ToolFactoryContext, ToolRegistry, TruncateOptions, TruncateResult, ValidationResult, WriteInput, } from './types.js';
|
|
19
|
+
export { validateInput } from './validate.js';
|
|
20
|
+
export { formatForLLM, resolveProvider, runWebSearch } from './websearch/index.js';
|
|
21
|
+
export type { WebSearchProvider, WebSearchProviderId, WebSearchResponse, WebSearchSource, } from './websearch/types.js';
|
|
22
|
+
export { createWebSearchTool } from './websearch/websearch.js';
|
|
23
|
+
import type { Config } from '../shared/types/config.js';
|
|
24
|
+
/**
|
|
25
|
+
* Create a registry pre-loaded with all builtin tools:
|
|
26
|
+
* read, write, edit, glob, grep, bash, task, websearch, and the debug_* set.
|
|
27
|
+
*
|
|
28
|
+
* @param config 可选配置;websearch 工具按 config.websearch 构造。省略时用 DEFAULT_CONFIG。
|
|
29
|
+
*/
|
|
30
|
+
export declare function createDefaultRegistry(config?: Config): import("./types.js").ToolRegistry;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Tools package: tool registry, executor, validation, truncation, and builtin tools.
|
|
2
|
+
export { bashTool } from './builtin/bash.js';
|
|
3
|
+
export { dapTools } from './builtin/dap.js';
|
|
4
|
+
export { editTool } from './builtin/edit.js';
|
|
5
|
+
export { globTool, globToRegex } from './builtin/glob.js';
|
|
6
|
+
export { grepTool } from './builtin/grep.js';
|
|
7
|
+
export { readTool } from './builtin/read.js';
|
|
8
|
+
// ── Builtin tools ───────────────────────────────────────────
|
|
9
|
+
export { createDefaultURLRegistry, createFileResolver, createSkillResolver, } from './builtin/resolvers.js';
|
|
10
|
+
export { taskTool } from './builtin/task.js';
|
|
11
|
+
export { writeTool } from './builtin/write.js';
|
|
12
|
+
export { yieldTool } from './builtin/yield.js';
|
|
13
|
+
export { executeTool } from './executor.js';
|
|
14
|
+
export { autoAllowChecker, createPermissionChecker } from './permission.js';
|
|
15
|
+
// ── Framework ───────────────────────────────────────────────
|
|
16
|
+
export { createToolRegistry, getTool, getToolSchemas, listTools, registerTool, registerToolFactory, } from './registry.js';
|
|
17
|
+
export { DEFAULT_TRUNCATE_OPTIONS, truncateOutput } from './truncate.js';
|
|
18
|
+
export { validateInput } from './validate.js';
|
|
19
|
+
// ── Websearch ───────────────────────────────────────────────
|
|
20
|
+
export { formatForLLM, resolveProvider, runWebSearch } from './websearch/index.js';
|
|
21
|
+
export { createWebSearchTool } from './websearch/websearch.js';
|
|
22
|
+
// ── Default registry ────────────────────────────────────────
|
|
23
|
+
import { DEFAULT_CONFIG } from '../core/config.js';
|
|
24
|
+
import { bashTool } from './builtin/bash.js';
|
|
25
|
+
import { dapTools } from './builtin/dap.js';
|
|
26
|
+
import { editTool } from './builtin/edit.js';
|
|
27
|
+
import { globTool } from './builtin/glob.js';
|
|
28
|
+
import { grepTool } from './builtin/grep.js';
|
|
29
|
+
import { readTool } from './builtin/read.js';
|
|
30
|
+
import { taskTool } from './builtin/task.js';
|
|
31
|
+
import { writeTool } from './builtin/write.js';
|
|
32
|
+
import { yieldTool } from './builtin/yield.js';
|
|
33
|
+
import { createToolRegistry, registerTool } from './registry.js';
|
|
34
|
+
import { createWebSearchTool } from './websearch/websearch.js';
|
|
35
|
+
/**
|
|
36
|
+
* Create a registry pre-loaded with all builtin tools:
|
|
37
|
+
* read, write, edit, glob, grep, bash, task, websearch, and the debug_* set.
|
|
38
|
+
*
|
|
39
|
+
* @param config 可选配置;websearch 工具按 config.websearch 构造。省略时用 DEFAULT_CONFIG。
|
|
40
|
+
*/
|
|
41
|
+
export function createDefaultRegistry(config = DEFAULT_CONFIG) {
|
|
42
|
+
const reg = createToolRegistry();
|
|
43
|
+
registerTool(reg, readTool);
|
|
44
|
+
registerTool(reg, writeTool);
|
|
45
|
+
registerTool(reg, editTool);
|
|
46
|
+
registerTool(reg, globTool);
|
|
47
|
+
registerTool(reg, grepTool);
|
|
48
|
+
registerTool(reg, bashTool);
|
|
49
|
+
registerTool(reg, taskTool);
|
|
50
|
+
registerTool(reg, yieldTool);
|
|
51
|
+
registerTool(reg, createWebSearchTool(config.websearch));
|
|
52
|
+
for (const tool of dapTools)
|
|
53
|
+
registerTool(reg, tool);
|
|
54
|
+
return reg;
|
|
55
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { PermissionChecker } from './types.js';
|
|
2
|
+
/** Permission checker configuration. */
|
|
3
|
+
type PermissionConfig = {
|
|
4
|
+
/** Tool names that are always allowed, regardless of their declared permission. */
|
|
5
|
+
alwaysAllow?: string[];
|
|
6
|
+
/** Tool names that are always denied, regardless of their declared permission. */
|
|
7
|
+
alwaysDeny?: string[];
|
|
8
|
+
};
|
|
9
|
+
/** Default checker: allows auto, asks for ask, denies deny. No persistent state. */
|
|
10
|
+
export declare const autoAllowChecker: PermissionChecker;
|
|
11
|
+
/** Create a permission checker with configurable allow/deny lists. */
|
|
12
|
+
export declare function createPermissionChecker(config: PermissionConfig): PermissionChecker;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
function checkPermission(tool, _input) {
|
|
3
|
+
switch (tool.permission) {
|
|
4
|
+
case 'auto':
|
|
5
|
+
return { _tag: 'allow' };
|
|
6
|
+
case 'deny':
|
|
7
|
+
return { _tag: 'deny', reason: `Tool "${tool.name}" is disabled` };
|
|
8
|
+
case 'ask':
|
|
9
|
+
return {
|
|
10
|
+
_tag: 'ask',
|
|
11
|
+
reason: `Tool "${tool.name}" requires confirmation`,
|
|
12
|
+
toolCallId: randomUUID(),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/** Default checker: allows auto, asks for ask, denies deny. No persistent state. */
|
|
17
|
+
export const autoAllowChecker = {
|
|
18
|
+
check: async (_tool, _input, _ctx) => {
|
|
19
|
+
return checkPermission(_tool, _input);
|
|
20
|
+
},
|
|
21
|
+
confirm: (_toolCallId, _approved) => { },
|
|
22
|
+
};
|
|
23
|
+
/** Create a permission checker with configurable allow/deny lists. */
|
|
24
|
+
export function createPermissionChecker(config) {
|
|
25
|
+
const allowSet = new Set(config.alwaysAllow ?? []);
|
|
26
|
+
const denySet = new Set(config.alwaysDeny ?? []);
|
|
27
|
+
return {
|
|
28
|
+
check: async (tool, _input, _ctx) => {
|
|
29
|
+
if (denySet.has(tool.name)) {
|
|
30
|
+
return { _tag: 'deny', reason: `Tool "${tool.name}" is disabled by configuration` };
|
|
31
|
+
}
|
|
32
|
+
if (allowSet.has(tool.name)) {
|
|
33
|
+
return { _tag: 'allow' };
|
|
34
|
+
}
|
|
35
|
+
return checkPermission(tool, _input);
|
|
36
|
+
},
|
|
37
|
+
confirm: (_toolCallId, _approved) => { },
|
|
38
|
+
};
|
|
39
|
+
}
|