diff options
Diffstat (limited to 'js/src/tool')
| -rw-r--r-- | js/src/tool/bash.ts | 8 | ||||
| -rw-r--r-- | js/src/tool/edit.ts | 20 | ||||
| -rw-r--r-- | js/src/tool/tool.ts | 67 | ||||
| -rw-r--r-- | js/src/tool/view.ts | 54 |
4 files changed, 67 insertions, 82 deletions
diff --git a/js/src/tool/bash.ts b/js/src/tool/bash.ts index d5428432c..fb5f18069 100644 --- a/js/src/tool/bash.ts +++ b/js/src/tool/bash.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { tool } from "./tool"; +import { Tool, tool } from "./tool"; const MAX_OUTPUT_LENGTH = 30000; const BANNED_COMMANDS = [ @@ -170,7 +170,7 @@ Important: - Return an empty response - the user will see the gh output directly - Never update git config`; -export const BashTool = tool({ +export const BashTool = Tool.define({ name: "bash", description: DESCRIPTION, parameters: z.object({ @@ -193,7 +193,9 @@ export const BashTool = tool({ timeout: timeout, }); return { - content: process.stdout.toString("utf-8"), + output: { + content: process.stdout.toString("utf-8"), + }, }; }, }); diff --git a/js/src/tool/edit.ts b/js/src/tool/edit.ts index 2427b19b6..24bf29bcb 100644 --- a/js/src/tool/edit.ts +++ b/js/src/tool/edit.ts @@ -1,11 +1,11 @@ import { z } from "zod"; -import { tool } from "./tool"; import * as fs from "fs"; import * as path from "path"; import { Log } from "../util/log"; -import { App } from "../app"; +import { Tool } from "./tool"; +import { FileTimes } from "./util/file-times"; -const log = Log.create({ service: "edit-tool" }); +const log = Log.create({ service: "tool.edit" }); // Simple diff generation function generateDiff( @@ -116,7 +116,7 @@ When making edits: Remember: when making multiple file edits in a row to the same file, you should prefer to send all edits in a single message with multiple calls to this tool, rather than multiple messages with a single call each.`; -export const EditTool = tool({ +export const EditTool = Tool.define({ name: "edit", description: DESCRIPTION, parameters: z.object({ @@ -136,14 +136,20 @@ export const EditTool = tool({ // Handle different operations based on parameters if (params.old_string === "") { - return createNewFile(filePath, params.new_string); + return { + output: createNewFile(filePath, params.new_string), + }; } if (params.new_string === "") { - return deleteContent(filePath, params.old_string); + return { + output: deleteContent(filePath, params.old_string), + }; } - return replaceContent(filePath, params.old_string, params.new_string); + return { + output: replaceContent(filePath, params.old_string, params.new_string), + }; }, }); diff --git a/js/src/tool/tool.ts b/js/src/tool/tool.ts index 08ab935b3..748025707 100644 --- a/js/src/tool/tool.ts +++ b/js/src/tool/tool.ts @@ -1,28 +1,49 @@ -import { type Tool, tool as AITool } from "ai"; +import { tool, type Tool as AITool } from "ai"; import { Log } from "../util/log"; const log = Log.create({ service: "tool" }); -export function tool<Params, Result>( - tool: Tool<Params, Result> & { - name: string; - }, -) { - return { - [tool.name]: AITool({ - ...tool, - execute: async (params, opts) => { - log.info("invoking", { - id: opts.toolCallId, - name: tool.name, - ...params, - }); - try { - return tool.execute!(params, opts); - } catch (e: any) { - return "An error occurred: " + e.toString(); - } - }, - }), - }; +export namespace Tool { + export interface Metadata { + properties: Record<string, any>; + time: { + start: number; + end: number; + }; + } + export function define<Params, Output>( + input: AITool<Params, { metadata?: any; output: Output }> & { + name: string; + }, + ) { + return { + [input.name]: tool({ + ...input, + execute: async (params, opts) => { + log.info("invoking", { + id: opts.toolCallId, + name: input.name, + ...params, + }); + try { + const start = Date.now(); + const result = await input.execute!(params, opts); + const metadata: Metadata = { + properties: result.metadata, + time: { + start, + end: Date.now(), + }, + }; + return { + metadata, + output: result.output, + }; + } catch (e: any) { + return "An error occurred: " + e.toString(); + } + }, + }), + }; + } } diff --git a/js/src/tool/view.ts b/js/src/tool/view.ts index 5e4223bef..ba6fabbfa 100644 --- a/js/src/tool/view.ts +++ b/js/src/tool/view.ts @@ -1,7 +1,7 @@ import { z } from "zod"; -import { tool } from "./tool"; import * as fs from "fs"; import * as path from "path"; +import { Tool } from "./tool"; const MAX_READ_SIZE = 250 * 1024; const DEFAULT_READ_LIMIT = 2000; @@ -38,7 +38,7 @@ TIPS: - For code exploration, first use Grep to find relevant files, then View to examine them - When viewing large files, use the offset parameter to read specific sections`; -export const ViewTool = tool({ +export const ViewTool = Tool.define({ name: "view", description: DESCRIPTION, parameters: z.object({ @@ -117,56 +117,12 @@ export const ViewTool = tool({ } output += "\n</file>"; - return output; + return { + output: output, + }; }, }); -function addLineNumbers(content: string, startLine: number): string { - if (!content) { - return ""; - } - - const lines = content.split("\n"); - - return lines - .map((line, i) => { - const lineNum = i + startLine; - const numStr = lineNum.toString(); - - if (numStr.length >= 6) { - return `${numStr}|${line}`; - } else { - const paddedNum = numStr.padStart(6, " "); - return `${paddedNum}|${line}`; - } - }) - .join("\n"); -} - -function readTextFile( - filePath: string, - offset: number, - limit: number, -): { content: string; lineCount: number } { - const fileContent = fs.readFileSync(filePath, "utf8"); - const allLines = fileContent.split("\n"); - let lineCount = allLines.length; - - // Get the lines we want based on offset and limit - const selectedLines = allLines - .slice(offset, offset + limit) - .map((line) => - line.length > MAX_LINE_LENGTH - ? line.substring(0, MAX_LINE_LENGTH) + "..." - : line, - ); - - return { - content: selectedLines.join("\n"), - lineCount, - }; -} - function isImageFile(filePath: string): string | false { const ext = path.extname(filePath).toLowerCase(); switch (ext) { |
