bashkit 0.1.0 → 0.1.1
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/AGENTS.md +19 -9
- package/README.md +46 -17
- package/dist/cli/init.js +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +312 -120
- package/dist/tools/ask-user.d.ts +23 -0
- package/dist/tools/enter-plan-mode.d.ts +22 -0
- package/dist/tools/index.d.ts +42 -10
- package/dist/tools/lsp.d.ts +94 -0
- package/dist/tools/skill.d.ts +27 -0
- package/dist/types.d.ts +17 -0
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -24,7 +24,7 @@ Runs commands directly on the local machine. Use for development/testing only.
|
|
|
24
24
|
import { createAgentTools, LocalSandbox } from "bashkit";
|
|
25
25
|
|
|
26
26
|
const sandbox = new LocalSandbox("/tmp/workspace");
|
|
27
|
-
const tools = createAgentTools(sandbox);
|
|
27
|
+
const { tools } = createAgentTools(sandbox);
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
### VercelSandbox (Production)
|
|
@@ -38,7 +38,7 @@ const sandbox = new VercelSandbox({
|
|
|
38
38
|
runtime: "node22",
|
|
39
39
|
resources: { vcpus: 2 },
|
|
40
40
|
});
|
|
41
|
-
const tools = createAgentTools(sandbox);
|
|
41
|
+
const { tools } = createAgentTools(sandbox);
|
|
42
42
|
|
|
43
43
|
// Don't forget to cleanup
|
|
44
44
|
await sandbox.destroy();
|
|
@@ -46,7 +46,7 @@ await sandbox.destroy();
|
|
|
46
46
|
|
|
47
47
|
## Available Tools
|
|
48
48
|
|
|
49
|
-
###
|
|
49
|
+
### Default Tools (always included)
|
|
50
50
|
|
|
51
51
|
| Tool | Purpose | Key Inputs |
|
|
52
52
|
|------|---------|------------|
|
|
@@ -57,13 +57,23 @@ await sandbox.destroy();
|
|
|
57
57
|
| `Glob` | Find files by pattern | `pattern`, `path?` |
|
|
58
58
|
| `Grep` | Search file contents | `pattern`, `path?`, `output_mode?`, `-i?`, `-C?` |
|
|
59
59
|
|
|
60
|
+
### Optional Tools (via config)
|
|
61
|
+
|
|
62
|
+
| Tool | Purpose | Config Key |
|
|
63
|
+
|------|---------|------------|
|
|
64
|
+
| `AskUser` | Ask user clarifying questions | `askUser: { onQuestion? }` |
|
|
65
|
+
| `EnterPlanMode` | Enter planning/exploration mode | `planMode: true` |
|
|
66
|
+
| `ExitPlanMode` | Exit planning mode with a plan | `planMode: true` |
|
|
67
|
+
| `Skill` | Execute skills | `skill: { skills }` |
|
|
68
|
+
| `WebSearch` | Search the web | `webSearch: { apiKey }` |
|
|
69
|
+
| `WebFetch` | Fetch URL and process with AI | `webFetch: { apiKey, model }` |
|
|
70
|
+
|
|
60
71
|
### Workflow Tools (created separately)
|
|
61
72
|
|
|
62
73
|
| Tool | Purpose | Factory |
|
|
63
74
|
|------|---------|---------|
|
|
64
75
|
| `Task` | Spawn sub-agents | `createTaskTool({ model, tools, subagentTypes? })` |
|
|
65
76
|
| `TodoWrite` | Track task progress | `createTodoWriteTool(state, config?, onUpdate?)` |
|
|
66
|
-
| `ExitPlanMode` | Exit planning mode | `createExitPlanModeTool(config?, onPlanSubmit?)` |
|
|
67
77
|
|
|
68
78
|
### Web Tools (require `parallel-web` peer dependency)
|
|
69
79
|
|
|
@@ -84,7 +94,7 @@ import {
|
|
|
84
94
|
} from "bashkit";
|
|
85
95
|
|
|
86
96
|
const sandbox = new LocalSandbox("/tmp/workspace");
|
|
87
|
-
const tools = createAgentTools(sandbox);
|
|
97
|
+
const { tools } = createAgentTools(sandbox);
|
|
88
98
|
|
|
89
99
|
// Wrap model with prompt caching (recommended)
|
|
90
100
|
const model = wrapLanguageModel({
|
|
@@ -273,7 +283,7 @@ import { anthropic } from "@ai-sdk/anthropic";
|
|
|
273
283
|
|
|
274
284
|
const skills = await discoverSkills();
|
|
275
285
|
const sandbox = new LocalSandbox("/tmp/workspace");
|
|
276
|
-
const tools = createAgentTools(sandbox);
|
|
286
|
+
const { tools } = createAgentTools(sandbox);
|
|
277
287
|
|
|
278
288
|
const result = await generateText({
|
|
279
289
|
model: anthropic("claude-sonnet-4-20250514"),
|
|
@@ -363,7 +373,7 @@ const systemPrompt = `Save notes to: ${config.workspace.notes}
|
|
|
363
373
|
${skillsToXml(skills)}
|
|
364
374
|
`;
|
|
365
375
|
|
|
366
|
-
const tools = createAgentTools(sandbox);
|
|
376
|
+
const { tools } = createAgentTools(sandbox);
|
|
367
377
|
```
|
|
368
378
|
|
|
369
379
|
## Common Patterns
|
|
@@ -386,7 +396,7 @@ import {
|
|
|
386
396
|
const sandbox = new LocalSandbox("/tmp/workspace");
|
|
387
397
|
|
|
388
398
|
// 2. Create sandbox tools
|
|
389
|
-
const sandboxTools = createAgentTools(sandbox);
|
|
399
|
+
const { tools: sandboxTools } = createAgentTools(sandbox);
|
|
390
400
|
|
|
391
401
|
// 3. Create model with caching
|
|
392
402
|
const model = wrapLanguageModel({
|
|
@@ -424,7 +434,7 @@ await sandbox.destroy();
|
|
|
424
434
|
Restrict tools with configuration:
|
|
425
435
|
|
|
426
436
|
```typescript
|
|
427
|
-
const tools = createAgentTools(sandbox, {
|
|
437
|
+
const { tools } = createAgentTools(sandbox, {
|
|
428
438
|
tools: {
|
|
429
439
|
Bash: {
|
|
430
440
|
enabled: true,
|
package/README.md
CHANGED
|
@@ -43,7 +43,7 @@ import { generateText, stepCountIs } from 'ai';
|
|
|
43
43
|
const sandbox = createLocalSandbox({ cwd: '/tmp/workspace' });
|
|
44
44
|
|
|
45
45
|
// Create tools bound to the sandbox
|
|
46
|
-
const tools = createAgentTools(sandbox);
|
|
46
|
+
const { tools } = createAgentTools(sandbox);
|
|
47
47
|
|
|
48
48
|
// Use with Vercel AI SDK
|
|
49
49
|
const result = await generateText({
|
|
@@ -74,7 +74,7 @@ const sandbox = createVercelSandbox({
|
|
|
74
74
|
resources: { vcpus: 2 },
|
|
75
75
|
});
|
|
76
76
|
|
|
77
|
-
const tools = createAgentTools(sandbox);
|
|
77
|
+
const { tools } = createAgentTools(sandbox);
|
|
78
78
|
|
|
79
79
|
const result = streamText({
|
|
80
80
|
model: anthropic('claude-sonnet-4-5'),
|
|
@@ -89,7 +89,7 @@ await sandbox.destroy();
|
|
|
89
89
|
|
|
90
90
|
## Available Tools
|
|
91
91
|
|
|
92
|
-
###
|
|
92
|
+
### Default Tools (always included)
|
|
93
93
|
|
|
94
94
|
| Tool | Purpose | Key Inputs |
|
|
95
95
|
|------|---------|------------|
|
|
@@ -100,13 +100,23 @@ await sandbox.destroy();
|
|
|
100
100
|
| `Glob` | Find files by pattern | `pattern`, `path?` |
|
|
101
101
|
| `Grep` | Search file contents | `pattern`, `path?`, `output_mode?`, `-i?`, `-C?` |
|
|
102
102
|
|
|
103
|
+
### Optional Tools (via config)
|
|
104
|
+
|
|
105
|
+
| Tool | Purpose | Config Key |
|
|
106
|
+
|------|---------|------------|
|
|
107
|
+
| `AskUser` | Ask user clarifying questions | `askUser: { onQuestion? }` |
|
|
108
|
+
| `EnterPlanMode` | Enter planning/exploration mode | `planMode: true` |
|
|
109
|
+
| `ExitPlanMode` | Exit planning mode with a plan | `planMode: true` |
|
|
110
|
+
| `Skill` | Execute skills | `skill: { skills }` |
|
|
111
|
+
| `WebSearch` | Search the web | `webSearch: { apiKey }` |
|
|
112
|
+
| `WebFetch` | Fetch URL and process with AI | `webFetch: { apiKey, model }` |
|
|
113
|
+
|
|
103
114
|
### Workflow Tools (created separately)
|
|
104
115
|
|
|
105
116
|
| Tool | Purpose | Factory |
|
|
106
117
|
|------|---------|---------|
|
|
107
118
|
| `Task` | Spawn sub-agents | `createTaskTool({ model, tools, subagentTypes? })` |
|
|
108
119
|
| `TodoWrite` | Track task progress | `createTodoWriteTool(state, config?, onUpdate?)` |
|
|
109
|
-
| `ExitPlanMode` | Exit planning mode | `createExitPlanModeTool(config?, onPlanSubmit?)` |
|
|
110
120
|
|
|
111
121
|
### Web Tools (require `parallel-web` peer dependency)
|
|
112
122
|
|
|
@@ -154,10 +164,30 @@ const sandbox = createE2BSandbox({
|
|
|
154
164
|
|
|
155
165
|
## Configuration
|
|
156
166
|
|
|
157
|
-
You can configure tools with security restrictions and limits:
|
|
167
|
+
You can configure tools with security restrictions and limits, and enable optional tools:
|
|
158
168
|
|
|
159
169
|
```typescript
|
|
160
|
-
const tools = createAgentTools(sandbox, {
|
|
170
|
+
const { tools, planModeState } = createAgentTools(sandbox, {
|
|
171
|
+
// Enable optional tools
|
|
172
|
+
askUser: {
|
|
173
|
+
onQuestion: async (question) => {
|
|
174
|
+
// Return user's answer, or undefined to return awaiting_response
|
|
175
|
+
return await promptUser(question);
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
planMode: true, // Enables EnterPlanMode and ExitPlanMode
|
|
179
|
+
skill: {
|
|
180
|
+
skills: discoveredSkills, // From discoverSkills()
|
|
181
|
+
},
|
|
182
|
+
webSearch: {
|
|
183
|
+
apiKey: process.env.PARALLEL_API_KEY,
|
|
184
|
+
},
|
|
185
|
+
webFetch: {
|
|
186
|
+
apiKey: process.env.PARALLEL_API_KEY,
|
|
187
|
+
model: anthropic('claude-haiku-4'),
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
// Tool-specific config
|
|
161
191
|
tools: {
|
|
162
192
|
Bash: {
|
|
163
193
|
timeout: 30000,
|
|
@@ -171,13 +201,6 @@ const tools = createAgentTools(sandbox, {
|
|
|
171
201
|
maxFileSize: 1_000_000, // 1MB limit
|
|
172
202
|
},
|
|
173
203
|
},
|
|
174
|
-
webSearch: {
|
|
175
|
-
apiKey: process.env.PARALLEL_API_KEY,
|
|
176
|
-
},
|
|
177
|
-
webFetch: {
|
|
178
|
-
apiKey: process.env.PARALLEL_API_KEY,
|
|
179
|
-
model: anthropic('claude-haiku-4'),
|
|
180
|
-
},
|
|
181
204
|
});
|
|
182
205
|
```
|
|
183
206
|
|
|
@@ -335,7 +358,7 @@ import { discoverSkills, skillsToXml, createAgentTools, createLocalSandbox } fro
|
|
|
335
358
|
|
|
336
359
|
const skills = await discoverSkills();
|
|
337
360
|
const sandbox = createLocalSandbox({ cwd: '/tmp/workspace' });
|
|
338
|
-
const tools = createAgentTools(sandbox);
|
|
361
|
+
const { tools } = createAgentTools(sandbox);
|
|
339
362
|
|
|
340
363
|
const result = await generateText({
|
|
341
364
|
model: anthropic('claude-sonnet-4-5'),
|
|
@@ -504,7 +527,7 @@ ${skillsToXml(skills)}
|
|
|
504
527
|
`;
|
|
505
528
|
|
|
506
529
|
// Create tools and run
|
|
507
|
-
const tools = createAgentTools(sandbox);
|
|
530
|
+
const { tools } = createAgentTools(sandbox);
|
|
508
531
|
|
|
509
532
|
const result = await generateText({
|
|
510
533
|
model: anthropic('claude-sonnet-4-5'),
|
|
@@ -571,7 +594,7 @@ class DockerSandbox implements Sandbox {
|
|
|
571
594
|
}
|
|
572
595
|
|
|
573
596
|
const sandbox = new DockerSandbox();
|
|
574
|
-
const tools = createAgentTools(sandbox);
|
|
597
|
+
const { tools } = createAgentTools(sandbox);
|
|
575
598
|
```
|
|
576
599
|
|
|
577
600
|
## Architecture
|
|
@@ -641,7 +664,13 @@ Creates a set of agent tools bound to a sandbox instance.
|
|
|
641
664
|
|
|
642
665
|
- `createTaskTool(config)` - Spawn sub-agents for complex tasks
|
|
643
666
|
- `createTodoWriteTool(state, config?, onUpdate?)` - Track task progress
|
|
644
|
-
|
|
667
|
+
|
|
668
|
+
### Optional Tools (also available via config)
|
|
669
|
+
|
|
670
|
+
- `createAskUserTool(onQuestion?)` - Ask user for clarification
|
|
671
|
+
- `createEnterPlanModeTool(state)` - Enter planning/exploration mode
|
|
672
|
+
- `createExitPlanModeTool(state, onPlanSubmit?)` - Exit planning mode with a plan
|
|
673
|
+
- `createSkillTool(skills)` - Execute loaded skills
|
|
645
674
|
|
|
646
675
|
### Utilities
|
|
647
676
|
|
package/dist/cli/init.js
CHANGED
|
@@ -54,7 +54,7 @@ export const config: AgentConfig = {${webTools ? `
|
|
|
54
54
|
` : ""}};
|
|
55
55
|
|
|
56
56
|
// Create tools
|
|
57
|
-
export const tools = createAgentTools(sandbox${webTools ? ", config" : ""});
|
|
57
|
+
export const { tools } = createAgentTools(sandbox${webTools ? ", config" : ""});
|
|
58
58
|
`;
|
|
59
59
|
const configPath = join(process.cwd(), "bashkit.config.ts");
|
|
60
60
|
if (existsSync(configPath)) {
|
|
@@ -141,7 +141,7 @@ async function init() {
|
|
|
141
141
|
stdio: "inherit"
|
|
142
142
|
});
|
|
143
143
|
s.stop("Dependencies installed ✓");
|
|
144
|
-
} catch
|
|
144
|
+
} catch {
|
|
145
145
|
s.stop("Installation failed ✗");
|
|
146
146
|
console.error(`
|
|
147
147
|
❌ Failed to install dependencies`);
|
package/dist/index.d.ts
CHANGED
|
@@ -2,9 +2,9 @@ export { anthropicPromptCacheMiddleware } from "./middleware";
|
|
|
2
2
|
export type { E2BSandboxConfig, LocalSandboxConfig, VercelSandboxConfig, } from "./sandbox";
|
|
3
3
|
export { createE2BSandbox, createLocalSandbox, createVercelSandbox, } from "./sandbox";
|
|
4
4
|
export type { ExecOptions, ExecResult, Sandbox } from "./sandbox/interface";
|
|
5
|
-
export type { BashError, BashOutput, EditError, EditOutput, ExitPlanModeError, ExitPlanModeOutput, GlobError, GlobOutput, GrepContentOutput, GrepCountOutput, GrepError, GrepFilesOutput, GrepMatch, GrepOutput, ReadDirectoryOutput, ReadError, ReadOutput, ReadTextOutput, SubagentStepEvent, SubagentTypeConfig, TaskError, TaskOutput, TaskToolConfig, TodoItem, TodoState, TodoWriteError, TodoWriteOutput, WebFetchError, WebFetchOutput, WebFetchToolConfig, WebSearchError, WebSearchOutput, WebSearchResult, WebSearchToolConfig, WriteError, WriteOutput, } from "./tools";
|
|
6
|
-
export { createAgentTools, createBashTool, createEditTool, createExitPlanModeTool, createGlobTool, createGrepTool, createReadTool, createTaskTool, createTodoWriteTool, createWebFetchTool, createWebSearchTool, createWriteTool, } from "./tools";
|
|
7
|
-
export type { AgentConfig, ToolConfig, WebFetchConfig, WebSearchConfig, } from "./types";
|
|
5
|
+
export type { AgentToolsResult, AskUserError, AskUserOutput, AskUserResponseHandler, BashError, BashOutput, EditError, EditOutput, EnterPlanModeError, EnterPlanModeOutput, ExitPlanModeError, ExitPlanModeOutput, PlanModeState, GlobError, GlobOutput, GrepContentOutput, GrepCountOutput, GrepError, GrepFilesOutput, GrepMatch, GrepOutput, ReadDirectoryOutput, ReadError, ReadOutput, ReadTextOutput, SkillError, SkillOutput, SkillToolConfig, SubagentStepEvent, SubagentTypeConfig, TaskError, TaskOutput, TaskToolConfig, TodoItem, TodoState, TodoWriteError, TodoWriteOutput, WebFetchError, WebFetchOutput, WebFetchToolConfig, WebSearchError, WebSearchOutput, WebSearchResult, WebSearchToolConfig, WriteError, WriteOutput, } from "./tools";
|
|
6
|
+
export { createAgentTools, createAskUserTool, createBashTool, createEditTool, createEnterPlanModeTool, createExitPlanModeTool, createGlobTool, createGrepTool, createReadTool, createSkillTool, createTaskTool, createTodoWriteTool, createWebFetchTool, createWebSearchTool, createWriteTool, } from "./tools";
|
|
7
|
+
export type { AgentConfig, AskUserConfig, SkillConfig, ToolConfig, WebFetchConfig, WebSearchConfig, } from "./types";
|
|
8
8
|
export { DEFAULT_CONFIG } from "./types";
|
|
9
9
|
export type { CompactConversationConfig, CompactConversationResult, CompactConversationState, ContextMetrics, ContextStatus, ContextStatusConfig, ContextStatusLevel, ModelContextLimit, PruneMessagesConfig, } from "./utils";
|
|
10
10
|
export { compactConversation, contextNeedsAttention, contextNeedsCompaction, createCompactConfig, estimateMessagesTokens, estimateMessageTokens, estimateTokens, getContextStatus, MODEL_CONTEXT_LIMITS, pruneMessagesByTokens, } from "./utils";
|
package/dist/index.js
CHANGED
|
@@ -358,14 +358,59 @@ var DEFAULT_CONFIG = {
|
|
|
358
358
|
}
|
|
359
359
|
};
|
|
360
360
|
|
|
361
|
-
// src/tools/
|
|
361
|
+
// src/tools/ask-user.ts
|
|
362
362
|
import { tool, zodSchema } from "ai";
|
|
363
363
|
import { z } from "zod";
|
|
364
|
-
var
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
364
|
+
var askUserInputSchema = z.object({
|
|
365
|
+
question: z.string().describe("The question to ask the user. Be specific and concise.")
|
|
366
|
+
});
|
|
367
|
+
var ASK_USER_DESCRIPTION = `Ask the user a clarifying question when you need more information to proceed.
|
|
368
|
+
|
|
369
|
+
**When to use:**
|
|
370
|
+
- You need clarification on ambiguous requirements
|
|
371
|
+
- Multiple valid approaches exist and user preference matters
|
|
372
|
+
- You're about to make a decision with significant consequences
|
|
373
|
+
- Required information is missing from the context
|
|
374
|
+
|
|
375
|
+
**When NOT to use:**
|
|
376
|
+
- You can make a reasonable assumption
|
|
377
|
+
- The question is trivial or can be inferred
|
|
378
|
+
- You're just being overly cautious
|
|
379
|
+
|
|
380
|
+
Keep questions specific and actionable. Avoid yes/no questions when you need details.`;
|
|
381
|
+
function createAskUserTool(onQuestion) {
|
|
382
|
+
return tool({
|
|
383
|
+
description: ASK_USER_DESCRIPTION,
|
|
384
|
+
inputSchema: zodSchema(askUserInputSchema),
|
|
385
|
+
execute: async ({
|
|
386
|
+
question
|
|
387
|
+
}) => {
|
|
388
|
+
try {
|
|
389
|
+
if (onQuestion) {
|
|
390
|
+
const answer = await onQuestion(question);
|
|
391
|
+
return { answer };
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
question,
|
|
395
|
+
awaiting_response: true
|
|
396
|
+
};
|
|
397
|
+
} catch (error) {
|
|
398
|
+
return {
|
|
399
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// src/tools/bash.ts
|
|
407
|
+
import { tool as tool2, zodSchema as zodSchema2 } from "ai";
|
|
408
|
+
import { z as z2 } from "zod";
|
|
409
|
+
var bashInputSchema = z2.object({
|
|
410
|
+
command: z2.string().describe("The command to execute"),
|
|
411
|
+
timeout: z2.number().optional().describe("Optional timeout in milliseconds (max 600000)"),
|
|
412
|
+
description: z2.string().optional().describe("Clear, concise description of what this command does in 5-10 words"),
|
|
413
|
+
run_in_background: z2.boolean().optional().describe("Set to true to run this command in the background")
|
|
369
414
|
});
|
|
370
415
|
var BASH_DESCRIPTION = `Executes bash commands in a persistent shell session with optional timeout and background execution.
|
|
371
416
|
|
|
@@ -379,9 +424,9 @@ var BASH_DESCRIPTION = `Executes bash commands in a persistent shell session wit
|
|
|
379
424
|
function createBashTool(sandbox, config) {
|
|
380
425
|
const maxOutputLength = config?.maxOutputLength ?? 30000;
|
|
381
426
|
const defaultTimeout = config?.timeout ?? 120000;
|
|
382
|
-
return
|
|
427
|
+
return tool2({
|
|
383
428
|
description: BASH_DESCRIPTION,
|
|
384
|
-
inputSchema:
|
|
429
|
+
inputSchema: zodSchema2(bashInputSchema),
|
|
385
430
|
execute: async ({
|
|
386
431
|
command,
|
|
387
432
|
timeout,
|
|
@@ -429,18 +474,18 @@ function createBashTool(sandbox, config) {
|
|
|
429
474
|
}
|
|
430
475
|
|
|
431
476
|
// src/tools/edit.ts
|
|
432
|
-
import { tool as
|
|
433
|
-
import { z as
|
|
434
|
-
var editInputSchema =
|
|
435
|
-
file_path:
|
|
436
|
-
old_string:
|
|
437
|
-
new_string:
|
|
438
|
-
replace_all:
|
|
477
|
+
import { tool as tool3, zodSchema as zodSchema3 } from "ai";
|
|
478
|
+
import { z as z3 } from "zod";
|
|
479
|
+
var editInputSchema = z3.object({
|
|
480
|
+
file_path: z3.string().describe("The absolute path to the file to modify"),
|
|
481
|
+
old_string: z3.string().describe("The text to replace"),
|
|
482
|
+
new_string: z3.string().describe("The text to replace it with (must be different from old_string)"),
|
|
483
|
+
replace_all: z3.boolean().optional().describe("Replace all occurrences of old_string (default false)")
|
|
439
484
|
});
|
|
440
485
|
function createEditTool(sandbox, config) {
|
|
441
|
-
return
|
|
486
|
+
return tool3({
|
|
442
487
|
description: "Performs exact string replacements in files.",
|
|
443
|
-
inputSchema:
|
|
488
|
+
inputSchema: zodSchema3(editInputSchema),
|
|
444
489
|
execute: async ({
|
|
445
490
|
file_path,
|
|
446
491
|
old_string,
|
|
@@ -495,17 +540,104 @@ function createEditTool(sandbox, config) {
|
|
|
495
540
|
});
|
|
496
541
|
}
|
|
497
542
|
|
|
543
|
+
// src/tools/enter-plan-mode.ts
|
|
544
|
+
import { tool as tool4, zodSchema as zodSchema4 } from "ai";
|
|
545
|
+
import { z as z4 } from "zod";
|
|
546
|
+
var enterPlanModeInputSchema = z4.object({
|
|
547
|
+
reason: z4.string().describe("Brief explanation of why you're entering planning mode (e.g., 'Need to explore codebase architecture before implementing feature')")
|
|
548
|
+
});
|
|
549
|
+
var ENTER_PLAN_MODE_DESCRIPTION = `Enter planning mode to explore and design implementation approaches before making changes.
|
|
550
|
+
|
|
551
|
+
**When to use:**
|
|
552
|
+
- Complex tasks requiring research or exploration
|
|
553
|
+
- Need to understand codebase structure before implementing
|
|
554
|
+
- Multiple approaches possible and you need to evaluate trade-offs
|
|
555
|
+
- User explicitly asks you to plan before executing
|
|
556
|
+
|
|
557
|
+
**In planning mode:**
|
|
558
|
+
- Focus on reading, searching, and understanding
|
|
559
|
+
- Avoid making file changes (use Read, Grep, Glob instead of Write, Edit)
|
|
560
|
+
- Document your findings and proposed approach
|
|
561
|
+
- Use ExitPlanMode when ready with a plan for user approval
|
|
562
|
+
|
|
563
|
+
**When NOT to use:**
|
|
564
|
+
- Simple, well-defined tasks
|
|
565
|
+
- You already understand the codebase and approach
|
|
566
|
+
- User wants immediate execution`;
|
|
567
|
+
function createEnterPlanModeTool(state, onEnter) {
|
|
568
|
+
return tool4({
|
|
569
|
+
description: ENTER_PLAN_MODE_DESCRIPTION,
|
|
570
|
+
inputSchema: zodSchema4(enterPlanModeInputSchema),
|
|
571
|
+
execute: async ({
|
|
572
|
+
reason
|
|
573
|
+
}) => {
|
|
574
|
+
try {
|
|
575
|
+
if (state.isActive) {
|
|
576
|
+
return {
|
|
577
|
+
error: "Already in planning mode. Use ExitPlanMode to exit."
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
state.isActive = true;
|
|
581
|
+
state.enteredAt = new Date;
|
|
582
|
+
state.reason = reason;
|
|
583
|
+
if (onEnter) {
|
|
584
|
+
await onEnter(reason);
|
|
585
|
+
}
|
|
586
|
+
return {
|
|
587
|
+
message: `Entered planning mode: ${reason}. Use Read, Grep, and Glob to explore. Call ExitPlanMode when ready with a plan.`,
|
|
588
|
+
mode: "planning"
|
|
589
|
+
};
|
|
590
|
+
} catch (error) {
|
|
591
|
+
return {
|
|
592
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// src/tools/exit-plan-mode.ts
|
|
600
|
+
import { tool as tool5, zodSchema as zodSchema5 } from "ai";
|
|
601
|
+
import { z as z5 } from "zod";
|
|
602
|
+
var exitPlanModeInputSchema = z5.object({
|
|
603
|
+
plan: z5.string().describe("The plan to present to the user for approval")
|
|
604
|
+
});
|
|
605
|
+
function createExitPlanModeTool(config, onPlanSubmit) {
|
|
606
|
+
return tool5({
|
|
607
|
+
description: "Exits planning mode and prompts the user to approve the plan. Use this when you have finished planning and want user confirmation before proceeding.",
|
|
608
|
+
inputSchema: zodSchema5(exitPlanModeInputSchema),
|
|
609
|
+
execute: async ({
|
|
610
|
+
plan
|
|
611
|
+
}) => {
|
|
612
|
+
try {
|
|
613
|
+
let approved;
|
|
614
|
+
if (onPlanSubmit) {
|
|
615
|
+
approved = await onPlanSubmit(plan);
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
message: approved ? "Plan approved, proceeding with execution" : "Plan submitted for review",
|
|
619
|
+
approved
|
|
620
|
+
};
|
|
621
|
+
} catch (error) {
|
|
622
|
+
return {
|
|
623
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
|
|
498
630
|
// src/tools/glob.ts
|
|
499
|
-
import { tool as
|
|
500
|
-
import { z as
|
|
501
|
-
var globInputSchema =
|
|
502
|
-
pattern:
|
|
503
|
-
path:
|
|
631
|
+
import { tool as tool6, zodSchema as zodSchema6 } from "ai";
|
|
632
|
+
import { z as z6 } from "zod";
|
|
633
|
+
var globInputSchema = z6.object({
|
|
634
|
+
pattern: z6.string().describe('Glob pattern to match files (e.g., "**/*.ts", "src/**/*.js", "*.md")'),
|
|
635
|
+
path: z6.string().optional().describe("Directory to search in (defaults to working directory)")
|
|
504
636
|
});
|
|
505
637
|
function createGlobTool(sandbox, config) {
|
|
506
|
-
return
|
|
638
|
+
return tool6({
|
|
507
639
|
description: "Search for files matching a glob pattern. Returns file paths sorted by modification time. Use this instead of `find` command.",
|
|
508
|
-
inputSchema:
|
|
640
|
+
inputSchema: zodSchema6(globInputSchema),
|
|
509
641
|
execute: async ({
|
|
510
642
|
pattern,
|
|
511
643
|
path
|
|
@@ -539,26 +671,26 @@ function createGlobTool(sandbox, config) {
|
|
|
539
671
|
}
|
|
540
672
|
|
|
541
673
|
// src/tools/grep.ts
|
|
542
|
-
import { tool as
|
|
543
|
-
import { z as
|
|
544
|
-
var grepInputSchema =
|
|
545
|
-
pattern:
|
|
546
|
-
path:
|
|
547
|
-
glob:
|
|
548
|
-
type:
|
|
549
|
-
output_mode:
|
|
550
|
-
"-i":
|
|
551
|
-
"-n":
|
|
552
|
-
"-B":
|
|
553
|
-
"-A":
|
|
554
|
-
"-C":
|
|
555
|
-
head_limit:
|
|
556
|
-
multiline:
|
|
674
|
+
import { tool as tool7, zodSchema as zodSchema7 } from "ai";
|
|
675
|
+
import { z as z7 } from "zod";
|
|
676
|
+
var grepInputSchema = z7.object({
|
|
677
|
+
pattern: z7.string().describe("The regular expression pattern to search for"),
|
|
678
|
+
path: z7.string().optional().describe("File or directory to search in (defaults to cwd)"),
|
|
679
|
+
glob: z7.string().optional().describe('Glob pattern to filter files (e.g. "*.js")'),
|
|
680
|
+
type: z7.string().optional().describe('File type to search (e.g. "js", "py", "rust")'),
|
|
681
|
+
output_mode: z7.enum(["content", "files_with_matches", "count"]).optional().describe('Output mode: "content", "files_with_matches", or "count"'),
|
|
682
|
+
"-i": z7.boolean().optional().describe("Case insensitive search"),
|
|
683
|
+
"-n": z7.boolean().optional().describe("Show line numbers (for content mode)"),
|
|
684
|
+
"-B": z7.number().optional().describe("Lines to show before each match"),
|
|
685
|
+
"-A": z7.number().optional().describe("Lines to show after each match"),
|
|
686
|
+
"-C": z7.number().optional().describe("Lines to show before and after each match"),
|
|
687
|
+
head_limit: z7.number().optional().describe("Limit output to first N lines/entries"),
|
|
688
|
+
multiline: z7.boolean().optional().describe("Enable multiline mode")
|
|
557
689
|
});
|
|
558
690
|
function createGrepTool(sandbox, config) {
|
|
559
|
-
return
|
|
691
|
+
return tool7({
|
|
560
692
|
description: "Powerful search tool built on ripgrep with regex support. Use this instead of the grep command.",
|
|
561
|
-
inputSchema:
|
|
693
|
+
inputSchema: zodSchema7(grepInputSchema),
|
|
562
694
|
execute: async (input) => {
|
|
563
695
|
const {
|
|
564
696
|
pattern,
|
|
@@ -668,17 +800,17 @@ function createGrepTool(sandbox, config) {
|
|
|
668
800
|
}
|
|
669
801
|
|
|
670
802
|
// src/tools/read.ts
|
|
671
|
-
import { tool as
|
|
672
|
-
import { z as
|
|
673
|
-
var readInputSchema =
|
|
674
|
-
file_path:
|
|
675
|
-
offset:
|
|
676
|
-
limit:
|
|
803
|
+
import { tool as tool8, zodSchema as zodSchema8 } from "ai";
|
|
804
|
+
import { z as z8 } from "zod";
|
|
805
|
+
var readInputSchema = z8.object({
|
|
806
|
+
file_path: z8.string().describe("Absolute path to file or directory"),
|
|
807
|
+
offset: z8.number().optional().describe("Line number to start reading from (1-indexed)"),
|
|
808
|
+
limit: z8.number().optional().describe("Maximum number of lines to read")
|
|
677
809
|
});
|
|
678
810
|
function createReadTool(sandbox, config) {
|
|
679
|
-
return
|
|
811
|
+
return tool8({
|
|
680
812
|
description: "Read the contents of a file or list directory entries. For text files, returns numbered lines with total line count. For directories, returns file/folder names. Use this instead of `cat`, `head`, or `tail` commands.",
|
|
681
|
-
inputSchema:
|
|
813
|
+
inputSchema: zodSchema8(readInputSchema),
|
|
682
814
|
execute: async ({
|
|
683
815
|
file_path,
|
|
684
816
|
offset,
|
|
@@ -760,20 +892,91 @@ function createReadTool(sandbox, config) {
|
|
|
760
892
|
});
|
|
761
893
|
}
|
|
762
894
|
|
|
895
|
+
// src/tools/skill.ts
|
|
896
|
+
import { tool as tool9, zodSchema as zodSchema9 } from "ai";
|
|
897
|
+
import { z as z9 } from "zod";
|
|
898
|
+
var skillInputSchema = z9.object({
|
|
899
|
+
name: z9.string().describe("The name of the skill to activate (from available skills list)")
|
|
900
|
+
});
|
|
901
|
+
var SKILL_DESCRIPTION = `Activate a skill to get specialized instructions for a task.
|
|
902
|
+
|
|
903
|
+
**How skills work:**
|
|
904
|
+
1. Skills are pre-loaded at startup (only metadata: name, description, path)
|
|
905
|
+
2. Calling this tool loads the full skill instructions from SKILL.md
|
|
906
|
+
3. Follow the returned instructions to complete the task
|
|
907
|
+
4. Some skills restrict which tools you can use (allowed_tools)
|
|
908
|
+
|
|
909
|
+
**When to use:**
|
|
910
|
+
- A task matches a skill's description
|
|
911
|
+
- You need specialized knowledge for a domain (e.g., PDF processing, web research)
|
|
912
|
+
- The skill provides step-by-step guidance you should follow
|
|
913
|
+
|
|
914
|
+
**Available skills are listed in the system prompt.**`;
|
|
915
|
+
function createSkillTool(config) {
|
|
916
|
+
const { skills, sandbox, onActivate } = config;
|
|
917
|
+
return tool9({
|
|
918
|
+
description: SKILL_DESCRIPTION,
|
|
919
|
+
inputSchema: zodSchema9(skillInputSchema),
|
|
920
|
+
execute: async ({
|
|
921
|
+
name
|
|
922
|
+
}) => {
|
|
923
|
+
try {
|
|
924
|
+
const skill = skills[name];
|
|
925
|
+
if (!skill) {
|
|
926
|
+
const available = Object.keys(skills);
|
|
927
|
+
if (available.length === 0) {
|
|
928
|
+
return { error: "No skills are available." };
|
|
929
|
+
}
|
|
930
|
+
return {
|
|
931
|
+
error: `Skill '${name}' not found. Available skills: ${available.join(", ")}`
|
|
932
|
+
};
|
|
933
|
+
}
|
|
934
|
+
let instructions;
|
|
935
|
+
if (!sandbox) {
|
|
936
|
+
return {
|
|
937
|
+
error: `Cannot load skill '${name}': no sandbox provided to read ${skill.path}`
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
const content = await sandbox.readFile(skill.path);
|
|
941
|
+
const frontmatterEnd = content.indexOf(`
|
|
942
|
+
---`, 4);
|
|
943
|
+
if (frontmatterEnd !== -1) {
|
|
944
|
+
instructions = content.slice(frontmatterEnd + 4).trim();
|
|
945
|
+
} else {
|
|
946
|
+
instructions = content;
|
|
947
|
+
}
|
|
948
|
+
if (onActivate) {
|
|
949
|
+
await onActivate(skill, instructions);
|
|
950
|
+
}
|
|
951
|
+
return {
|
|
952
|
+
name: skill.name,
|
|
953
|
+
instructions,
|
|
954
|
+
allowed_tools: skill.allowedTools,
|
|
955
|
+
message: skill.allowedTools ? `Skill '${name}' activated. Restricted to tools: ${skill.allowedTools.join(", ")}` : `Skill '${name}' activated. Follow the instructions below.`
|
|
956
|
+
};
|
|
957
|
+
} catch (error) {
|
|
958
|
+
return {
|
|
959
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
|
|
763
966
|
// src/tools/web-fetch.ts
|
|
764
|
-
import { generateText, tool as
|
|
967
|
+
import { generateText, tool as tool10, zodSchema as zodSchema10 } from "ai";
|
|
765
968
|
import Parallel from "parallel-web";
|
|
766
|
-
import { z as
|
|
767
|
-
var webFetchInputSchema =
|
|
768
|
-
url:
|
|
769
|
-
prompt:
|
|
969
|
+
import { z as z10 } from "zod";
|
|
970
|
+
var webFetchInputSchema = z10.object({
|
|
971
|
+
url: z10.string().describe("The URL to fetch content from"),
|
|
972
|
+
prompt: z10.string().describe("The prompt to run on the fetched content")
|
|
770
973
|
});
|
|
771
974
|
var RETRYABLE_CODES = [408, 429, 500, 502, 503];
|
|
772
975
|
function createWebFetchTool(config) {
|
|
773
976
|
const { apiKey, model } = config;
|
|
774
|
-
return
|
|
977
|
+
return tool10({
|
|
775
978
|
description: "Fetches content from a URL and processes it with an AI model. Use this to analyze web pages, extract information, or summarize content.",
|
|
776
|
-
inputSchema:
|
|
979
|
+
inputSchema: zodSchema10(webFetchInputSchema),
|
|
777
980
|
execute: async (input) => {
|
|
778
981
|
const { url, prompt } = input;
|
|
779
982
|
try {
|
|
@@ -833,20 +1036,20 @@ ${content}`
|
|
|
833
1036
|
}
|
|
834
1037
|
|
|
835
1038
|
// src/tools/web-search.ts
|
|
836
|
-
import { tool as
|
|
1039
|
+
import { tool as tool11, zodSchema as zodSchema11 } from "ai";
|
|
837
1040
|
import Parallel2 from "parallel-web";
|
|
838
|
-
import { z as
|
|
839
|
-
var webSearchInputSchema =
|
|
840
|
-
query:
|
|
841
|
-
allowed_domains:
|
|
842
|
-
blocked_domains:
|
|
1041
|
+
import { z as z11 } from "zod";
|
|
1042
|
+
var webSearchInputSchema = z11.object({
|
|
1043
|
+
query: z11.string().describe("The search query to use"),
|
|
1044
|
+
allowed_domains: z11.array(z11.string()).optional().describe("Only include results from these domains"),
|
|
1045
|
+
blocked_domains: z11.array(z11.string()).optional().describe("Never include results from these domains")
|
|
843
1046
|
});
|
|
844
1047
|
var RETRYABLE_CODES2 = [408, 429, 500, 502, 503];
|
|
845
1048
|
function createWebSearchTool(config) {
|
|
846
1049
|
const { apiKey } = config;
|
|
847
|
-
return
|
|
1050
|
+
return tool11({
|
|
848
1051
|
description: "Searches the web and returns formatted results. Use this to find current information, documentation, articles, and more.",
|
|
849
|
-
inputSchema:
|
|
1052
|
+
inputSchema: zodSchema11(webSearchInputSchema),
|
|
850
1053
|
execute: async (input) => {
|
|
851
1054
|
const { query, allowed_domains, blocked_domains } = input;
|
|
852
1055
|
try {
|
|
@@ -892,16 +1095,16 @@ function createWebSearchTool(config) {
|
|
|
892
1095
|
}
|
|
893
1096
|
|
|
894
1097
|
// src/tools/write.ts
|
|
895
|
-
import { tool as
|
|
896
|
-
import { z as
|
|
897
|
-
var writeInputSchema =
|
|
898
|
-
file_path:
|
|
899
|
-
content:
|
|
1098
|
+
import { tool as tool12, zodSchema as zodSchema12 } from "ai";
|
|
1099
|
+
import { z as z12 } from "zod";
|
|
1100
|
+
var writeInputSchema = z12.object({
|
|
1101
|
+
file_path: z12.string().describe("Path to the file to write"),
|
|
1102
|
+
content: z12.string().describe("Content to write to the file")
|
|
900
1103
|
});
|
|
901
1104
|
function createWriteTool(sandbox, config) {
|
|
902
|
-
return
|
|
1105
|
+
return tool12({
|
|
903
1106
|
description: "Write content to a file. Creates the file if it does not exist, overwrites if it does.",
|
|
904
|
-
inputSchema:
|
|
1107
|
+
inputSchema: zodSchema12(writeInputSchema),
|
|
905
1108
|
execute: async ({
|
|
906
1109
|
file_path,
|
|
907
1110
|
content
|
|
@@ -933,48 +1136,18 @@ function createWriteTool(sandbox, config) {
|
|
|
933
1136
|
}
|
|
934
1137
|
});
|
|
935
1138
|
}
|
|
936
|
-
// src/tools/exit-plan-mode.ts
|
|
937
|
-
import { tool as tool9, zodSchema as zodSchema9 } from "ai";
|
|
938
|
-
import { z as z9 } from "zod";
|
|
939
|
-
var exitPlanModeInputSchema = z9.object({
|
|
940
|
-
plan: z9.string().describe("The plan to present to the user for approval")
|
|
941
|
-
});
|
|
942
|
-
function createExitPlanModeTool(config, onPlanSubmit) {
|
|
943
|
-
return tool9({
|
|
944
|
-
description: "Exits planning mode and prompts the user to approve the plan. Use this when you have finished planning and want user confirmation before proceeding.",
|
|
945
|
-
inputSchema: zodSchema9(exitPlanModeInputSchema),
|
|
946
|
-
execute: async ({
|
|
947
|
-
plan
|
|
948
|
-
}) => {
|
|
949
|
-
try {
|
|
950
|
-
let approved;
|
|
951
|
-
if (onPlanSubmit) {
|
|
952
|
-
approved = await onPlanSubmit(plan);
|
|
953
|
-
}
|
|
954
|
-
return {
|
|
955
|
-
message: approved ? "Plan approved, proceeding with execution" : "Plan submitted for review",
|
|
956
|
-
approved
|
|
957
|
-
};
|
|
958
|
-
} catch (error) {
|
|
959
|
-
return {
|
|
960
|
-
error: error instanceof Error ? error.message : "Unknown error"
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
});
|
|
965
|
-
}
|
|
966
1139
|
// src/tools/task.ts
|
|
967
1140
|
import {
|
|
968
1141
|
generateText as generateText2,
|
|
969
1142
|
stepCountIs,
|
|
970
|
-
tool as
|
|
971
|
-
zodSchema as
|
|
1143
|
+
tool as tool13,
|
|
1144
|
+
zodSchema as zodSchema13
|
|
972
1145
|
} from "ai";
|
|
973
|
-
import { z as
|
|
974
|
-
var taskInputSchema =
|
|
975
|
-
description:
|
|
976
|
-
prompt:
|
|
977
|
-
subagent_type:
|
|
1146
|
+
import { z as z13 } from "zod";
|
|
1147
|
+
var taskInputSchema = z13.object({
|
|
1148
|
+
description: z13.string().describe("A short (3-5 word) description of the task"),
|
|
1149
|
+
prompt: z13.string().describe("The task for the agent to perform"),
|
|
1150
|
+
subagent_type: z13.string().describe("The type of specialized agent to use for this task")
|
|
978
1151
|
});
|
|
979
1152
|
function filterTools(allTools, allowedTools) {
|
|
980
1153
|
if (!allowedTools)
|
|
@@ -997,9 +1170,9 @@ function createTaskTool(config) {
|
|
|
997
1170
|
defaultStopWhen,
|
|
998
1171
|
defaultOnStepFinish
|
|
999
1172
|
} = config;
|
|
1000
|
-
return
|
|
1173
|
+
return tool13({
|
|
1001
1174
|
description: "Launches a new agent to handle complex, multi-step tasks autonomously. Use this for tasks that require multiple steps, research, or specialized expertise.",
|
|
1002
|
-
inputSchema:
|
|
1175
|
+
inputSchema: zodSchema13(taskInputSchema),
|
|
1003
1176
|
execute: async ({
|
|
1004
1177
|
description,
|
|
1005
1178
|
prompt,
|
|
@@ -1051,19 +1224,19 @@ function createTaskTool(config) {
|
|
|
1051
1224
|
});
|
|
1052
1225
|
}
|
|
1053
1226
|
// src/tools/todo-write.ts
|
|
1054
|
-
import { tool as
|
|
1055
|
-
import { z as
|
|
1056
|
-
var todoWriteInputSchema =
|
|
1057
|
-
todos:
|
|
1058
|
-
content:
|
|
1059
|
-
status:
|
|
1060
|
-
activeForm:
|
|
1227
|
+
import { tool as tool14, zodSchema as zodSchema14 } from "ai";
|
|
1228
|
+
import { z as z14 } from "zod";
|
|
1229
|
+
var todoWriteInputSchema = z14.object({
|
|
1230
|
+
todos: z14.array(z14.object({
|
|
1231
|
+
content: z14.string().describe("The task description"),
|
|
1232
|
+
status: z14.enum(["pending", "in_progress", "completed"]).describe("The task status"),
|
|
1233
|
+
activeForm: z14.string().describe("Active form of the task description")
|
|
1061
1234
|
})).describe("The updated todo list")
|
|
1062
1235
|
});
|
|
1063
1236
|
function createTodoWriteTool(state, config, onUpdate) {
|
|
1064
|
-
return
|
|
1237
|
+
return tool14({
|
|
1065
1238
|
description: "Creates and manages a structured task list for tracking progress. Use this to plan complex tasks and track completion.",
|
|
1066
|
-
inputSchema:
|
|
1239
|
+
inputSchema: zodSchema14(todoWriteInputSchema),
|
|
1067
1240
|
execute: async ({
|
|
1068
1241
|
todos
|
|
1069
1242
|
}) => {
|
|
@@ -1105,13 +1278,29 @@ function createAgentTools(sandbox, config) {
|
|
|
1105
1278
|
Glob: createGlobTool(sandbox, toolsConfig.Glob),
|
|
1106
1279
|
Grep: createGrepTool(sandbox, toolsConfig.Grep)
|
|
1107
1280
|
};
|
|
1281
|
+
let planModeState;
|
|
1282
|
+
if (config?.askUser) {
|
|
1283
|
+
tools.AskUser = createAskUserTool(config.askUser.onQuestion);
|
|
1284
|
+
}
|
|
1285
|
+
if (config?.planMode) {
|
|
1286
|
+
planModeState = { isActive: false };
|
|
1287
|
+
tools.EnterPlanMode = createEnterPlanModeTool(planModeState);
|
|
1288
|
+
tools.ExitPlanMode = createExitPlanModeTool();
|
|
1289
|
+
}
|
|
1290
|
+
if (config?.skill) {
|
|
1291
|
+
tools.Skill = createSkillTool({
|
|
1292
|
+
skills: config.skill.skills,
|
|
1293
|
+
sandbox,
|
|
1294
|
+
onActivate: config.skill.onActivate
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1108
1297
|
if (config?.webSearch) {
|
|
1109
1298
|
tools.WebSearch = createWebSearchTool(config.webSearch);
|
|
1110
1299
|
}
|
|
1111
1300
|
if (config?.webFetch) {
|
|
1112
1301
|
tools.WebFetch = createWebFetchTool(config.webFetch);
|
|
1113
1302
|
}
|
|
1114
|
-
return tools;
|
|
1303
|
+
return { tools, planModeState };
|
|
1115
1304
|
}
|
|
1116
1305
|
// src/utils/compact-conversation.ts
|
|
1117
1306
|
import { generateText as generateText3 } from "ai";
|
|
@@ -1786,15 +1975,18 @@ export {
|
|
|
1786
1975
|
createVercelSandbox,
|
|
1787
1976
|
createTodoWriteTool,
|
|
1788
1977
|
createTaskTool,
|
|
1978
|
+
createSkillTool,
|
|
1789
1979
|
createReadTool,
|
|
1790
1980
|
createLocalSandbox,
|
|
1791
1981
|
createGrepTool,
|
|
1792
1982
|
createGlobTool,
|
|
1793
1983
|
createExitPlanModeTool,
|
|
1984
|
+
createEnterPlanModeTool,
|
|
1794
1985
|
createEditTool,
|
|
1795
1986
|
createE2BSandbox,
|
|
1796
1987
|
createCompactConfig,
|
|
1797
1988
|
createBashTool,
|
|
1989
|
+
createAskUserTool,
|
|
1798
1990
|
createAgentTools,
|
|
1799
1991
|
contextNeedsCompaction,
|
|
1800
1992
|
contextNeedsAttention,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface AskUserOutput {
|
|
2
|
+
question: string;
|
|
3
|
+
awaiting_response: true;
|
|
4
|
+
}
|
|
5
|
+
export interface AskUserError {
|
|
6
|
+
error: string;
|
|
7
|
+
}
|
|
8
|
+
export type AskUserResponseHandler = (question: string) => Promise<string> | string;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a tool for asking the user clarifying questions.
|
|
11
|
+
*
|
|
12
|
+
* The response handler can be:
|
|
13
|
+
* - Synchronous: returns the answer immediately
|
|
14
|
+
* - Async: waits for user input (e.g., from a UI)
|
|
15
|
+
* - Undefined: tool returns awaiting_response flag for external handling
|
|
16
|
+
*
|
|
17
|
+
* @param onQuestion - Optional callback to handle the question and return an answer
|
|
18
|
+
*/
|
|
19
|
+
export declare function createAskUserTool(onQuestion?: AskUserResponseHandler): import("ai").Tool<{
|
|
20
|
+
question: string;
|
|
21
|
+
}, AskUserOutput | AskUserError | {
|
|
22
|
+
answer: string;
|
|
23
|
+
}>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface PlanModeState {
|
|
2
|
+
isActive: boolean;
|
|
3
|
+
enteredAt?: Date;
|
|
4
|
+
reason?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface EnterPlanModeOutput {
|
|
7
|
+
message: string;
|
|
8
|
+
mode: "planning";
|
|
9
|
+
}
|
|
10
|
+
export interface EnterPlanModeError {
|
|
11
|
+
error: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Creates a tool for entering planning mode.
|
|
15
|
+
* Works in conjunction with ExitPlanMode for plan-then-execute workflows.
|
|
16
|
+
*
|
|
17
|
+
* @param state - Shared state object to track planning mode
|
|
18
|
+
* @param onEnter - Optional callback when entering planning mode
|
|
19
|
+
*/
|
|
20
|
+
export declare function createEnterPlanModeTool(state: PlanModeState, onEnter?: (reason: string) => void | Promise<void>): import("ai").Tool<{
|
|
21
|
+
reason: string;
|
|
22
|
+
}, EnterPlanModeOutput | EnterPlanModeError>;
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,30 +1,60 @@
|
|
|
1
1
|
import type { ToolSet } from "ai";
|
|
2
2
|
import type { Sandbox } from "../sandbox/interface";
|
|
3
3
|
import type { AgentConfig } from "../types";
|
|
4
|
+
import { type PlanModeState } from "./enter-plan-mode";
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
* Result from createAgentTools including tools and optional shared state.
|
|
7
|
+
*/
|
|
8
|
+
export interface AgentToolsResult {
|
|
9
|
+
/** All configured tools for use with generateText/streamText */
|
|
10
|
+
tools: ToolSet;
|
|
11
|
+
/** Shared plan mode state (only present when planMode is enabled) */
|
|
12
|
+
planModeState?: PlanModeState;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates agent tools for AI SDK's generateText/streamText.
|
|
16
|
+
*
|
|
17
|
+
* **Default tools (always included):**
|
|
18
|
+
* - Bash, Read, Write, Edit, Glob, Grep (sandbox operations)
|
|
19
|
+
*
|
|
20
|
+
* **Optional tools (via config):**
|
|
21
|
+
* - `askUser` — AskUser tool for clarifying questions
|
|
22
|
+
* - `planMode` — EnterPlanMode, ExitPlanMode for interactive planning
|
|
23
|
+
* - `skill` — Skill tool for skill execution
|
|
24
|
+
* - `webSearch` — WebSearch tool
|
|
25
|
+
* - `webFetch` — WebFetch tool
|
|
8
26
|
*
|
|
9
27
|
* @param sandbox - The sandbox to execute commands in
|
|
10
|
-
* @param config - Optional configuration for
|
|
28
|
+
* @param config - Optional configuration for tools
|
|
29
|
+
* @returns Object with tools and optional planModeState
|
|
11
30
|
*
|
|
12
31
|
* @example
|
|
13
|
-
* // Basic
|
|
14
|
-
* const tools = createAgentTools(sandbox);
|
|
32
|
+
* // Basic usage (lean default for background agents)
|
|
33
|
+
* const { tools } = createAgentTools(sandbox);
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* // Interactive agent with plan mode
|
|
37
|
+
* const { tools, planModeState } = createAgentTools(sandbox, {
|
|
38
|
+
* planMode: true,
|
|
39
|
+
* askUser: { onQuestion: async (q) => await promptUser(q) },
|
|
40
|
+
* });
|
|
15
41
|
*
|
|
16
42
|
* @example
|
|
17
|
-
* // With web tools
|
|
18
|
-
* const tools = createAgentTools(sandbox, {
|
|
43
|
+
* // With web and skill tools
|
|
44
|
+
* const { tools } = createAgentTools(sandbox, {
|
|
19
45
|
* webSearch: { apiKey: process.env.PARALLEL_API_KEY },
|
|
20
|
-
*
|
|
46
|
+
* skill: { skills: discoveredSkills },
|
|
21
47
|
* });
|
|
22
48
|
*/
|
|
23
|
-
export declare function createAgentTools(sandbox: Sandbox, config?: AgentConfig):
|
|
49
|
+
export declare function createAgentTools(sandbox: Sandbox, config?: AgentConfig): AgentToolsResult;
|
|
50
|
+
export type { AskUserError, AskUserOutput, AskUserResponseHandler, } from "./ask-user";
|
|
51
|
+
export { createAskUserTool } from "./ask-user";
|
|
24
52
|
export type { BashError, BashOutput } from "./bash";
|
|
25
53
|
export { createBashTool } from "./bash";
|
|
26
54
|
export type { EditError, EditOutput } from "./edit";
|
|
27
55
|
export { createEditTool } from "./edit";
|
|
56
|
+
export type { EnterPlanModeError, EnterPlanModeOutput, PlanModeState, } from "./enter-plan-mode";
|
|
57
|
+
export { createEnterPlanModeTool } from "./enter-plan-mode";
|
|
28
58
|
export type { ExitPlanModeError, ExitPlanModeOutput } from "./exit-plan-mode";
|
|
29
59
|
export { createExitPlanModeTool } from "./exit-plan-mode";
|
|
30
60
|
export type { GlobError, GlobOutput } from "./glob";
|
|
@@ -33,6 +63,8 @@ export type { GrepContentOutput, GrepCountOutput, GrepError, GrepFilesOutput, Gr
|
|
|
33
63
|
export { createGrepTool } from "./grep";
|
|
34
64
|
export type { ReadDirectoryOutput, ReadError, ReadOutput, ReadTextOutput, } from "./read";
|
|
35
65
|
export { createReadTool } from "./read";
|
|
66
|
+
export type { SkillError, SkillOutput, SkillToolConfig } from "./skill";
|
|
67
|
+
export { createSkillTool } from "./skill";
|
|
36
68
|
export type { SubagentStepEvent, SubagentTypeConfig, TaskError, TaskOutput, TaskToolConfig, } from "./task";
|
|
37
69
|
export { createTaskTool } from "./task";
|
|
38
70
|
export type { TodoItem, TodoState, TodoWriteError, TodoWriteOutput, } from "./todo-write";
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A diagnostic (error/warning) from the language server.
|
|
3
|
+
*/
|
|
4
|
+
export interface LspDiagnostic {
|
|
5
|
+
file: string;
|
|
6
|
+
line: number;
|
|
7
|
+
column: number;
|
|
8
|
+
endLine?: number;
|
|
9
|
+
endColumn?: number;
|
|
10
|
+
severity: "error" | "warning" | "info" | "hint";
|
|
11
|
+
message: string;
|
|
12
|
+
source?: string;
|
|
13
|
+
code?: string | number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A location in the codebase (for go-to-definition, references, etc.)
|
|
17
|
+
*/
|
|
18
|
+
export interface LspLocation {
|
|
19
|
+
file: string;
|
|
20
|
+
line: number;
|
|
21
|
+
column: number;
|
|
22
|
+
endLine?: number;
|
|
23
|
+
endColumn?: number;
|
|
24
|
+
preview?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Hover information for a symbol.
|
|
28
|
+
*/
|
|
29
|
+
export interface LspHoverInfo {
|
|
30
|
+
contents: string;
|
|
31
|
+
range?: {
|
|
32
|
+
startLine: number;
|
|
33
|
+
startColumn: number;
|
|
34
|
+
endLine: number;
|
|
35
|
+
endColumn: number;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Interface that LSP providers must implement.
|
|
40
|
+
* This abstracts over different LSP implementations (vscode, standalone servers, etc.)
|
|
41
|
+
*/
|
|
42
|
+
export interface LspProvider {
|
|
43
|
+
/** Get diagnostics for a file or the entire workspace */
|
|
44
|
+
getDiagnostics(file?: string): Promise<LspDiagnostic[]>;
|
|
45
|
+
/** Go to definition of symbol at position */
|
|
46
|
+
getDefinition(file: string, line: number, column: number): Promise<LspLocation[]>;
|
|
47
|
+
/** Find all references to symbol at position */
|
|
48
|
+
getReferences(file: string, line: number, column: number): Promise<LspLocation[]>;
|
|
49
|
+
/** Get hover information for symbol at position */
|
|
50
|
+
getHover(file: string, line: number, column: number): Promise<LspHoverInfo | null>;
|
|
51
|
+
/** Get available actions at position (optional) */
|
|
52
|
+
getCodeActions?(file: string, line: number, column: number): Promise<Array<{
|
|
53
|
+
title: string;
|
|
54
|
+
kind?: string;
|
|
55
|
+
}>>;
|
|
56
|
+
}
|
|
57
|
+
export interface LspDiagnosticsOutput {
|
|
58
|
+
type: "diagnostics";
|
|
59
|
+
diagnostics: LspDiagnostic[];
|
|
60
|
+
counts: {
|
|
61
|
+
errors: number;
|
|
62
|
+
warnings: number;
|
|
63
|
+
info: number;
|
|
64
|
+
hints: number;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
export interface LspDefinitionOutput {
|
|
68
|
+
type: "definition";
|
|
69
|
+
locations: LspLocation[];
|
|
70
|
+
}
|
|
71
|
+
export interface LspReferencesOutput {
|
|
72
|
+
type: "references";
|
|
73
|
+
locations: LspLocation[];
|
|
74
|
+
count: number;
|
|
75
|
+
}
|
|
76
|
+
export interface LspHoverOutput {
|
|
77
|
+
type: "hover";
|
|
78
|
+
info: LspHoverInfo | null;
|
|
79
|
+
}
|
|
80
|
+
export interface LspError {
|
|
81
|
+
error: string;
|
|
82
|
+
}
|
|
83
|
+
export type LspOutput = LspDiagnosticsOutput | LspDefinitionOutput | LspReferencesOutput | LspHoverOutput | LspError;
|
|
84
|
+
/**
|
|
85
|
+
* Creates an LSP tool for code intelligence operations.
|
|
86
|
+
*
|
|
87
|
+
* @param provider - An implementation of LspProvider that interfaces with language servers
|
|
88
|
+
*/
|
|
89
|
+
export declare function createLspTool(provider: LspProvider): import("ai").Tool<{
|
|
90
|
+
action: "diagnostics" | "definition" | "references" | "hover";
|
|
91
|
+
file?: string | undefined;
|
|
92
|
+
line?: number | undefined;
|
|
93
|
+
column?: number | undefined;
|
|
94
|
+
}, LspOutput>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Sandbox } from "../sandbox/interface";
|
|
2
|
+
import type { SkillMetadata } from "../skills/types";
|
|
3
|
+
export interface SkillOutput {
|
|
4
|
+
name: string;
|
|
5
|
+
instructions: string;
|
|
6
|
+
allowed_tools?: string[];
|
|
7
|
+
message: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SkillError {
|
|
10
|
+
error: string;
|
|
11
|
+
}
|
|
12
|
+
export interface SkillToolConfig {
|
|
13
|
+
/** Map of skill name to metadata (from discoverSkills or setupAgentEnvironment) */
|
|
14
|
+
skills: Record<string, SkillMetadata>;
|
|
15
|
+
/** Sandbox for reading skill files (optional if skills have embedded content) */
|
|
16
|
+
sandbox?: Sandbox;
|
|
17
|
+
/** Callback when a skill is activated */
|
|
18
|
+
onActivate?: (skill: SkillMetadata, instructions: string) => void | Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates a tool for activating and loading skills.
|
|
22
|
+
*
|
|
23
|
+
* @param config - Configuration with available skills and optional sandbox
|
|
24
|
+
*/
|
|
25
|
+
export declare function createSkillTool(config: SkillToolConfig): import("ai").Tool<{
|
|
26
|
+
name: string;
|
|
27
|
+
}, SkillOutput | SkillError>;
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { LanguageModel } from "ai";
|
|
2
|
+
import type { SkillMetadata } from "./skills/types";
|
|
2
3
|
export type ToolConfig = {
|
|
3
4
|
timeout?: number;
|
|
4
5
|
maxFileSize?: number;
|
|
@@ -13,6 +14,16 @@ export type WebFetchConfig = {
|
|
|
13
14
|
apiKey: string;
|
|
14
15
|
model: LanguageModel;
|
|
15
16
|
};
|
|
17
|
+
export type AskUserConfig = {
|
|
18
|
+
/** Callback to handle questions and return answers */
|
|
19
|
+
onQuestion?: (question: string) => Promise<string> | string;
|
|
20
|
+
};
|
|
21
|
+
export type SkillConfig = {
|
|
22
|
+
/** Map of skill name to metadata */
|
|
23
|
+
skills: Record<string, SkillMetadata>;
|
|
24
|
+
/** Callback when a skill is activated */
|
|
25
|
+
onActivate?: (skill: SkillMetadata, instructions: string) => void | Promise<void>;
|
|
26
|
+
};
|
|
16
27
|
export type AgentConfig = {
|
|
17
28
|
tools?: {
|
|
18
29
|
Bash?: ToolConfig;
|
|
@@ -22,6 +33,12 @@ export type AgentConfig = {
|
|
|
22
33
|
Glob?: ToolConfig;
|
|
23
34
|
Grep?: ToolConfig;
|
|
24
35
|
};
|
|
36
|
+
/** Include AskUser tool for user clarification */
|
|
37
|
+
askUser?: AskUserConfig;
|
|
38
|
+
/** Include EnterPlanMode and ExitPlanMode tools for interactive planning */
|
|
39
|
+
planMode?: boolean;
|
|
40
|
+
/** Include Skill tool with this config */
|
|
41
|
+
skill?: SkillConfig;
|
|
25
42
|
/** Include WebSearch tool with this config */
|
|
26
43
|
webSearch?: WebSearchConfig;
|
|
27
44
|
/** Include WebFetch tool with this config */
|