mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-31 14:22:27 +00:00
core: fix issue when switching models (mainly between providers) where past reasoning/metadata would be sent to server and cause 400 errors since they came from another account/provider
This commit is contained in:
@@ -149,7 +149,7 @@ export namespace SessionCompaction {
|
||||
tools: {},
|
||||
system: [],
|
||||
messages: [
|
||||
...MessageV2.toModelMessages(input.messages),
|
||||
...MessageV2.toModelMessages(input.messages, model),
|
||||
{
|
||||
role: "user",
|
||||
content: [
|
||||
|
||||
@@ -11,6 +11,7 @@ import { ProviderTransform } from "@/provider/transform"
|
||||
import { STATUS_CODES } from "http"
|
||||
import { iife } from "@/util/iife"
|
||||
import { type SystemError } from "bun"
|
||||
import type { Provider } from "@/provider/provider"
|
||||
|
||||
export namespace MessageV2 {
|
||||
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
|
||||
@@ -432,7 +433,7 @@ export namespace MessageV2 {
|
||||
})
|
||||
export type WithParts = z.infer<typeof WithParts>
|
||||
|
||||
export function toModelMessages(input: WithParts[]): ModelMessage[] {
|
||||
export function toModelMessages(input: WithParts[], model: Provider.Model): ModelMessage[] {
|
||||
const result: UIMessage[] = []
|
||||
|
||||
for (const msg of input) {
|
||||
@@ -476,6 +477,8 @@ export namespace MessageV2 {
|
||||
}
|
||||
|
||||
if (msg.info.role === "assistant") {
|
||||
const differentModel = `${model.providerID}/${model.api.id}` !== `${msg.info.providerID}/${msg.info.modelID}`
|
||||
|
||||
if (
|
||||
msg.info.error &&
|
||||
!(
|
||||
@@ -495,7 +498,7 @@ export namespace MessageV2 {
|
||||
assistantMessage.parts.push({
|
||||
type: "text",
|
||||
text: part.text,
|
||||
providerMetadata: part.metadata,
|
||||
...(differentModel ? {} : { providerMetadata: part.metadata }),
|
||||
})
|
||||
if (part.type === "step-start")
|
||||
assistantMessage.parts.push({
|
||||
@@ -527,7 +530,7 @@ export namespace MessageV2 {
|
||||
toolCallId: part.callID,
|
||||
input: part.state.input,
|
||||
output: part.state.time.compacted ? "[Old tool result content cleared]" : part.state.output,
|
||||
callProviderMetadata: part.metadata,
|
||||
...(differentModel ? {} : { callProviderMetadata: part.metadata }),
|
||||
})
|
||||
}
|
||||
if (part.state.status === "error")
|
||||
@@ -537,7 +540,7 @@ export namespace MessageV2 {
|
||||
toolCallId: part.callID,
|
||||
input: part.state.input,
|
||||
errorText: part.state.error,
|
||||
callProviderMetadata: part.metadata,
|
||||
...(differentModel ? {} : { callProviderMetadata: part.metadata }),
|
||||
})
|
||||
// Handle pending/running tool calls to prevent dangling tool_use blocks
|
||||
// Anthropic/Claude APIs require every tool_use to have a corresponding tool_result
|
||||
@@ -548,14 +551,14 @@ export namespace MessageV2 {
|
||||
toolCallId: part.callID,
|
||||
input: part.state.input,
|
||||
errorText: "[Tool execution was interrupted]",
|
||||
callProviderMetadata: part.metadata,
|
||||
...(differentModel ? {} : { callProviderMetadata: part.metadata }),
|
||||
})
|
||||
}
|
||||
if (part.type === "reasoning") {
|
||||
assistantMessage.parts.push({
|
||||
type: "reasoning",
|
||||
text: part.text,
|
||||
providerMetadata: part.metadata,
|
||||
...(differentModel ? {} : { providerMetadata: part.metadata }),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,7 +598,7 @@ export namespace SessionPrompt {
|
||||
sessionID,
|
||||
system: [...(await SystemPrompt.environment()), ...(await SystemPrompt.custom())],
|
||||
messages: [
|
||||
...MessageV2.toModelMessages(sessionMessages),
|
||||
...MessageV2.toModelMessages(sessionMessages, model),
|
||||
...(isLastStep
|
||||
? [
|
||||
{
|
||||
@@ -1778,18 +1778,19 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
|
||||
const agent = await Agent.get("title")
|
||||
if (!agent) return
|
||||
const model = await iife(async () => {
|
||||
if (agent.model) return await Provider.getModel(agent.model.providerID, agent.model.modelID)
|
||||
return (
|
||||
(await Provider.getSmallModel(input.providerID)) ?? (await Provider.getModel(input.providerID, input.modelID))
|
||||
)
|
||||
})
|
||||
const result = await LLM.stream({
|
||||
agent,
|
||||
user: firstRealUser.info as MessageV2.User,
|
||||
system: [],
|
||||
small: true,
|
||||
tools: {},
|
||||
model: await iife(async () => {
|
||||
if (agent.model) return await Provider.getModel(agent.model.providerID, agent.model.modelID)
|
||||
return (
|
||||
(await Provider.getSmallModel(input.providerID)) ?? (await Provider.getModel(input.providerID, input.modelID))
|
||||
)
|
||||
}),
|
||||
model,
|
||||
abort: new AbortController().signal,
|
||||
sessionID: input.session.id,
|
||||
retries: 2,
|
||||
@@ -1800,7 +1801,7 @@ NOTE: At any point in time through this workflow you should feel free to ask the
|
||||
},
|
||||
...(hasOnlySubtaskParts
|
||||
? [{ role: "user" as const, content: subtaskParts.map((p) => p.prompt).join("\n") }]
|
||||
: MessageV2.toModelMessages(contextMessages)),
|
||||
: MessageV2.toModelMessages(contextMessages, model)),
|
||||
],
|
||||
})
|
||||
const text = await result.text.catch((err) => log.error("failed to generate title", { error: err }))
|
||||
|
||||
Reference in New Issue
Block a user