mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-31 22:32:28 +00:00
fix: ensure that tool attachments arent sent as user messages (#8944)
This commit is contained in:
@@ -1,7 +1,14 @@
|
||||
import { BusEvent } from "@/bus/bus-event"
|
||||
import z from "zod"
|
||||
import { NamedError } from "@opencode-ai/util/error"
|
||||
import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessage, type UIMessage } from "ai"
|
||||
import {
|
||||
APICallError,
|
||||
convertToModelMessages,
|
||||
LoadAPIKeyError,
|
||||
type ModelMessage,
|
||||
type ToolSet,
|
||||
type UIMessage,
|
||||
} from "ai"
|
||||
import { Identifier } from "../id/id"
|
||||
import { LSP } from "../lsp"
|
||||
import { Snapshot } from "@/snapshot"
|
||||
@@ -432,7 +439,7 @@ export namespace MessageV2 {
|
||||
})
|
||||
export type WithParts = z.infer<typeof WithParts>
|
||||
|
||||
export function toModelMessage(input: WithParts[]): ModelMessage[] {
|
||||
export function toModelMessage(input: WithParts[], options?: { tools?: ToolSet }): ModelMessage[] {
|
||||
const result: UIMessage[] = []
|
||||
|
||||
for (const msg of input) {
|
||||
@@ -503,30 +510,14 @@ export namespace MessageV2 {
|
||||
})
|
||||
if (part.type === "tool") {
|
||||
if (part.state.status === "completed") {
|
||||
if (part.state.attachments?.length) {
|
||||
result.push({
|
||||
id: Identifier.ascending("message"),
|
||||
role: "user",
|
||||
parts: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Tool ${part.tool} returned an attachment:`,
|
||||
},
|
||||
...part.state.attachments.map((attachment) => ({
|
||||
type: "file" as const,
|
||||
url: attachment.url,
|
||||
mediaType: attachment.mime,
|
||||
filename: attachment.filename,
|
||||
})),
|
||||
],
|
||||
})
|
||||
}
|
||||
assistantMessage.parts.push({
|
||||
type: ("tool-" + part.tool) as `tool-${string}`,
|
||||
state: "output-available",
|
||||
toolCallId: part.callID,
|
||||
input: part.state.input,
|
||||
output: part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output,
|
||||
output: part.state.time.compacted
|
||||
? { output: "[Old tool result content cleared]" }
|
||||
: { output: part.state.output, attachments: part.state.attachments },
|
||||
callProviderMetadata: part.metadata,
|
||||
})
|
||||
}
|
||||
@@ -565,7 +556,10 @@ export namespace MessageV2 {
|
||||
}
|
||||
}
|
||||
|
||||
return convertToModelMessages(result.filter((msg) => msg.parts.some((part) => part.type !== "step-start")))
|
||||
return convertToModelMessages(
|
||||
result.filter((msg) => msg.parts.some((part) => part.type !== "step-start")),
|
||||
{ tools: options?.tools },
|
||||
)
|
||||
}
|
||||
|
||||
export const stream = fn(Identifier.schema("session"), async function* (sessionID) {
|
||||
|
||||
@@ -597,7 +597,7 @@ export namespace SessionPrompt {
|
||||
sessionID,
|
||||
system: [...(await SystemPrompt.environment()), ...(await SystemPrompt.custom())],
|
||||
messages: [
|
||||
...MessageV2.toModelMessage(sessionMessages),
|
||||
...MessageV2.toModelMessage(sessionMessages, { tools }),
|
||||
...(isLastStep
|
||||
? [
|
||||
{
|
||||
@@ -718,8 +718,22 @@ export namespace SessionPrompt {
|
||||
},
|
||||
toModelOutput(result) {
|
||||
return {
|
||||
type: "text",
|
||||
value: result.output,
|
||||
type: "content",
|
||||
value: [
|
||||
{
|
||||
type: "text",
|
||||
text: result.output,
|
||||
},
|
||||
...(result.attachments?.map((attachment: MessageV2.FilePart) => {
|
||||
const base64 = attachment.url.startsWith("data:") ? attachment.url.split(",", 2)[1] : attachment.url
|
||||
|
||||
return {
|
||||
type: "media",
|
||||
data: base64,
|
||||
mediaType: attachment.mime,
|
||||
}
|
||||
}) ?? []),
|
||||
],
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -808,8 +822,22 @@ export namespace SessionPrompt {
|
||||
}
|
||||
item.toModelOutput = (result) => {
|
||||
return {
|
||||
type: "text",
|
||||
value: result.output,
|
||||
type: "content",
|
||||
value: [
|
||||
{
|
||||
type: "text",
|
||||
text: result.output,
|
||||
},
|
||||
...(result.attachments?.map((attachment: MessageV2.FilePart) => {
|
||||
const base64 = attachment.url.startsWith("data:") ? attachment.url.split(",", 2)[1] : attachment.url
|
||||
|
||||
return {
|
||||
type: "media",
|
||||
data: base64,
|
||||
mediaType: attachment.mime,
|
||||
}
|
||||
}) ?? []),
|
||||
],
|
||||
}
|
||||
}
|
||||
tools[key] = item
|
||||
|
||||
Reference in New Issue
Block a user