fix: preserve model names in exported task history

- Add modelId field to ClineMessage type to store model ID with each message
- Update Task.ts to capture and store model ID when messages are created
- Update getEnvironmentDetails to accept optional model ID parameter
- Ensures exported task history shows correct model names for each message

Fixes #9580
This commit is contained in:
Roo Code 2025-11-25 16:09:10 +00:00
parent a66cd8a841
commit f05c2123f2
3 changed files with 41 additions and 5 deletions

View file

@ -227,6 +227,7 @@ export const clineMessageSchema = z.object({
isProtected: z.boolean().optional(),
apiProtocol: z.union([z.literal("openai"), z.literal("anthropic")]).optional(),
isAnswered: z.boolean().optional(),
modelId: z.string().optional(), // Store the model ID used when creating this message
})
export type ClineMessage = z.infer<typeof clineMessageSchema>

View file

@ -22,7 +22,11 @@ import { getGitStatus } from "../../utils/git"
import { Task } from "../task/Task"
import { formatReminderSection } from "./reminder"
export async function getEnvironmentDetails(cline: Task, includeFileDetails: boolean = false) {
export async function getEnvironmentDetails(
cline: Task,
includeFileDetails: boolean = false,
overrideModelId?: string,
) {
let details = ""
const clineProvider = cline.providerRef.deref()
@ -215,7 +219,9 @@ export async function getEnvironmentDetails(cline: Task, includeFileDetails: boo
details += `\n\n# Current Cost\n${totalCost !== null ? `$${totalCost.toFixed(2)}` : "(Not available)"}`
}
const { id: modelId } = cline.api.getModel()
// Use the override model ID if provided (e.g., for preserving historical model in exports)
// Otherwise use the current model from the task
const modelId = overrideModelId || cline.api.getModel().id
// Add current mode and any mode-specific warnings.
const {

View file

@ -798,6 +798,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
}
private async addToClineMessages(message: ClineMessage) {
// Add the current model ID to the message if not already present
if (!message.modelId) {
message.modelId = this.api.getModel().id
}
this.clineMessages.push(message)
const provider = this.providerRef.deref()
await provider?.postStateToWebview()
@ -941,7 +945,15 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
askTs = Date.now()
this.lastMessageTs = askTs
console.log(`Task#ask: new partial ask -> ${type} @ ${askTs}`)
await this.addToClineMessages({ ts: askTs, type: "ask", ask: type, text, partial, isProtected })
await this.addToClineMessages({
ts: askTs,
type: "ask",
ask: type,
text,
partial,
isProtected,
modelId: this.api.getModel().id,
})
// console.log("Task#ask: current ask promise was ignored (#2)")
throw new Error("Current ask promise was ignored (#2)")
}
@ -981,7 +993,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
askTs = Date.now()
console.log(`Task#ask: new complete ask -> ${type} @ ${askTs}`)
this.lastMessageTs = askTs
await this.addToClineMessages({ ts: askTs, type: "ask", ask: type, text, isProtected })
await this.addToClineMessages({
ts: askTs,
type: "ask",
ask: type,
text,
isProtected,
modelId: this.api.getModel().id,
})
}
}
} else {
@ -992,7 +1011,14 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
askTs = Date.now()
console.log(`Task#ask: new complete ask -> ${type} @ ${askTs}`)
this.lastMessageTs = askTs
await this.addToClineMessages({ ts: askTs, type: "ask", ask: type, text, isProtected })
await this.addToClineMessages({
ts: askTs,
type: "ask",
ask: type,
text,
isProtected,
modelId: this.api.getModel().id,
})
}
let timeouts: NodeJS.Timeout[] = []
@ -1364,6 +1390,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
images,
partial,
contextCondense,
modelId: this.api.getModel().id,
})
}
} else {
@ -1401,6 +1428,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
text,
images,
contextCondense,
modelId: this.api.getModel().id,
})
}
}
@ -1424,6 +1452,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
images,
checkpoint,
contextCondense,
modelId: this.api.getModel().id,
})
}