Refactor ClaudeDev

This commit is contained in:
Saoud Rizwan
2024-10-05 23:24:50 -04:00
parent fe052d28df
commit d235c2d1c5
2 changed files with 34 additions and 34 deletions

View File

@@ -51,7 +51,7 @@ type UserContent = Array<
Anthropic.TextBlockParam | Anthropic.ImageBlockParam | Anthropic.ToolUseBlockParam | Anthropic.ToolResultBlockParam Anthropic.TextBlockParam | Anthropic.ImageBlockParam | Anthropic.ToolUseBlockParam | Anthropic.ToolResultBlockParam
> >
export class ClaudeDev { export class Cline {
readonly taskId: string readonly taskId: string
api: ApiHandler api: ApiHandler
private terminalManager: TerminalManager private terminalManager: TerminalManager
@@ -1731,7 +1731,7 @@ export class ClaudeDev {
await abortStream("streaming_failed", error.message ?? JSON.stringify(serializeError(error), null, 2)) await abortStream("streaming_failed", error.message ?? JSON.stringify(serializeError(error), null, 2))
const history = await this.providerRef.deref()?.getTaskWithId(this.taskId) const history = await this.providerRef.deref()?.getTaskWithId(this.taskId)
if (history) { if (history) {
await this.providerRef.deref()?.initClaudeDevWithHistoryItem(history.historyItem) await this.providerRef.deref()?.initClineWithHistoryItem(history.historyItem)
// await this.providerRef.deref()?.postStateToWebview() // await this.providerRef.deref()?.postStateToWebview()
} }
} }

View File

@@ -1,6 +1,6 @@
import { Anthropic } from "@anthropic-ai/sdk" import { Anthropic } from "@anthropic-ai/sdk"
import * as vscode from "vscode" import * as vscode from "vscode"
import { ClaudeDev } from "../ClaudeDev" import { Cline } from "../ClaudeDev"
import { ApiProvider, ModelInfo } from "../../shared/api" import { ApiProvider, ModelInfo } from "../../shared/api"
import { ExtensionMessage } from "../../shared/ExtensionMessage" import { ExtensionMessage } from "../../shared/ExtensionMessage"
import { WebviewMessage } from "../../shared/WebviewMessage" import { WebviewMessage } from "../../shared/WebviewMessage"
@@ -67,7 +67,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
private static activeInstances: Set<ClineProvider> = new Set() private static activeInstances: Set<ClineProvider> = new Set()
private disposables: vscode.Disposable[] = [] private disposables: vscode.Disposable[] = []
private view?: vscode.WebviewView | vscode.WebviewPanel private view?: vscode.WebviewView | vscode.WebviewPanel
private claudeDev?: ClaudeDev private cline?: Cline
private workspaceTracker?: WorkspaceTracker private workspaceTracker?: WorkspaceTracker
private latestAnnouncementId = "sep-21-2024" // update to some unique identifier when we add a new announcement private latestAnnouncementId = "sep-21-2024" // update to some unique identifier when we add a new announcement
@@ -208,16 +208,16 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.outputChannel.appendLine("Webview view resolved") this.outputChannel.appendLine("Webview view resolved")
} }
async initClaudeDevWithTask(task?: string, images?: string[]) { async initClineWithTask(task?: string, images?: string[]) {
await this.clearTask() // ensures that an exising task doesn't exist before starting a new one, although this shouldn't be possible since user must clear task before starting a new one await this.clearTask() // ensures that an exising task doesn't exist before starting a new one, although this shouldn't be possible since user must clear task before starting a new one
const { apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState() const { apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState()
this.claudeDev = new ClaudeDev(this, apiConfiguration, customInstructions, alwaysAllowReadOnly, task, images) this.cline = new Cline(this, apiConfiguration, customInstructions, alwaysAllowReadOnly, task, images)
} }
async initClaudeDevWithHistoryItem(historyItem: HistoryItem) { async initClineWithHistoryItem(historyItem: HistoryItem) {
await this.clearTask() await this.clearTask()
const { apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState() const { apiConfiguration, customInstructions, alwaysAllowReadOnly } = await this.getState()
this.claudeDev = new ClaudeDev( this.cline = new Cline(
this, this,
apiConfiguration, apiConfiguration,
customInstructions, customInstructions,
@@ -347,8 +347,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
// You can send any JSON serializable data. // You can send any JSON serializable data.
// Could also do this in extension .ts // Could also do this in extension .ts
//this.postMessageToWebview({ type: "text", text: `Extension: ${Date.now()}` }) //this.postMessageToWebview({ type: "text", text: `Extension: ${Date.now()}` })
// initializing new instance of ClaudeDev will make sure that any agentically running promises in old instance don't affect our new task. this essentially creates a fresh slate for the new task // initializing new instance of Cline will make sure that any agentically running promises in old instance don't affect our new task. this essentially creates a fresh slate for the new task
await this.initClaudeDevWithTask(message.text, message.images) await this.initClineWithTask(message.text, message.images)
break break
case "apiConfiguration": case "apiConfiguration":
if (message.apiConfiguration) { if (message.apiConfiguration) {
@@ -396,8 +396,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.updateGlobalState("azureApiVersion", azureApiVersion) await this.updateGlobalState("azureApiVersion", azureApiVersion)
await this.updateGlobalState("openRouterModelId", openRouterModelId) await this.updateGlobalState("openRouterModelId", openRouterModelId)
await this.updateGlobalState("openRouterModelInfo", openRouterModelInfo) await this.updateGlobalState("openRouterModelInfo", openRouterModelInfo)
if (this.claudeDev) { if (this.cline) {
this.claudeDev.api = buildApiHandler(message.apiConfiguration) this.cline.api = buildApiHandler(message.apiConfiguration)
} }
} }
await this.postStateToWebview() await this.postStateToWebview()
@@ -407,13 +407,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
break break
case "alwaysAllowReadOnly": case "alwaysAllowReadOnly":
await this.updateGlobalState("alwaysAllowReadOnly", message.bool ?? undefined) await this.updateGlobalState("alwaysAllowReadOnly", message.bool ?? undefined)
if (this.claudeDev) { if (this.cline) {
this.claudeDev.alwaysAllowReadOnly = message.bool ?? false this.cline.alwaysAllowReadOnly = message.bool ?? false
} }
await this.postStateToWebview() await this.postStateToWebview()
break break
case "askResponse": case "askResponse":
this.claudeDev?.handleWebviewAskResponse(message.askResponse!, message.text, message.images) this.cline?.handleWebviewAskResponse(message.askResponse!, message.text, message.images)
break break
case "clearTask": case "clearTask":
// newTask will start a new task with a given task text, while clear task resets the current session and allows for a new task to be started // newTask will start a new task with a given task text, while clear task resets the current session and allows for a new task to be started
@@ -429,7 +429,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.postMessageToWebview({ type: "selectedImages", images }) await this.postMessageToWebview({ type: "selectedImages", images })
break break
case "exportCurrentTask": case "exportCurrentTask":
const currentTaskId = this.claudeDev?.taskId const currentTaskId = this.cline?.taskId
if (currentTaskId) { if (currentTaskId) {
this.exportTaskWithId(currentTaskId) this.exportTaskWithId(currentTaskId)
} }
@@ -463,13 +463,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
openMention(message.text) openMention(message.text)
break break
case "cancelTask": case "cancelTask":
if (this.claudeDev) { if (this.cline) {
const { historyItem } = await this.getTaskWithId(this.claudeDev.taskId) const { historyItem } = await this.getTaskWithId(this.cline.taskId)
this.claudeDev.abortTask() this.cline.abortTask()
await pWaitFor(() => this.claudeDev === undefined || this.claudeDev.didFinishAborting, { await pWaitFor(() => this.cline === undefined || this.cline.didFinishAborting, {
timeout: 3_000, timeout: 3_000,
}) })
await this.initClaudeDevWithHistoryItem(historyItem) // clears task again, so we need to abortTask manually above await this.initClineWithHistoryItem(historyItem) // clears task again, so we need to abortTask manually above
// await this.postStateToWebview() // new claude dev instance will post state when it's ready. having this here sent an empty messages array to webview leading to virtuoso having to reload the entire list // await this.postStateToWebview() // new claude dev instance will post state when it's ready. having this here sent an empty messages array to webview leading to virtuoso having to reload the entire list
} }
@@ -486,8 +486,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
async updateCustomInstructions(instructions?: string) { async updateCustomInstructions(instructions?: string) {
// User may be clearing the field // User may be clearing the field
await this.updateGlobalState("customInstructions", instructions || undefined) await this.updateGlobalState("customInstructions", instructions || undefined)
if (this.claudeDev) { if (this.cline) {
this.claudeDev.customInstructions = instructions || undefined this.cline.customInstructions = instructions || undefined
} }
await this.postStateToWebview() await this.postStateToWebview()
} }
@@ -531,8 +531,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.updateGlobalState("apiProvider", openrouter) await this.updateGlobalState("apiProvider", openrouter)
await this.storeSecret("openRouterApiKey", apiKey) await this.storeSecret("openRouterApiKey", apiKey)
await this.postStateToWebview() await this.postStateToWebview()
if (this.claudeDev) { if (this.cline) {
this.claudeDev.api = buildApiHandler({ apiProvider: openrouter, openRouterApiKey: apiKey }) this.cline.api = buildApiHandler({ apiProvider: openrouter, openRouterApiKey: apiKey })
} }
// await this.postMessageToWebview({ type: "action", action: "settingsButtonTapped" }) // bad ux if user is on welcome // await this.postMessageToWebview({ type: "action", action: "settingsButtonTapped" }) // bad ux if user is on welcome
} }
@@ -678,10 +678,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
} }
async showTaskWithId(id: string) { async showTaskWithId(id: string) {
if (id !== this.claudeDev?.taskId) { if (id !== this.cline?.taskId) {
// non-current task // non-current task
const { historyItem } = await this.getTaskWithId(id) const { historyItem } = await this.getTaskWithId(id)
await this.initClaudeDevWithHistoryItem(historyItem) // clears existing task await this.initClineWithHistoryItem(historyItem) // clears existing task
} }
await this.postMessageToWebview({ type: "action", action: "chatButtonTapped" }) await this.postMessageToWebview({ type: "action", action: "chatButtonTapped" })
} }
@@ -692,7 +692,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
} }
async deleteTaskWithId(id: string) { async deleteTaskWithId(id: string) {
if (id === this.claudeDev?.taskId) { if (id === this.cline?.taskId) {
await this.clearTask() await this.clearTask()
} }
@@ -736,15 +736,15 @@ export class ClineProvider implements vscode.WebviewViewProvider {
customInstructions, customInstructions,
alwaysAllowReadOnly, alwaysAllowReadOnly,
uriScheme: vscode.env.uriScheme, uriScheme: vscode.env.uriScheme,
claudeMessages: this.claudeDev?.claudeMessages || [], claudeMessages: this.cline?.claudeMessages || [],
taskHistory: (taskHistory || []).filter((item) => item.ts && item.task).sort((a, b) => b.ts - a.ts), taskHistory: (taskHistory || []).filter((item) => item.ts && item.task).sort((a, b) => b.ts - a.ts),
shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId, shouldShowAnnouncement: lastShownAnnouncementId !== this.latestAnnouncementId,
} }
} }
async clearTask() { async clearTask() {
this.claudeDev?.abortTask() this.cline?.abortTask()
this.claudeDev = undefined // removes reference to it, so once promises end it will be garbage collected this.cline = undefined // removes reference to it, so once promises end it will be garbage collected
} }
// Caching mechanism to keep track of webview messages + API conversation history per provider instance // Caching mechanism to keep track of webview messages + API conversation history per provider instance
@@ -1004,9 +1004,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
for (const key of secretKeys) { for (const key of secretKeys) {
await this.storeSecret(key, undefined) await this.storeSecret(key, undefined)
} }
if (this.claudeDev) { if (this.cline) {
this.claudeDev.abortTask() this.cline.abortTask()
this.claudeDev = undefined this.cline = undefined
} }
vscode.window.showInformationMessage("State reset") vscode.window.showInformationMessage("State reset")
await this.postStateToWebview() await this.postStateToWebview()