mirror of
https://github.com/aljazceru/opencode.git
synced 2026-01-06 17:34:58 +01:00
tool meta
This commit is contained in:
@@ -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"),
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user