mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-31 06:12:26 +00:00
big format
This commit is contained in:
@@ -23,8 +23,13 @@ export const EditTool = Tool.define("edit", {
|
||||
parameters: z.object({
|
||||
filePath: z.string().describe("The absolute path to the file to modify"),
|
||||
oldString: z.string().describe("The text to replace"),
|
||||
newString: z.string().describe("The text to replace it with (must be different from oldString)"),
|
||||
replaceAll: z.boolean().optional().describe("Replace all occurrences of oldString (default false)"),
|
||||
newString: z
|
||||
.string()
|
||||
.describe("The text to replace it with (must be different from oldString)"),
|
||||
replaceAll: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Replace all occurrences of oldString (default false)"),
|
||||
}),
|
||||
async execute(params, ctx) {
|
||||
if (!params.filePath) {
|
||||
@@ -35,7 +40,9 @@ export const EditTool = Tool.define("edit", {
|
||||
throw new Error("oldString and newString must be different")
|
||||
}
|
||||
|
||||
const filePath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath)
|
||||
const filePath = path.isAbsolute(params.filePath)
|
||||
? params.filePath
|
||||
: path.join(Instance.directory, params.filePath)
|
||||
if (!Filesystem.contains(Instance.directory, filePath)) {
|
||||
const parentDir = path.dirname(filePath)
|
||||
await Permission.ask({
|
||||
@@ -172,7 +179,11 @@ function levenshtein(a: string, b: string): number {
|
||||
for (let i = 1; i <= a.length; i++) {
|
||||
for (let j = 1; j <= b.length; j++) {
|
||||
const cost = a[i - 1] === b[j - 1] ? 0 : 1
|
||||
matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j - 1] + cost)
|
||||
matrix[i][j] = Math.min(
|
||||
matrix[i - 1][j] + 1,
|
||||
matrix[i][j - 1] + 1,
|
||||
matrix[i - 1][j - 1] + cost,
|
||||
)
|
||||
}
|
||||
}
|
||||
return matrix[a.length][b.length]
|
||||
@@ -374,7 +385,9 @@ export const WhitespaceNormalizedReplacer: Replacer = function* (content, find)
|
||||
// Find the actual substring in the original line that matches
|
||||
const words = find.trim().split(/\s+/)
|
||||
if (words.length > 0) {
|
||||
const pattern = words.map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("\\s+")
|
||||
const pattern = words
|
||||
.map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
||||
.join("\\s+")
|
||||
try {
|
||||
const regex = new RegExp(pattern)
|
||||
const match = line.match(regex)
|
||||
@@ -612,7 +625,12 @@ export function trimDiff(diff: string): string {
|
||||
return trimmedLines.join("\n")
|
||||
}
|
||||
|
||||
export function replace(content: string, oldString: string, newString: string, replaceAll = false): string {
|
||||
export function replace(
|
||||
content: string,
|
||||
oldString: string,
|
||||
newString: string,
|
||||
replaceAll = false,
|
||||
): string {
|
||||
if (oldString === newString) {
|
||||
throw new Error("oldString and newString must be different")
|
||||
}
|
||||
|
||||
@@ -9,8 +9,14 @@ export const GrepTool = Tool.define("grep", {
|
||||
description: DESCRIPTION,
|
||||
parameters: z.object({
|
||||
pattern: z.string().describe("The regex pattern to search for in file contents"),
|
||||
path: z.string().optional().describe("The directory to search in. Defaults to the current working directory."),
|
||||
include: z.string().optional().describe('File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")'),
|
||||
path: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("The directory to search in. Defaults to the current working directory."),
|
||||
include: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")'),
|
||||
}),
|
||||
async execute(params) {
|
||||
if (!params.pattern) {
|
||||
|
||||
@@ -37,13 +37,18 @@ const LIMIT = 100
|
||||
export const ListTool = Tool.define("list", {
|
||||
description: DESCRIPTION,
|
||||
parameters: z.object({
|
||||
path: z.string().describe("The absolute path to the directory to list (must be absolute, not relative)").optional(),
|
||||
path: z
|
||||
.string()
|
||||
.describe("The absolute path to the directory to list (must be absolute, not relative)")
|
||||
.optional(),
|
||||
ignore: z.array(z.string()).describe("List of glob patterns to ignore").optional(),
|
||||
}),
|
||||
async execute(params) {
|
||||
const searchPath = path.resolve(Instance.directory, params.path || ".")
|
||||
|
||||
const ignoreGlobs = IGNORE_PATTERNS.map((p) => `!${p}*`).concat(params.ignore?.map((p) => `!${p}`) || [])
|
||||
const ignoreGlobs = IGNORE_PATTERNS.map((p) => `!${p}*`).concat(
|
||||
params.ignore?.map((p) => `!${p}`) || [],
|
||||
)
|
||||
const files = []
|
||||
for await (const file of Ripgrep.files({ cwd: searchPath, glob: ignoreGlobs })) {
|
||||
files.push(file)
|
||||
|
||||
@@ -11,7 +11,9 @@ export const LspDiagnosticTool = Tool.define("lsp_diagnostics", {
|
||||
path: z.string().describe("The path to the file to get diagnostics."),
|
||||
}),
|
||||
execute: async (args) => {
|
||||
const normalized = path.isAbsolute(args.path) ? args.path : path.join(Instance.directory, args.path)
|
||||
const normalized = path.isAbsolute(args.path)
|
||||
? args.path
|
||||
: path.join(Instance.directory, args.path)
|
||||
await LSP.touchFile(normalized, true)
|
||||
const diagnostics = await LSP.diagnostics()
|
||||
const file = diagnostics[normalized]
|
||||
|
||||
@@ -14,8 +14,13 @@ export const MultiEditTool = Tool.define("multiedit", {
|
||||
z.object({
|
||||
filePath: z.string().describe("The absolute path to the file to modify"),
|
||||
oldString: z.string().describe("The text to replace"),
|
||||
newString: z.string().describe("The text to replace it with (must be different from oldString)"),
|
||||
replaceAll: z.boolean().optional().describe("Replace all occurrences of oldString (default false)"),
|
||||
newString: z
|
||||
.string()
|
||||
.describe("The text to replace it with (must be different from oldString)"),
|
||||
replaceAll: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe("Replace all occurrences of oldString (default false)"),
|
||||
}),
|
||||
)
|
||||
.describe("Array of edit operations to perform sequentially on the file"),
|
||||
|
||||
@@ -18,7 +18,10 @@ export const ReadTool = Tool.define("read", {
|
||||
description: DESCRIPTION,
|
||||
parameters: z.object({
|
||||
filePath: z.string().describe("The path to the file to read"),
|
||||
offset: z.coerce.number().describe("The line number to start reading from (0-based)").optional(),
|
||||
offset: z.coerce
|
||||
.number()
|
||||
.describe("The line number to start reading from (0-based)")
|
||||
.optional(),
|
||||
limit: z.coerce.number().describe("The number of lines to read (defaults to 2000)").optional(),
|
||||
}),
|
||||
async execute(params, ctx) {
|
||||
@@ -53,13 +56,16 @@ export const ReadTool = Tool.define("read", {
|
||||
const suggestions = dirEntries
|
||||
.filter(
|
||||
(entry) =>
|
||||
entry.toLowerCase().includes(base.toLowerCase()) || base.toLowerCase().includes(entry.toLowerCase()),
|
||||
entry.toLowerCase().includes(base.toLowerCase()) ||
|
||||
base.toLowerCase().includes(entry.toLowerCase()),
|
||||
)
|
||||
.map((entry) => path.join(dir, entry))
|
||||
.slice(0, 3)
|
||||
|
||||
if (suggestions.length > 0) {
|
||||
throw new Error(`File not found: ${filepath}\n\nDid you mean one of these?\n${suggestions.join("\n")}`)
|
||||
throw new Error(
|
||||
`File not found: ${filepath}\n\nDid you mean one of these?\n${suggestions.join("\n")}`,
|
||||
)
|
||||
}
|
||||
|
||||
throw new Error(`File not found: ${filepath}`)
|
||||
|
||||
@@ -24,7 +24,12 @@ export namespace ToolRegistry {
|
||||
const glob = new Bun.Glob("tool/*.{js,ts}")
|
||||
|
||||
for (const dir of await Config.directories()) {
|
||||
for await (const match of glob.scan({ cwd: dir, absolute: true, followSymlinks: true, dot: true })) {
|
||||
for await (const match of glob.scan({
|
||||
cwd: dir,
|
||||
absolute: true,
|
||||
followSymlinks: true,
|
||||
dot: true,
|
||||
})) {
|
||||
const namespace = path.basename(match, path.extname(match))
|
||||
const mod = await import(match)
|
||||
for (const [id, def] of Object.entries<ToolDefinition>(mod)) {
|
||||
|
||||
@@ -14,7 +14,10 @@ export const TaskTool = Tool.define("task", async () => {
|
||||
const description = DESCRIPTION.replace(
|
||||
"{agents}",
|
||||
agents
|
||||
.map((a) => `- ${a.name}: ${a.description ?? "This subagent should only be called manually by the user."}`)
|
||||
.map(
|
||||
(a) =>
|
||||
`- ${a.name}: ${a.description ?? "This subagent should only be called manually by the user."}`,
|
||||
)
|
||||
.join("\n"),
|
||||
)
|
||||
return {
|
||||
@@ -26,7 +29,8 @@ export const TaskTool = Tool.define("task", async () => {
|
||||
}),
|
||||
async execute(params, ctx) {
|
||||
const agent = await Agent.get(params.subagent_type)
|
||||
if (!agent) throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`)
|
||||
if (!agent)
|
||||
throw new Error(`Unknown agent type: ${params.subagent_type} is not a valid agent type`)
|
||||
const session = await Session.create({
|
||||
parentID: ctx.sessionID,
|
||||
title: params.description + ` (@${agent.name} subagent)`,
|
||||
@@ -91,7 +95,9 @@ export const TaskTool = Tool.define("task", async () => {
|
||||
let all
|
||||
all = await Session.messages(session.id)
|
||||
all = all.filter((x) => x.info.role === "assistant")
|
||||
all = all.flatMap((msg) => msg.parts.filter((x: any) => x.type === "tool") as MessageV2.ToolPart[])
|
||||
all = all.flatMap(
|
||||
(msg) => msg.parts.filter((x: any) => x.type === "tool") as MessageV2.ToolPart[],
|
||||
)
|
||||
return {
|
||||
title: params.description,
|
||||
metadata: {
|
||||
|
||||
@@ -48,13 +48,15 @@ export const WebFetchTool = Tool.define("webfetch", {
|
||||
let acceptHeader = "*/*"
|
||||
switch (params.format) {
|
||||
case "markdown":
|
||||
acceptHeader = "text/markdown;q=1.0, text/x-markdown;q=0.9, text/plain;q=0.8, text/html;q=0.7, */*;q=0.1"
|
||||
acceptHeader =
|
||||
"text/markdown;q=1.0, text/x-markdown;q=0.9, text/plain;q=0.8, text/html;q=0.7, */*;q=0.1"
|
||||
break
|
||||
case "text":
|
||||
acceptHeader = "text/plain;q=1.0, text/markdown;q=0.9, text/html;q=0.8, */*;q=0.1"
|
||||
break
|
||||
case "html":
|
||||
acceptHeader = "text/html;q=1.0, application/xhtml+xml;q=0.9, text/plain;q=0.8, text/markdown;q=0.7, */*;q=0.1"
|
||||
acceptHeader =
|
||||
"text/html;q=1.0, application/xhtml+xml;q=0.9, text/plain;q=0.8, text/markdown;q=0.7, */*;q=0.1"
|
||||
break
|
||||
default:
|
||||
acceptHeader =
|
||||
@@ -158,7 +160,9 @@ async function extractTextFromHTML(html: string) {
|
||||
.on("*", {
|
||||
element(element) {
|
||||
// Reset skip flag when entering other elements
|
||||
if (!["script", "style", "noscript", "iframe", "object", "embed"].includes(element.tagName)) {
|
||||
if (
|
||||
!["script", "style", "noscript", "iframe", "object", "embed"].includes(element.tagName)
|
||||
) {
|
||||
skipContent = false
|
||||
}
|
||||
},
|
||||
|
||||
@@ -15,10 +15,14 @@ export const WriteTool = Tool.define("write", {
|
||||
description: DESCRIPTION,
|
||||
parameters: z.object({
|
||||
content: z.string().describe("The content to write to the file"),
|
||||
filePath: z.string().describe("The absolute path to the file to write (must be absolute, not relative)"),
|
||||
filePath: z
|
||||
.string()
|
||||
.describe("The absolute path to the file to write (must be absolute, not relative)"),
|
||||
}),
|
||||
async execute(params, ctx) {
|
||||
const filepath = path.isAbsolute(params.filePath) ? params.filePath : path.join(Instance.directory, params.filePath)
|
||||
const filepath = path.isAbsolute(params.filePath)
|
||||
? params.filePath
|
||||
: path.join(Instance.directory, params.filePath)
|
||||
if (!Filesystem.contains(Instance.directory, filepath)) {
|
||||
const parentDir = path.dirname(filepath)
|
||||
await Permission.ask({
|
||||
|
||||
Reference in New Issue
Block a user