oricore 1.0.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 +199 -0
- package/dist/agent/agent/agentManager.d.ts +38 -0
- package/dist/agent/agent/builtin/common.d.ts +5 -0
- package/dist/agent/agent/builtin/explore.d.ts +5 -0
- package/dist/agent/agent/builtin/general-purpose.d.ts +5 -0
- package/dist/agent/agent/builtin/index.d.ts +5 -0
- package/dist/agent/agent/executor.d.ts +2 -0
- package/dist/agent/agent/types.d.ts +98 -0
- package/dist/api/engine.d.ts +213 -0
- package/dist/communication/index.d.ts +4 -0
- package/dist/communication/messageBus.d.ts +71 -0
- package/dist/core/at.d.ts +26 -0
- package/dist/core/backgroundTaskManager.d.ts +27 -0
- package/dist/core/compact.d.ts +9 -0
- package/dist/core/config.d.ts +103 -0
- package/dist/core/constants.d.ts +32 -0
- package/dist/core/context.d.ts +57 -0
- package/dist/core/globalData.d.ts +21 -0
- package/dist/core/history.d.ts +24 -0
- package/dist/core/ide.d.ts +103 -0
- package/dist/core/jsonl.d.ts +37 -0
- package/dist/core/llmsContext.d.ts +14 -0
- package/dist/core/loop.d.ts +82 -0
- package/dist/core/message.d.ts +132 -0
- package/dist/core/model.d.ts +79 -0
- package/dist/core/output-style/builtin/default.d.ts +2 -0
- package/dist/core/output-style/builtin/explanatory.d.ts +2 -0
- package/dist/core/output-style/builtin/index.d.ts +6 -0
- package/dist/core/output-style/builtin/miao.d.ts +2 -0
- package/dist/core/output-style/builtin/minimal.d.ts +2 -0
- package/dist/core/output-style/types.d.ts +6 -0
- package/dist/core/outputFormat.d.ts +29 -0
- package/dist/core/outputStyle.d.ts +43 -0
- package/dist/core/paths.d.ts +20 -0
- package/dist/core/planSystemPrompt.d.ts +5 -0
- package/dist/core/plugin.d.ts +138 -0
- package/dist/core/project.d.ts +64 -0
- package/dist/core/promptCache.d.ts +3 -0
- package/dist/core/query.d.ts +14 -0
- package/dist/core/rules.d.ts +8 -0
- package/dist/core/systemPrompt.d.ts +9 -0
- package/dist/core/thinking-config.d.ts +3 -0
- package/dist/core/usage.d.ts +14 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +144432 -0
- package/dist/mcp/mcp.d.ts +49 -0
- package/dist/modes/builtin.d.ts +34 -0
- package/dist/modes/index.d.ts +8 -0
- package/dist/modes/registry.d.ts +18 -0
- package/dist/modes/types.d.ts +51 -0
- package/dist/platform/index.d.ts +5 -0
- package/dist/platform/node.d.ts +28 -0
- package/dist/platform/types.d.ts +41 -0
- package/dist/session/session.d.ts +43 -0
- package/dist/skill/skill.d.ts +79 -0
- package/dist/tools/tool.d.ts +119 -0
- package/dist/tools/tools/askUserQuestion.d.ts +48 -0
- package/dist/tools/tools/bash.d.ts +43 -0
- package/dist/tools/tools/edit.d.ts +9 -0
- package/dist/tools/tools/fetch.d.ts +9 -0
- package/dist/tools/tools/glob.d.ts +7 -0
- package/dist/tools/tools/grep.d.ts +22 -0
- package/dist/tools/tools/ls.d.ts +6 -0
- package/dist/tools/tools/read.d.ts +9 -0
- package/dist/tools/tools/skill.d.ts +7 -0
- package/dist/tools/tools/task.d.ts +14 -0
- package/dist/tools/tools/todo.d.ts +37 -0
- package/dist/tools/tools/write.d.ts +7 -0
- package/dist/utils/apiKeyRotation.d.ts +2 -0
- package/dist/utils/applyEdit.d.ts +17 -0
- package/dist/utils/background-detection.d.ts +2 -0
- package/dist/utils/dotenv.d.ts +9 -0
- package/dist/utils/env.d.ts +6 -0
- package/dist/utils/error.d.ts +11 -0
- package/dist/utils/execFileNoThrow.d.ts +8 -0
- package/dist/utils/files.d.ts +10 -0
- package/dist/utils/git.d.ts +163 -0
- package/dist/utils/ide.d.ts +27 -0
- package/dist/utils/ignore.d.ts +6 -0
- package/dist/utils/isLocal.d.ts +1 -0
- package/dist/utils/language.d.ts +9 -0
- package/dist/utils/list.d.ts +20 -0
- package/dist/utils/mergeSystemMessagesMiddleware.d.ts +2 -0
- package/dist/utils/messageNormalization.d.ts +22 -0
- package/dist/utils/path.d.ts +34 -0
- package/dist/utils/prependSystemMessageMiddleware.d.ts +2 -0
- package/dist/utils/project.d.ts +1 -0
- package/dist/utils/proxy.d.ts +18 -0
- package/dist/utils/randomUUID.d.ts +5 -0
- package/dist/utils/renderSessionMarkdown.d.ts +10 -0
- package/dist/utils/ripgrep.d.ts +16 -0
- package/dist/utils/safeFrontMatter.d.ts +11 -0
- package/dist/utils/safeParseJson.d.ts +1 -0
- package/dist/utils/safeStringify.d.ts +1 -0
- package/dist/utils/sanitizeAIResponse.d.ts +30 -0
- package/dist/utils/setTerminalTitle.d.ts +1 -0
- package/dist/utils/shell-execution.d.ts +44 -0
- package/dist/utils/string.d.ts +8 -0
- package/dist/utils/symbols.d.ts +14 -0
- package/dist/utils/system-encoding.d.ts +40 -0
- package/dist/utils/tokenCounter.d.ts +8 -0
- package/dist/utils/username.d.ts +1 -0
- package/package.json +106 -0
- package/src/agent/agent/agentManager.test.ts +124 -0
- package/src/agent/agent/agentManager.ts +372 -0
- package/src/agent/agent/builtin/common.ts +20 -0
- package/src/agent/agent/builtin/explore.ts +53 -0
- package/src/agent/agent/builtin/general-purpose.ts +38 -0
- package/src/agent/agent/builtin/index.ts +13 -0
- package/src/agent/agent/executor.test.ts +339 -0
- package/src/agent/agent/executor.ts +224 -0
- package/src/agent/agent/types.ts +119 -0
- package/src/api/engine.ts +466 -0
- package/src/communication/index.ts +18 -0
- package/src/communication/messageBus.ts +393 -0
- package/src/core/at.ts +315 -0
- package/src/core/backgroundTaskManager.ts +129 -0
- package/src/core/compact.ts +95 -0
- package/src/core/config.ts +441 -0
- package/src/core/constants.ts +82 -0
- package/src/core/context.ts +214 -0
- package/src/core/globalData.ts +77 -0
- package/src/core/history.ts +323 -0
- package/src/core/ide.ts +325 -0
- package/src/core/jsonl.ts +100 -0
- package/src/core/llmsContext.ts +117 -0
- package/src/core/loop.ts +638 -0
- package/src/core/message.ts +304 -0
- package/src/core/model.ts +2198 -0
- package/src/core/output-style/builtin/default.ts +9 -0
- package/src/core/output-style/builtin/explanatory.ts +22 -0
- package/src/core/output-style/builtin/index.ts +19 -0
- package/src/core/output-style/builtin/miao.ts +22 -0
- package/src/core/output-style/builtin/minimal.ts +8 -0
- package/src/core/output-style/types.ts +6 -0
- package/src/core/outputFormat.ts +93 -0
- package/src/core/outputStyle.ts +255 -0
- package/src/core/paths.ts +161 -0
- package/src/core/planSystemPrompt.ts +46 -0
- package/src/core/plugin.ts +299 -0
- package/src/core/project.ts +492 -0
- package/src/core/promptCache.ts +32 -0
- package/src/core/query.ts +46 -0
- package/src/core/rules.ts +56 -0
- package/src/core/systemPrompt.ts +176 -0
- package/src/core/thinking-config.ts +98 -0
- package/src/core/usage.ts +68 -0
- package/src/index.ts +39 -0
- package/src/mcp/mcp.ts +637 -0
- package/src/modes/builtin.ts +305 -0
- package/src/modes/index.ts +22 -0
- package/src/modes/registry.ts +39 -0
- package/src/modes/types.ts +56 -0
- package/src/platform/index.ts +6 -0
- package/src/platform/node.ts +108 -0
- package/src/platform/types.ts +54 -0
- package/src/plugins/index.ts +15 -0
- package/src/session/session.ts +187 -0
- package/src/skill/skill.ts +702 -0
- package/src/tools/tool.ts +378 -0
- package/src/tools/tools/askUserQuestion.ts +134 -0
- package/src/tools/tools/bash.test.ts +425 -0
- package/src/tools/tools/bash.ts +999 -0
- package/src/tools/tools/edit.ts +86 -0
- package/src/tools/tools/fetch.ts +129 -0
- package/src/tools/tools/glob.ts +69 -0
- package/src/tools/tools/grep.test.ts +194 -0
- package/src/tools/tools/grep.ts +358 -0
- package/src/tools/tools/ls.ts +51 -0
- package/src/tools/tools/read.test.ts +169 -0
- package/src/tools/tools/read.ts +284 -0
- package/src/tools/tools/skill.ts +73 -0
- package/src/tools/tools/task.test.ts +262 -0
- package/src/tools/tools/task.ts +284 -0
- package/src/tools/tools/todo.ts +269 -0
- package/src/tools/tools/write.ts +71 -0
- package/src/types.d.ts +18 -0
- package/src/utils/apiKeyRotation.test.ts +70 -0
- package/src/utils/apiKeyRotation.ts +24 -0
- package/src/utils/applyEdit.test.ts +388 -0
- package/src/utils/applyEdit.ts +547 -0
- package/src/utils/background-detection.test.ts +61 -0
- package/src/utils/background-detection.ts +58 -0
- package/src/utils/dotenv.ts +26 -0
- package/src/utils/env.ts +90 -0
- package/src/utils/error.ts +38 -0
- package/src/utils/execFileNoThrow.ts +49 -0
- package/src/utils/files.ts +93 -0
- package/src/utils/git.ts +1152 -0
- package/src/utils/ide.ts +279 -0
- package/src/utils/ignore.ts +275 -0
- package/src/utils/isLocal.ts +6 -0
- package/src/utils/language.ts +33 -0
- package/src/utils/list.ts +200 -0
- package/src/utils/mergeSystemMessagesMiddleware.ts +32 -0
- package/src/utils/messageNormalization.test.ts +401 -0
- package/src/utils/messageNormalization.ts +168 -0
- package/src/utils/path.ts +98 -0
- package/src/utils/prependSystemMessageMiddleware.ts +16 -0
- package/src/utils/project.ts +32 -0
- package/src/utils/proxy.ts +102 -0
- package/src/utils/randomUUID.ts +11 -0
- package/src/utils/renderSessionMarkdown.ts +175 -0
- package/src/utils/ripgrep.ts +189 -0
- package/src/utils/safeFrontMatter.test.ts +118 -0
- package/src/utils/safeFrontMatter.ts +68 -0
- package/src/utils/safeParseJson.ts +7 -0
- package/src/utils/safeStringify.ts +10 -0
- package/src/utils/sanitizeAIResponse.test.ts +135 -0
- package/src/utils/sanitizeAIResponse.ts +55 -0
- package/src/utils/setTerminalTitle.ts +7 -0
- package/src/utils/shell-execution.test.ts +237 -0
- package/src/utils/shell-execution.ts +279 -0
- package/src/utils/string.ts +13 -0
- package/src/utils/symbols.ts +18 -0
- package/src/utils/system-encoding.test.ts +164 -0
- package/src/utils/system-encoding.ts +296 -0
- package/src/utils/tokenCounter.test.ts +38 -0
- package/src/utils/tokenCounter.ts +19 -0
- package/src/utils/username.ts +21 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import type { LanguageModelV2FunctionTool } from '@ai-sdk/provider';
|
|
2
|
+
import path from 'pathe';
|
|
3
|
+
import * as z from 'zod';
|
|
4
|
+
import type { Context } from '../core/context';
|
|
5
|
+
import type { ImagePart, TextPart } from '../core/message';
|
|
6
|
+
import { resolveModelWithContext } from '../core/model';
|
|
7
|
+
import { createAskUserQuestionTool } from './tools/askUserQuestion';
|
|
8
|
+
import {
|
|
9
|
+
createBashOutputTool,
|
|
10
|
+
createBashTool,
|
|
11
|
+
createKillBashTool,
|
|
12
|
+
} from './tools/bash';
|
|
13
|
+
import { createEditTool } from './tools/edit';
|
|
14
|
+
import { createFetchTool } from './tools/fetch';
|
|
15
|
+
import { createGlobTool } from './tools/glob';
|
|
16
|
+
import { createGrepTool } from './tools/grep';
|
|
17
|
+
import { createLSTool } from './tools/ls';
|
|
18
|
+
import { createReadTool } from './tools/read';
|
|
19
|
+
import { createSkillTool } from './tools/skill';
|
|
20
|
+
import { createTaskTool } from './tools/task';
|
|
21
|
+
import { createTodoTool, type TodoItem } from './tools/todo';
|
|
22
|
+
import { createWriteTool } from './tools/write';
|
|
23
|
+
|
|
24
|
+
type ResolveToolsOpts = {
|
|
25
|
+
context: Context;
|
|
26
|
+
sessionId: string;
|
|
27
|
+
write?: boolean;
|
|
28
|
+
todo?: boolean;
|
|
29
|
+
askUserQuestion?: boolean;
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
task?: boolean;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export async function resolveTools(opts: ResolveToolsOpts) {
|
|
35
|
+
const { cwd, productName, paths } = opts.context;
|
|
36
|
+
const sessionId = opts.sessionId;
|
|
37
|
+
const model = (
|
|
38
|
+
await resolveModelWithContext(
|
|
39
|
+
opts.context.config.smallModel || opts.context.config.model,
|
|
40
|
+
opts.context,
|
|
41
|
+
)
|
|
42
|
+
).model!;
|
|
43
|
+
const hasSkills =
|
|
44
|
+
opts.context.skillManager &&
|
|
45
|
+
opts.context.skillManager.getSkills().length > 0;
|
|
46
|
+
const readonlyTools = [
|
|
47
|
+
createReadTool({ cwd, productName }),
|
|
48
|
+
createLSTool({ cwd }),
|
|
49
|
+
createGlobTool({ cwd }),
|
|
50
|
+
createGrepTool({ cwd }),
|
|
51
|
+
createFetchTool({ model, fetch: opts.context.fetch }),
|
|
52
|
+
...(hasSkills
|
|
53
|
+
? [createSkillTool({ skillManager: opts.context.skillManager! })]
|
|
54
|
+
: []),
|
|
55
|
+
];
|
|
56
|
+
const askUserQuestionTools = opts.askUserQuestion
|
|
57
|
+
? [createAskUserQuestionTool()]
|
|
58
|
+
: [];
|
|
59
|
+
const writeTools = opts.write
|
|
60
|
+
? [
|
|
61
|
+
createWriteTool({ cwd }),
|
|
62
|
+
createEditTool({ cwd }),
|
|
63
|
+
createBashTool({
|
|
64
|
+
cwd,
|
|
65
|
+
backgroundTaskManager: opts.context.backgroundTaskManager,
|
|
66
|
+
messageBus: opts.context.messageBus,
|
|
67
|
+
}),
|
|
68
|
+
]
|
|
69
|
+
: [];
|
|
70
|
+
const todoTools = (() => {
|
|
71
|
+
if (!opts.todo) return [];
|
|
72
|
+
const { todoWriteTool } = createTodoTool({
|
|
73
|
+
filePath: path.join(paths.globalConfigDir, 'todos', `${sessionId}.json`),
|
|
74
|
+
});
|
|
75
|
+
return [todoWriteTool];
|
|
76
|
+
})();
|
|
77
|
+
// Bash background tools
|
|
78
|
+
const backgroundTools: any[] = opts.write
|
|
79
|
+
? [
|
|
80
|
+
createBashOutputTool({
|
|
81
|
+
backgroundTaskManager: opts.context.backgroundTaskManager,
|
|
82
|
+
}),
|
|
83
|
+
createKillBashTool({
|
|
84
|
+
backgroundTaskManager: opts.context.backgroundTaskManager,
|
|
85
|
+
}),
|
|
86
|
+
]
|
|
87
|
+
: [];
|
|
88
|
+
|
|
89
|
+
const mcpTools = await getMcpTools(opts.context);
|
|
90
|
+
|
|
91
|
+
const allTools = [
|
|
92
|
+
...readonlyTools,
|
|
93
|
+
...askUserQuestionTools,
|
|
94
|
+
...writeTools,
|
|
95
|
+
...todoTools,
|
|
96
|
+
...backgroundTools,
|
|
97
|
+
...mcpTools,
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const toolsConfig = opts.context.config.tools;
|
|
101
|
+
const availableTools = (() => {
|
|
102
|
+
if (!toolsConfig || Object.keys(toolsConfig).length === 0) {
|
|
103
|
+
return allTools;
|
|
104
|
+
}
|
|
105
|
+
return allTools.filter((tool) => {
|
|
106
|
+
// Check if the tool is disabled (only explicitly set to false will disable)
|
|
107
|
+
const isDisabled = toolsConfig[tool.name] === false;
|
|
108
|
+
return !isDisabled;
|
|
109
|
+
});
|
|
110
|
+
})();
|
|
111
|
+
|
|
112
|
+
const taskTools = (() => {
|
|
113
|
+
// Task tool is only available in quiet mode
|
|
114
|
+
if (!opts.task) return [];
|
|
115
|
+
if (!opts.context.agentManager) return [];
|
|
116
|
+
const tool = createTaskTool({
|
|
117
|
+
context: opts.context,
|
|
118
|
+
tools: availableTools,
|
|
119
|
+
sessionId: opts.sessionId,
|
|
120
|
+
signal: opts.signal,
|
|
121
|
+
});
|
|
122
|
+
if (toolsConfig && toolsConfig[tool.name] === false) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
return [tool];
|
|
126
|
+
})();
|
|
127
|
+
|
|
128
|
+
return [...availableTools, ...taskTools];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function getMcpTools(context: Context): Promise<Tool[]> {
|
|
132
|
+
try {
|
|
133
|
+
const mcpManager = context.mcpManager;
|
|
134
|
+
await mcpManager.initAsync();
|
|
135
|
+
return await mcpManager.getAllTools();
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.warn('Failed to load MCP tools:', error);
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export class Tools {
|
|
143
|
+
tools: Record<string, Tool>;
|
|
144
|
+
constructor(tools: Tool[]) {
|
|
145
|
+
this.tools = tools.reduce(
|
|
146
|
+
(acc, tool) => {
|
|
147
|
+
acc[tool.name] = tool;
|
|
148
|
+
return acc;
|
|
149
|
+
},
|
|
150
|
+
{} as Record<string, Tool>,
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
get(toolName: string) {
|
|
155
|
+
return this.tools[toolName];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
length() {
|
|
159
|
+
return Object.keys(this.tools).length;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async invoke(
|
|
163
|
+
toolName: string,
|
|
164
|
+
args: string,
|
|
165
|
+
toolCallId: string,
|
|
166
|
+
): Promise<ToolResult> {
|
|
167
|
+
const tool = this.tools[toolName];
|
|
168
|
+
if (!tool) {
|
|
169
|
+
return {
|
|
170
|
+
llmContent: `Tool ${toolName} not found`,
|
|
171
|
+
isError: true,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
// // @ts-expect-error
|
|
175
|
+
// const result = validateToolParams(tool.parameters, args);
|
|
176
|
+
// if (!result.success) {
|
|
177
|
+
// return {
|
|
178
|
+
// llmContent: `Invalid tool parameters: ${result.error}`,
|
|
179
|
+
// isError: true,
|
|
180
|
+
// };
|
|
181
|
+
// }
|
|
182
|
+
let argsObj: any;
|
|
183
|
+
try {
|
|
184
|
+
argsObj = JSON.parse(args);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
return {
|
|
187
|
+
llmContent: `Tool parameters parse failed: ${error}`,
|
|
188
|
+
isError: true,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
return await tool.execute(argsObj, toolCallId);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
toLanguageV2Tools(): LanguageModelV2FunctionTool[] {
|
|
195
|
+
return Object.entries(this.tools).map(([key, tool]) => {
|
|
196
|
+
// parameters of mcp tools is not zod object
|
|
197
|
+
const isMCP = key.startsWith('mcp__');
|
|
198
|
+
const schema = isMCP ? tool.parameters : z.toJSONSchema(tool.parameters);
|
|
199
|
+
// some providers have a limit on the description length, so we need to truncate it
|
|
200
|
+
// e.g. megallm.io has a limit of 1024 characters
|
|
201
|
+
const limit = process.env.TOOL_DESCRIPTION_LIMIT
|
|
202
|
+
? Math.floor(parseInt(process.env.TOOL_DESCRIPTION_LIMIT, 10))
|
|
203
|
+
: 0;
|
|
204
|
+
const desc =
|
|
205
|
+
limit > 0 && tool.description.length > limit
|
|
206
|
+
? `${tool.description.slice(0, limit - 3)}...`
|
|
207
|
+
: tool.description;
|
|
208
|
+
return {
|
|
209
|
+
type: 'function',
|
|
210
|
+
name: key,
|
|
211
|
+
description: desc,
|
|
212
|
+
inputSchema: schema as LanguageModelV2FunctionTool['inputSchema'],
|
|
213
|
+
providerOptions: {},
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// function validateToolParams(schema: z.ZodObject<any>, params: string) {
|
|
220
|
+
// try {
|
|
221
|
+
// if (isZodObject(schema)) {
|
|
222
|
+
// const parsedParams = JSON.parse(params);
|
|
223
|
+
// const result = schema.safeParse(parsedParams);
|
|
224
|
+
// if (!result.success) {
|
|
225
|
+
// return {
|
|
226
|
+
// success: false,
|
|
227
|
+
// error: `Parameter validation failed: ${result.error.message}`,
|
|
228
|
+
// };
|
|
229
|
+
// }
|
|
230
|
+
// return {
|
|
231
|
+
// success: true,
|
|
232
|
+
// message: 'Tool parameters validated successfully',
|
|
233
|
+
// };
|
|
234
|
+
// }
|
|
235
|
+
// return {
|
|
236
|
+
// success: true,
|
|
237
|
+
// message: 'Tool parameters validated successfully',
|
|
238
|
+
// };
|
|
239
|
+
// } catch (error) {
|
|
240
|
+
// return {
|
|
241
|
+
// success: false,
|
|
242
|
+
// error: error,
|
|
243
|
+
// };
|
|
244
|
+
// }
|
|
245
|
+
// }
|
|
246
|
+
|
|
247
|
+
export type ToolUse = {
|
|
248
|
+
name: string;
|
|
249
|
+
params: Record<string, any>;
|
|
250
|
+
callId: string;
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
export type ToolUseResult = {
|
|
254
|
+
toolUse: ToolUse;
|
|
255
|
+
result: any;
|
|
256
|
+
approved: boolean;
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
export interface Tool<TSchema extends z.ZodTypeAny = z.ZodTypeAny> {
|
|
260
|
+
name: string;
|
|
261
|
+
description: string;
|
|
262
|
+
getDescription?: ({
|
|
263
|
+
params,
|
|
264
|
+
cwd,
|
|
265
|
+
}: {
|
|
266
|
+
params: z.output<TSchema>;
|
|
267
|
+
cwd: string;
|
|
268
|
+
}) => string;
|
|
269
|
+
displayName?: string;
|
|
270
|
+
execute: (
|
|
271
|
+
params: z.output<TSchema>,
|
|
272
|
+
toolCallId?: string,
|
|
273
|
+
) => Promise<ToolResult> | ToolResult;
|
|
274
|
+
approval?: ToolApprovalInfo;
|
|
275
|
+
parameters: TSchema;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
type ApprovalContext = {
|
|
279
|
+
toolName: string;
|
|
280
|
+
params: Record<string, any>;
|
|
281
|
+
approvalMode: string;
|
|
282
|
+
context: any;
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
export type ApprovalCategory = 'read' | 'write' | 'command' | 'network' | 'ask';
|
|
286
|
+
|
|
287
|
+
type ToolApprovalInfo = {
|
|
288
|
+
needsApproval?: (context: ApprovalContext) => Promise<boolean> | boolean;
|
|
289
|
+
category?: ApprovalCategory;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
type TodoWriteReturnDisplay = {
|
|
293
|
+
type: 'todo_write';
|
|
294
|
+
oldTodos: TodoItem[];
|
|
295
|
+
newTodos: TodoItem[];
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
type DiffViewerReturnDisplay = {
|
|
299
|
+
type: 'diff_viewer';
|
|
300
|
+
originalContent: string | { inputKey: string };
|
|
301
|
+
newContent: string | { inputKey: string };
|
|
302
|
+
filePath: string;
|
|
303
|
+
[key: string]: any;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
type AgentResultReturnDisplay = {
|
|
307
|
+
type: 'agent_result';
|
|
308
|
+
agentId: string;
|
|
309
|
+
agentType: string;
|
|
310
|
+
description: string;
|
|
311
|
+
prompt: string;
|
|
312
|
+
content: string;
|
|
313
|
+
stats: {
|
|
314
|
+
toolCalls: number;
|
|
315
|
+
duration: number;
|
|
316
|
+
tokens: {
|
|
317
|
+
input: number;
|
|
318
|
+
output: number;
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
status: 'completed' | 'failed';
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
export type ReturnDisplay =
|
|
325
|
+
| string
|
|
326
|
+
| DiffViewerReturnDisplay
|
|
327
|
+
| TodoWriteReturnDisplay
|
|
328
|
+
| AgentResultReturnDisplay;
|
|
329
|
+
|
|
330
|
+
export type ToolResult = {
|
|
331
|
+
llmContent: string | (TextPart | ImagePart)[];
|
|
332
|
+
returnDisplay?: ReturnDisplay;
|
|
333
|
+
isError?: boolean;
|
|
334
|
+
metadata?: {
|
|
335
|
+
agentId?: string;
|
|
336
|
+
agentType?: string;
|
|
337
|
+
[key: string]: any;
|
|
338
|
+
};
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
export function createTool<TSchema extends z.ZodTypeAny>(config: {
|
|
342
|
+
name: string;
|
|
343
|
+
displayName?: string;
|
|
344
|
+
description: string;
|
|
345
|
+
parameters: TSchema;
|
|
346
|
+
execute: (
|
|
347
|
+
params: z.output<TSchema>,
|
|
348
|
+
toolCallId?: string,
|
|
349
|
+
) => Promise<ToolResult> | ToolResult;
|
|
350
|
+
approval?: ToolApprovalInfo;
|
|
351
|
+
getDescription?: ({
|
|
352
|
+
params,
|
|
353
|
+
cwd,
|
|
354
|
+
}: {
|
|
355
|
+
params: z.output<TSchema>;
|
|
356
|
+
cwd: string;
|
|
357
|
+
}) => string;
|
|
358
|
+
}): Tool<TSchema> {
|
|
359
|
+
return {
|
|
360
|
+
name: config.name,
|
|
361
|
+
displayName: config.displayName,
|
|
362
|
+
description: config.description,
|
|
363
|
+
getDescription: config.getDescription,
|
|
364
|
+
parameters: config.parameters,
|
|
365
|
+
execute: config.execute,
|
|
366
|
+
approval: config.approval,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export type ToolParams = Record<string, unknown>;
|
|
371
|
+
|
|
372
|
+
export type ToolApprovalResult =
|
|
373
|
+
| boolean
|
|
374
|
+
| {
|
|
375
|
+
approved: boolean;
|
|
376
|
+
params?: ToolParams;
|
|
377
|
+
denyReason?: string;
|
|
378
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TOOL_NAMES } from '../../core/constants';
|
|
3
|
+
import { createTool } from '../tool';
|
|
4
|
+
|
|
5
|
+
const MAX_HEADER_LENGTH = 12;
|
|
6
|
+
|
|
7
|
+
const QuestionOptionSchema = z.object({
|
|
8
|
+
label: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe(
|
|
11
|
+
'The display text for this option that the user will see and select. Should be concise (1-5 words) and clearly describe the choice.',
|
|
12
|
+
),
|
|
13
|
+
description: z
|
|
14
|
+
.string()
|
|
15
|
+
.describe(
|
|
16
|
+
'Explanation of what this option means or what will happen if chosen. Useful for providing context about trade-offs or implications.',
|
|
17
|
+
),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const QuestionSchema = z.object({
|
|
21
|
+
question: z
|
|
22
|
+
.string()
|
|
23
|
+
.describe(
|
|
24
|
+
'The complete question to ask the user. Should be clear, specific, and end with a question mark. Example: "Which library should we use for date formatting?" If multiSelect is true, phrase it accordingly, e.g. "Which features do you want to enable?',
|
|
25
|
+
),
|
|
26
|
+
header: z
|
|
27
|
+
.string()
|
|
28
|
+
.describe(
|
|
29
|
+
`Very short label displayed as a chip/tag (max ${MAX_HEADER_LENGTH} chars). Examples: "Auth method", "Library", "Approach".`,
|
|
30
|
+
),
|
|
31
|
+
options: z
|
|
32
|
+
.array(QuestionOptionSchema)
|
|
33
|
+
.min(2)
|
|
34
|
+
.max(4)
|
|
35
|
+
.describe(
|
|
36
|
+
`The available choices for this question. Must have 2-4 options. Each option should be a distinct, mutually exclusive choice (unless multiSelect is enabled). There should be no 'Other' option, that will be provided automatically.`,
|
|
37
|
+
),
|
|
38
|
+
multiSelect: z
|
|
39
|
+
.boolean()
|
|
40
|
+
.optional()
|
|
41
|
+
.default(false)
|
|
42
|
+
.describe(
|
|
43
|
+
'Set to true to allow the user to select multiple options instead of just one. Use when choices are not mutually exclusive.',
|
|
44
|
+
),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const AskUserQuestionInputSchema = z
|
|
48
|
+
.object({
|
|
49
|
+
questions: z
|
|
50
|
+
.array(QuestionSchema)
|
|
51
|
+
.min(1)
|
|
52
|
+
.max(4)
|
|
53
|
+
.describe('Questions to ask the user (1-4 questions)'),
|
|
54
|
+
answers: z
|
|
55
|
+
.array(z.object({ question: z.string(), answer: z.string() }))
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('User answers collected by the permission component'),
|
|
58
|
+
})
|
|
59
|
+
.refine(
|
|
60
|
+
(data) => {
|
|
61
|
+
const questionTexts = data.questions.map((q) => q.question);
|
|
62
|
+
return questionTexts.length === new Set(questionTexts).size;
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
message:
|
|
66
|
+
'Question texts must be unique, option labels must be unique within each question',
|
|
67
|
+
},
|
|
68
|
+
)
|
|
69
|
+
.refine(
|
|
70
|
+
(data) => {
|
|
71
|
+
for (const question of data.questions) {
|
|
72
|
+
const labels = question.options.map((o) => o.label);
|
|
73
|
+
if (labels.length !== new Set(labels).size) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return true;
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
message: 'Option labels must be unique within each question',
|
|
81
|
+
},
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
export type QuestionOption = z.infer<typeof QuestionOptionSchema>;
|
|
85
|
+
export type Question = z.infer<typeof QuestionSchema>;
|
|
86
|
+
export type AskUserQuestionInput = z.infer<typeof AskUserQuestionInputSchema>;
|
|
87
|
+
|
|
88
|
+
const TOOL_DESCRIPTION = `
|
|
89
|
+
Use this tool when you need to ask the user questions during execution. This allows you to:
|
|
90
|
+
1. Gather user preferences or requirements
|
|
91
|
+
2. Clarify ambiguous instructions
|
|
92
|
+
3. Get decisions on implementation choices as you work
|
|
93
|
+
4. Offer choices to the user about what direction to take.
|
|
94
|
+
|
|
95
|
+
Usage notes:
|
|
96
|
+
- Users will always be able to select "Other" to provide custom text input
|
|
97
|
+
- Use multiSelect: true to allow multiple answers to be selected for a question
|
|
98
|
+
- If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end
|
|
99
|
+
of the label
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
export function createAskUserQuestionTool() {
|
|
103
|
+
return createTool({
|
|
104
|
+
name: TOOL_NAMES.ASK_USER_QUESTION,
|
|
105
|
+
description: TOOL_DESCRIPTION,
|
|
106
|
+
parameters: AskUserQuestionInputSchema,
|
|
107
|
+
async execute({ questions, answers }) {
|
|
108
|
+
if (!answers || answers.length === 0) {
|
|
109
|
+
return {
|
|
110
|
+
isError: true,
|
|
111
|
+
llmContent: 'No answers provided by user',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const answerSummary = answers
|
|
116
|
+
.map(({ question, answer }) => `"${question}" = "${answer}"`)
|
|
117
|
+
.join(', ');
|
|
118
|
+
|
|
119
|
+
const displayText = answers
|
|
120
|
+
.map(({ question, answer }) => `· ${question} → ${answer}`)
|
|
121
|
+
.join('\n');
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
llmContent: `User has answered your questions: ${answerSummary}. You can now continue with the user's answers in mind.`,
|
|
125
|
+
returnDisplay: `User has answered your questions:\n${displayText}`,
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
approval: {
|
|
129
|
+
// Always require user input, even in yolo mode
|
|
130
|
+
category: 'ask',
|
|
131
|
+
needsApproval: () => true,
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
}
|