Compare commits

...

5 Commits

Author SHA1 Message Date
Evan 1ad72236e4 Cline.ts - Factor out saveApiConversationHistory [2/8] (#2357)
* factor out saveApiConversationHistory

* changeset

* refactor out getSavedApiConversationHistory

* changeset

* delete extra changeset
2025-03-20 18:08:13 -07:00
Marlon Monroy 6d6ab2fbb3 Merge branch 'main' into move-ensureTaskDirectoryExists-from-Cline-file 2025-03-20 17:31:22 -07:00
celestial-vault eea2c97835 changeset 2025-03-20 13:27:25 -07:00
celestial-vault cc67a77759 merge conflicts 2025-03-20 13:25:44 -07:00
celestial-vault 3d33834ce5 refactor out ensureTaskDirectoryExists 2025-03-20 13:21:58 -07:00
4 changed files with 75 additions and 36 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
refactor
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
refactor
+22 -36
View File
@@ -66,6 +66,7 @@ import { DEFAULT_LANGUAGE_SETTINGS, getLanguageKey, LanguageDisplay, LanguageKey
import { telemetryService } from "../services/telemetry/TelemetryService"
import pTimeout from "p-timeout"
import { GlobalFileNames } from "../global-constants"
import { ensureTaskDirectoryExists, getSavedApiConversationHistory, saveApiConversationHistory } from "./messages-io"
const cwd = vscode.workspace.workspaceFolders?.map((folder) => folder.uri.fsPath).at(0) ?? path.join(os.homedir(), "Desktop") // may or may not exist but fs checking existence would immediately ask for permission which would be bad UX, need to come up with a better solution
@@ -178,52 +179,29 @@ export class Cline {
// Storing task to disk for history
private async ensureTaskDirectoryExists(): Promise<string> {
const globalStoragePath = this.providerRef.deref()?.context.globalStorageUri.fsPath
if (!globalStoragePath) {
throw new Error("Global storage uri is invalid")
}
const taskDir = path.join(globalStoragePath, "tasks", this.taskId)
await fs.mkdir(taskDir, { recursive: true })
return taskDir
}
private async getSavedApiConversationHistory(): Promise<Anthropic.MessageParam[]> {
const filePath = path.join(await this.ensureTaskDirectoryExists(), GlobalFileNames.apiConversationHistory)
const fileExists = await fileExistsAtPath(filePath)
if (fileExists) {
return JSON.parse(await fs.readFile(filePath, "utf8"))
}
return []
}
private async addToApiConversationHistory(message: Anthropic.MessageParam) {
this.apiConversationHistory.push(message)
await this.saveApiConversationHistory()
const globalStoragePath = this.providerRef.deref()?.context.globalStorageUri.fsPath
const taskId = this.taskId
await saveApiConversationHistory(globalStoragePath, taskId, this.apiConversationHistory)
}
private async overwriteApiConversationHistory(newHistory: Anthropic.MessageParam[]) {
this.apiConversationHistory = newHistory
await this.saveApiConversationHistory()
}
private async saveApiConversationHistory() {
try {
const filePath = path.join(await this.ensureTaskDirectoryExists(), GlobalFileNames.apiConversationHistory)
await fs.writeFile(filePath, JSON.stringify(this.apiConversationHistory))
} catch (error) {
// in the off chance this fails, we don't want to stop the task
console.error("Failed to save API conversation history:", error)
}
const globalStoragePath = this.providerRef.deref()?.context.globalStorageUri.fsPath
const taskId = this.taskId
await saveApiConversationHistory(globalStoragePath, taskId, this.apiConversationHistory)
}
private async getSavedClineMessages(): Promise<ClineMessage[]> {
const filePath = path.join(await this.ensureTaskDirectoryExists(), GlobalFileNames.uiMessages)
const globalStoragePath = this.providerRef.deref()?.context.globalStorageUri.fsPath
const taskId = this.taskId
const filePath = path.join(await ensureTaskDirectoryExists(globalStoragePath, taskId), GlobalFileNames.uiMessages)
if (await fileExistsAtPath(filePath)) {
return JSON.parse(await fs.readFile(filePath, "utf8"))
} else {
// check old location
const oldPath = path.join(await this.ensureTaskDirectoryExists(), "claude_messages.json")
const oldPath = path.join(await ensureTaskDirectoryExists(globalStoragePath, taskId), "claude_messages.json")
if (await fileExistsAtPath(oldPath)) {
const data = JSON.parse(await fs.readFile(oldPath, "utf8"))
await fs.unlink(oldPath) // remove old file
@@ -249,7 +227,9 @@ export class Cline {
private async saveClineMessages() {
try {
const taskDir = await this.ensureTaskDirectoryExists()
const globalStoragePath = this.providerRef.deref()?.context.globalStorageUri.fsPath
const taskId = this.taskId
const taskDir = await ensureTaskDirectoryExists(globalStoragePath, taskId)
const filePath = path.join(taskDir, GlobalFileNames.uiMessages)
await fs.writeFile(filePath, JSON.stringify(this.clineMessages))
// combined as they are in ChatView
@@ -870,7 +850,10 @@ export class Cline {
// Now present the cline messages to the user and ask if they want to resume (NOTE: we ran into a bug before where the apiconversationhistory wouldnt be initialized when opening a old task, and it was because we were waiting for resume)
// This is important in case the user deletes messages without resuming the task first
this.apiConversationHistory = await this.getSavedApiConversationHistory()
const globalStoragePath = this.providerRef.deref()?.context.globalStorageUri.fsPath
const taskId = this.taskId
this.apiConversationHistory = await getSavedApiConversationHistory(globalStoragePath, taskId)
const lastClineMessage = this.clineMessages
.slice()
@@ -907,7 +890,10 @@ export class Cline {
// need to make sure that the api conversation history can be resumed by the api, even if it goes out of sync with cline messages
const existingApiConversationHistory: Anthropic.Messages.MessageParam[] = await this.getSavedApiConversationHistory()
const existingApiConversationHistory: Anthropic.Messages.MessageParam[] = await getSavedApiConversationHistory(
globalStoragePath,
taskId,
)
// if the last message is an assistant message, we need to check if there's tool use since every tool use has to have a tool response
// if there's no tool use and only a text block, then we can just add a user message
+43
View File
@@ -0,0 +1,43 @@
import fs from "fs/promises"
import path from "path"
import { GlobalFileNames } from "../global-constants"
import Anthropic from "@anthropic-ai/sdk"
import { fileExistsAtPath } from "../utils/fs"
export async function ensureTaskDirectoryExists(globalStoragePath: string | undefined, taskId: string): Promise<string> {
if (!globalStoragePath) {
throw new Error("Global storage uri is invalid")
}
const taskDir = path.join(globalStoragePath, "tasks", taskId)
await fs.mkdir(taskDir, { recursive: true })
return taskDir
}
export async function saveApiConversationHistory(
globalStoragePath: string | undefined,
taskId: string,
apiConversationHistory: Anthropic.MessageParam[],
) {
try {
const filePath = path.join(
await ensureTaskDirectoryExists(globalStoragePath, taskId),
GlobalFileNames.apiConversationHistory,
)
await fs.writeFile(filePath, JSON.stringify(apiConversationHistory))
} catch (error) {
// in the off chance this fails, we don't want to stop the task
console.error("Failed to save API conversation history:", error)
}
}
export async function getSavedApiConversationHistory(
globalStoragePath: string | undefined,
taskId: string,
): Promise<Anthropic.MessageParam[]> {
const filePath = path.join(await ensureTaskDirectoryExists(globalStoragePath, taskId), GlobalFileNames.apiConversationHistory)
const fileExists = await fileExistsAtPath(filePath)
if (fileExists) {
return JSON.parse(await fs.readFile(filePath, "utf8"))
}
return []
}