mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-04-01 06:42:26 +00:00
feat: allow read tool to handle images (#3052)
This commit is contained in:
@@ -7,6 +7,8 @@ import { FileTime } from "../file/time"
|
||||
import DESCRIPTION from "./read.txt"
|
||||
import { Filesystem } from "../util/filesystem"
|
||||
import { Instance } from "../project/instance"
|
||||
import { Provider } from "../provider/provider"
|
||||
import { Identifier } from "../id/id"
|
||||
|
||||
const DEFAULT_READ_LIMIT = 2000
|
||||
const MAX_LINE_LENGTH = 2000
|
||||
@@ -23,6 +25,8 @@ export const ReadTool = Tool.define("read", {
|
||||
if (!path.isAbsolute(filepath)) {
|
||||
filepath = path.join(process.cwd(), filepath)
|
||||
}
|
||||
const title = path.relative(Instance.worktree, filepath)
|
||||
|
||||
if (!ctx.extra?.["bypassCwdCheck"] && !Filesystem.contains(Instance.directory, filepath)) {
|
||||
throw new Error(`File ${filepath} is not in the current working directory`)
|
||||
}
|
||||
@@ -48,12 +52,45 @@ export const ReadTool = Tool.define("read", {
|
||||
throw new Error(`File not found: ${filepath}`)
|
||||
}
|
||||
|
||||
const limit = params.limit ?? DEFAULT_READ_LIMIT
|
||||
const offset = params.offset || 0
|
||||
const isImage = isImageFile(filepath)
|
||||
if (isImage) throw new Error(`This is an image file of type: ${isImage}\nUse a different tool to process images`)
|
||||
const supportsImages = await (async () => {
|
||||
if (!ctx.extra?.["providerID"] || !ctx.extra?.["modelID"]) return false
|
||||
const providerID = ctx.extra["providerID"] as string
|
||||
const modelID = ctx.extra["modelID"] as string
|
||||
const model = await Provider.getModel(providerID, modelID).catch(() => undefined)
|
||||
if (!model) return false
|
||||
return model.info.modalities?.input?.includes("image") ?? false
|
||||
})()
|
||||
if (isImage) {
|
||||
if (!supportsImages) {
|
||||
throw new Error(`Failed to read image: ${filepath}, model may not be able to read images`)
|
||||
}
|
||||
const mime = file.type
|
||||
const msg = "Image read successfully"
|
||||
return {
|
||||
title,
|
||||
output: msg,
|
||||
metadata: {
|
||||
preview: msg,
|
||||
},
|
||||
attachments: [
|
||||
{
|
||||
id: Identifier.ascending("part"),
|
||||
sessionID: ctx.sessionID,
|
||||
messageID: ctx.messageID,
|
||||
type: "file",
|
||||
mime,
|
||||
url: `data:${mime};base64,${Buffer.from(await file.bytes()).toString("base64")}`,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
const isBinary = await isBinaryFile(filepath, file)
|
||||
if (isBinary) throw new Error(`Cannot read binary file: ${filepath}`)
|
||||
|
||||
const limit = params.limit ?? DEFAULT_READ_LIMIT
|
||||
const offset = params.offset || 0
|
||||
const lines = await file.text().then((text) => text.split("\n"))
|
||||
const raw = lines.slice(offset, offset + limit).map((line) => {
|
||||
return line.length > MAX_LINE_LENGTH ? line.substring(0, MAX_LINE_LENGTH) + "..." : line
|
||||
@@ -76,7 +113,7 @@ export const ReadTool = Tool.define("read", {
|
||||
FileTime.read(ctx.sessionID, filepath)
|
||||
|
||||
return {
|
||||
title: path.relative(Instance.worktree, filepath),
|
||||
title,
|
||||
output,
|
||||
metadata: {
|
||||
preview,
|
||||
|
||||
@@ -7,6 +7,6 @@ Usage:
|
||||
- You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters
|
||||
- Any lines longer than 2000 characters will be truncated
|
||||
- Results are returned using cat -n format, with line numbers starting at 1
|
||||
- This tool cannot read binary files, including images
|
||||
- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.
|
||||
- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.
|
||||
- If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.
|
||||
- You can read image files using this tool.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import z from "zod/v4"
|
||||
import type { MessageV2 } from "../session/message-v2"
|
||||
|
||||
export namespace Tool {
|
||||
interface Metadata {
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export type Context<M extends Metadata = Metadata> = {
|
||||
sessionID: string
|
||||
messageID: string
|
||||
@@ -25,6 +27,7 @@ export namespace Tool {
|
||||
title: string
|
||||
metadata: M
|
||||
output: string
|
||||
attachments?: MessageV2.FilePart[]
|
||||
}>
|
||||
}>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user