mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-11 22:51:26 +00:00
Rename Cline to Task (#3352)
This commit is contained in:
parent
0069a2873d
commit
6af9fad180
26 changed files with 305 additions and 321 deletions
|
|
@ -31,7 +31,7 @@ import { checkpointSave } from "../checkpoints"
|
|||
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { validateToolUse } from "../tools/validateToolUse"
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
|
||||
/**
|
||||
* Processes and presents assistant message content to the user interface.
|
||||
|
|
@ -50,7 +50,7 @@ import { Cline } from "../Cline"
|
|||
* as it becomes available.
|
||||
*/
|
||||
|
||||
export async function presentAssistantMessage(cline: Cline) {
|
||||
export async function presentAssistantMessage(cline: Task) {
|
||||
if (cline.abort) {
|
||||
throw new Error(`[Cline#presentAssistantMessage] task ${cline.taskId}.${cline.instanceId} aborted`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import pWaitFor from "p-wait-for"
|
||||
import * as vscode from "vscode"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
|
||||
import { getWorkspacePath } from "../../utils/path"
|
||||
|
||||
|
|
@ -13,7 +13,7 @@ import { DIFF_VIEW_URI_SCHEME } from "../../integrations/editor/DiffViewProvider
|
|||
import { telemetryService } from "../../services/telemetry/TelemetryService"
|
||||
import { CheckpointServiceOptions, RepoPerTaskCheckpointService } from "../../services/checkpoints"
|
||||
|
||||
export function getCheckpointService(cline: Cline) {
|
||||
export function getCheckpointService(cline: Task) {
|
||||
if (!cline.enableCheckpoints) {
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -124,7 +124,7 @@ export function getCheckpointService(cline: Cline) {
|
|||
}
|
||||
|
||||
async function getInitializedCheckpointService(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
{ interval = 250, timeout = 15_000 }: { interval?: number; timeout?: number } = {},
|
||||
) {
|
||||
const service = getCheckpointService(cline)
|
||||
|
|
@ -148,7 +148,7 @@ async function getInitializedCheckpointService(
|
|||
}
|
||||
}
|
||||
|
||||
export async function checkpointSave(cline: Cline) {
|
||||
export async function checkpointSave(cline: Task) {
|
||||
const service = getCheckpointService(cline)
|
||||
|
||||
if (!service) {
|
||||
|
|
@ -177,7 +177,7 @@ export type CheckpointRestoreOptions = {
|
|||
mode: "preview" | "restore"
|
||||
}
|
||||
|
||||
export async function checkpointRestore(cline: Cline, { ts, commitHash, mode }: CheckpointRestoreOptions) {
|
||||
export async function checkpointRestore(cline: Task, { ts, commitHash, mode }: CheckpointRestoreOptions) {
|
||||
const service = await getInitializedCheckpointService(cline)
|
||||
|
||||
if (!service) {
|
||||
|
|
@ -245,10 +245,7 @@ export type CheckpointDiffOptions = {
|
|||
mode: "full" | "checkpoint"
|
||||
}
|
||||
|
||||
export async function checkpointDiff(
|
||||
cline: Cline,
|
||||
{ ts, previousCommitHash, commitHash, mode }: CheckpointDiffOptions,
|
||||
) {
|
||||
export async function checkpointDiff(cline: Task, { ts, previousCommitHash, commitHash, mode }: CheckpointDiffOptions) {
|
||||
const service = await getInitializedCheckpointService(cline)
|
||||
|
||||
if (!service) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import { ApiHandler } from "../../../api/index"
|
|||
import { ClineProvider } from "../../webview/ClineProvider"
|
||||
import { RooIgnoreController } from "../../ignore/RooIgnoreController"
|
||||
import { formatResponse } from "../../prompts/responses"
|
||||
import { Cline } from "../../Cline"
|
||||
import { Task } from "../../task/Task"
|
||||
|
||||
jest.mock("vscode", () => ({
|
||||
window: {
|
||||
|
|
@ -56,7 +56,7 @@ describe("getEnvironmentDetails", () => {
|
|||
cleanCompletedProcessQueue?: jest.Mock
|
||||
}
|
||||
|
||||
let mockCline: Partial<Cline>
|
||||
let mockCline: Partial<Task>
|
||||
let mockProvider: any
|
||||
let mockState: any
|
||||
|
||||
|
|
@ -134,7 +134,7 @@ describe("getEnvironmentDetails", () => {
|
|||
})
|
||||
|
||||
it("should return basic environment details", async () => {
|
||||
const result = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
expect(result).toContain("<environment_details>")
|
||||
expect(result).toContain("</environment_details>")
|
||||
|
|
@ -157,7 +157,7 @@ describe("getEnvironmentDetails", () => {
|
|||
})
|
||||
|
||||
it("should include file details when includeFileDetails is true", async () => {
|
||||
const result = await getEnvironmentDetails(mockCline as Cline, true)
|
||||
const result = await getEnvironmentDetails(mockCline as Task, true)
|
||||
expect(result).toContain("# Current Workspace Directory")
|
||||
expect(result).toContain("Files")
|
||||
|
||||
|
|
@ -173,14 +173,14 @@ describe("getEnvironmentDetails", () => {
|
|||
})
|
||||
|
||||
it("should not include file details when includeFileDetails is false", async () => {
|
||||
await getEnvironmentDetails(mockCline as Cline, false)
|
||||
await getEnvironmentDetails(mockCline as Task, false)
|
||||
expect(listFiles).not.toHaveBeenCalled()
|
||||
expect(formatResponse.formatFilesList).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it("should handle desktop directory specially", async () => {
|
||||
;(arePathsEqual as jest.Mock).mockReturnValue(true)
|
||||
const result = await getEnvironmentDetails(mockCline as Cline, true)
|
||||
const result = await getEnvironmentDetails(mockCline as Task, true)
|
||||
expect(result).toContain("Desktop files not shown automatically")
|
||||
expect(listFiles).not.toHaveBeenCalled()
|
||||
})
|
||||
|
|
@ -191,7 +191,7 @@ describe("getEnvironmentDetails", () => {
|
|||
"modified2.ts",
|
||||
])
|
||||
|
||||
const result = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
expect(result).toContain("# Recently Modified Files")
|
||||
expect(result).toContain("modified1.ts")
|
||||
|
|
@ -208,14 +208,14 @@ describe("getEnvironmentDetails", () => {
|
|||
;(TerminalRegistry.getTerminals as jest.Mock).mockReturnValue([mockActiveTerminal])
|
||||
;(TerminalRegistry.getUnretrievedOutput as jest.Mock).mockReturnValue("Test output")
|
||||
|
||||
const result = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
expect(result).toContain("# Actively Running Terminals")
|
||||
expect(result).toContain("Original command: `npm test`")
|
||||
expect(result).toContain("Test output")
|
||||
|
||||
mockCline.didEditFile = true
|
||||
await getEnvironmentDetails(mockCline as Cline)
|
||||
await getEnvironmentDetails(mockCline as Task)
|
||||
expect(delay).toHaveBeenCalledWith(300)
|
||||
|
||||
expect(pWaitFor).toHaveBeenCalled()
|
||||
|
|
@ -237,7 +237,7 @@ describe("getEnvironmentDetails", () => {
|
|||
active ? [] : [mockInactiveTerminal],
|
||||
)
|
||||
|
||||
const result = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
expect(result).toContain("# Inactive Terminals with Completed Process Output")
|
||||
expect(result).toContain("Terminal terminal-2")
|
||||
|
|
@ -261,7 +261,7 @@ describe("getEnvironmentDetails", () => {
|
|||
return null
|
||||
})
|
||||
|
||||
const result = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
expect(result).toContain("NOTE: You are currently in '💻 Code' mode, which does not allow write operations")
|
||||
})
|
||||
|
|
@ -270,7 +270,7 @@ describe("getEnvironmentDetails", () => {
|
|||
mockState.experiments = { [EXPERIMENT_IDS.POWER_STEERING]: true }
|
||||
;(experiments.isEnabled as jest.Mock).mockReturnValue(true)
|
||||
|
||||
const result = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
expect(result).toContain("<role>You are a code assistant</role>")
|
||||
expect(result).toContain("<custom_instructions>Custom instructions</custom_instructions>")
|
||||
|
|
@ -280,7 +280,7 @@ describe("getEnvironmentDetails", () => {
|
|||
// Mock provider to return null.
|
||||
mockCline.providerRef!.deref = jest.fn().mockReturnValue(null)
|
||||
|
||||
const result = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
// Verify the function still returns a result.
|
||||
expect(result).toContain("<environment_details>")
|
||||
|
|
@ -291,7 +291,7 @@ describe("getEnvironmentDetails", () => {
|
|||
getState: jest.fn().mockResolvedValue(null),
|
||||
})
|
||||
|
||||
const result2 = await getEnvironmentDetails(mockCline as Cline)
|
||||
const result2 = await getEnvironmentDetails(mockCline as Task)
|
||||
|
||||
// Verify the function still returns a result.
|
||||
expect(result2).toContain("<environment_details>")
|
||||
|
|
@ -311,6 +311,6 @@ describe("getEnvironmentDetails", () => {
|
|||
;(TerminalRegistry.getBackgroundTerminals as jest.Mock).mockReturnValue([])
|
||||
;(mockCline.fileContextTracker!.getAndClearRecentlyModifiedFiles as jest.Mock).mockReturnValue([])
|
||||
|
||||
await expect(getEnvironmentDetails(mockCline as Cline)).resolves.not.toThrow()
|
||||
await expect(getEnvironmentDetails(mockCline as Task)).resolves.not.toThrow()
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@ import { Terminal } from "../../integrations/terminal/Terminal"
|
|||
import { arePathsEqual } from "../../utils/path"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
|
||||
export async function getEnvironmentDetails(cline: Cline, includeFileDetails: boolean = false) {
|
||||
export async function getEnvironmentDetails(cline: Task, includeFileDetails: boolean = false) {
|
||||
let details = ""
|
||||
|
||||
const clineProvider = cline.providerRef.deref()
|
||||
|
|
|
|||
|
|
@ -9,17 +9,17 @@ import pWaitFor from "p-wait-for"
|
|||
import { serializeError } from "serialize-error"
|
||||
|
||||
// schemas
|
||||
import { TokenUsage, ToolUsage, ToolName } from "../schemas"
|
||||
import { TokenUsage, ToolUsage, ToolName } from "../../schemas"
|
||||
|
||||
// api
|
||||
import { ApiHandler, buildApiHandler } from "../api"
|
||||
import { ApiStream } from "../api/transform/stream"
|
||||
import { ApiHandler, buildApiHandler } from "../../api"
|
||||
import { ApiStream } from "../../api/transform/stream"
|
||||
|
||||
// shared
|
||||
import { ApiConfiguration } from "../shared/api"
|
||||
import { findLastIndex } from "../shared/array"
|
||||
import { combineApiRequests } from "../shared/combineApiRequests"
|
||||
import { combineCommandSequences } from "../shared/combineCommandSequences"
|
||||
import { ApiConfiguration } from "../../shared/api"
|
||||
import { findLastIndex } from "../../shared/array"
|
||||
import { combineApiRequests } from "../../shared/combineApiRequests"
|
||||
import { combineCommandSequences } from "../../shared/combineCommandSequences"
|
||||
import {
|
||||
ClineApiReqCancelReason,
|
||||
ClineApiReqInfo,
|
||||
|
|
@ -27,45 +27,45 @@ import {
|
|||
ClineMessage,
|
||||
ClineSay,
|
||||
ToolProgressStatus,
|
||||
} from "../shared/ExtensionMessage"
|
||||
import { getApiMetrics } from "../shared/getApiMetrics"
|
||||
import { HistoryItem } from "../shared/HistoryItem"
|
||||
import { ClineAskResponse } from "../shared/WebviewMessage"
|
||||
import { defaultModeSlug } from "../shared/modes"
|
||||
import { DiffStrategy } from "../shared/tools"
|
||||
} from "../../shared/ExtensionMessage"
|
||||
import { getApiMetrics } from "../../shared/getApiMetrics"
|
||||
import { HistoryItem } from "../../shared/HistoryItem"
|
||||
import { ClineAskResponse } from "../../shared/WebviewMessage"
|
||||
import { defaultModeSlug } from "../../shared/modes"
|
||||
import { DiffStrategy } from "../../shared/tools"
|
||||
|
||||
// services
|
||||
import { UrlContentFetcher } from "../services/browser/UrlContentFetcher"
|
||||
import { BrowserSession } from "../services/browser/BrowserSession"
|
||||
import { McpHub } from "../services/mcp/McpHub"
|
||||
import { McpServerManager } from "../services/mcp/McpServerManager"
|
||||
import { telemetryService } from "../services/telemetry/TelemetryService"
|
||||
import { RepoPerTaskCheckpointService } from "../services/checkpoints"
|
||||
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
|
||||
import { BrowserSession } from "../../services/browser/BrowserSession"
|
||||
import { McpHub } from "../../services/mcp/McpHub"
|
||||
import { McpServerManager } from "../../services/mcp/McpServerManager"
|
||||
import { telemetryService } from "../../services/telemetry/TelemetryService"
|
||||
import { RepoPerTaskCheckpointService } from "../../services/checkpoints"
|
||||
|
||||
// integrations
|
||||
import { DiffViewProvider } from "../integrations/editor/DiffViewProvider"
|
||||
import { findToolName, formatContentBlockToMarkdown } from "../integrations/misc/export-markdown"
|
||||
import { RooTerminalProcess } from "../integrations/terminal/types"
|
||||
import { TerminalRegistry } from "../integrations/terminal/TerminalRegistry"
|
||||
import { DiffViewProvider } from "../../integrations/editor/DiffViewProvider"
|
||||
import { findToolName, formatContentBlockToMarkdown } from "../../integrations/misc/export-markdown"
|
||||
import { RooTerminalProcess } from "../../integrations/terminal/types"
|
||||
import { TerminalRegistry } from "../../integrations/terminal/TerminalRegistry"
|
||||
|
||||
// utils
|
||||
import { calculateApiCostAnthropic } from "../utils/cost"
|
||||
import { getWorkspacePath } from "../utils/path"
|
||||
import { calculateApiCostAnthropic } from "../../utils/cost"
|
||||
import { getWorkspacePath } from "../../utils/path"
|
||||
|
||||
// prompts
|
||||
import { formatResponse } from "./prompts/responses"
|
||||
import { SYSTEM_PROMPT } from "./prompts/system"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { SYSTEM_PROMPT } from "../prompts/system"
|
||||
|
||||
// core modules
|
||||
import { ToolRepetitionDetector } from "./tools/ToolRepetitionDetector"
|
||||
import { FileContextTracker } from "./context-tracking/FileContextTracker"
|
||||
import { RooIgnoreController } from "./ignore/RooIgnoreController"
|
||||
import { type AssistantMessageContent, parseAssistantMessage, presentAssistantMessage } from "./assistant-message"
|
||||
import { truncateConversationIfNeeded } from "./sliding-window"
|
||||
import { ClineProvider } from "./webview/ClineProvider"
|
||||
import { MultiSearchReplaceDiffStrategy } from "./diff/strategies/multi-search-replace"
|
||||
import { readApiMessages, saveApiMessages, readTaskMessages, saveTaskMessages, taskMetadata } from "./task-persistence"
|
||||
import { getEnvironmentDetails } from "./environment/getEnvironmentDetails"
|
||||
import { ToolRepetitionDetector } from "../tools/ToolRepetitionDetector"
|
||||
import { FileContextTracker } from "../context-tracking/FileContextTracker"
|
||||
import { RooIgnoreController } from "../ignore/RooIgnoreController"
|
||||
import { type AssistantMessageContent, parseAssistantMessage, presentAssistantMessage } from "../assistant-message"
|
||||
import { truncateConversationIfNeeded } from "../sliding-window"
|
||||
import { ClineProvider } from "../webview/ClineProvider"
|
||||
import { MultiSearchReplaceDiffStrategy } from "../diff/strategies/multi-search-replace"
|
||||
import { readApiMessages, saveApiMessages, readTaskMessages, saveTaskMessages, taskMetadata } from "../task-persistence"
|
||||
import { getEnvironmentDetails } from "../environment/getEnvironmentDetails"
|
||||
import {
|
||||
type CheckpointDiffOptions,
|
||||
type CheckpointRestoreOptions,
|
||||
|
|
@ -73,8 +73,8 @@ import {
|
|||
checkpointSave,
|
||||
checkpointRestore,
|
||||
checkpointDiff,
|
||||
} from "./checkpoints"
|
||||
import { processUserContentMentions } from "./mentions/processUserContentMentions"
|
||||
} from "../checkpoints"
|
||||
import { processUserContentMentions } from "../mentions/processUserContentMentions"
|
||||
|
||||
export type ClineEvents = {
|
||||
message: [{ action: "created" | "updated"; message: ClineMessage }]
|
||||
|
|
@ -90,7 +90,7 @@ export type ClineEvents = {
|
|||
taskToolFailed: [taskId: string, tool: ToolName, error: string]
|
||||
}
|
||||
|
||||
export type ClineOptions = {
|
||||
export type TaskOptions = {
|
||||
provider: ClineProvider
|
||||
apiConfiguration: ApiConfiguration
|
||||
customInstructions?: string
|
||||
|
|
@ -103,18 +103,18 @@ export type ClineOptions = {
|
|||
historyItem?: HistoryItem
|
||||
experiments?: Record<string, boolean>
|
||||
startTask?: boolean
|
||||
rootTask?: Cline
|
||||
parentTask?: Cline
|
||||
rootTask?: Task
|
||||
parentTask?: Task
|
||||
taskNumber?: number
|
||||
onCreated?: (cline: Cline) => void
|
||||
onCreated?: (cline: Task) => void
|
||||
}
|
||||
|
||||
export class Cline extends EventEmitter<ClineEvents> {
|
||||
export class Task extends EventEmitter<ClineEvents> {
|
||||
readonly taskId: string
|
||||
readonly instanceId: string
|
||||
|
||||
readonly rootTask: Cline | undefined = undefined
|
||||
readonly parentTask: Cline | undefined = undefined
|
||||
readonly rootTask: Task | undefined = undefined
|
||||
readonly parentTask: Task | undefined = undefined
|
||||
readonly taskNumber: number
|
||||
readonly workspacePath: string
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ export class Cline extends EventEmitter<ClineEvents> {
|
|||
parentTask,
|
||||
taskNumber = -1,
|
||||
onCreated,
|
||||
}: ClineOptions) {
|
||||
}: TaskOptions) {
|
||||
super()
|
||||
|
||||
if (startTask && !task && !images && !historyItem) {
|
||||
|
|
@ -264,8 +264,8 @@ export class Cline extends EventEmitter<ClineEvents> {
|
|||
}
|
||||
}
|
||||
|
||||
static create(options: ClineOptions): [Cline, Promise<void>] {
|
||||
const instance = new Cline({ ...options, startTask: false })
|
||||
static create(options: TaskOptions): [Task, Promise<void>] {
|
||||
const instance = new Task({ ...options, startTask: false })
|
||||
const { images, task, historyItem } = options
|
||||
let promise
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// npx jest src/core/__tests__/Cline.test.ts
|
||||
// npx jest src/core/task/__tests__/Task.test.ts
|
||||
|
||||
import * as os from "os"
|
||||
import * as path from "path"
|
||||
|
|
@ -6,64 +6,18 @@ import * as path from "path"
|
|||
import * as vscode from "vscode"
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
|
||||
import { GlobalState } from "../../schemas"
|
||||
import { Cline } from "../Cline"
|
||||
import { ClineProvider } from "../webview/ClineProvider"
|
||||
import { ApiConfiguration, ModelInfo } from "../../shared/api"
|
||||
import { ApiStreamChunk } from "../../api/transform/stream"
|
||||
import { ContextProxy } from "../config/ContextProxy"
|
||||
import { processUserContentMentions } from "../mentions/processUserContentMentions"
|
||||
|
||||
jest.mock("../mentions", () => ({
|
||||
parseMentions: jest.fn().mockImplementation((text) => {
|
||||
return Promise.resolve(`processed: ${text}`)
|
||||
}),
|
||||
openMention: jest.fn(),
|
||||
getLatestTerminalOutput: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.mock("../../integrations/misc/extract-text", () => ({
|
||||
extractTextFromFile: jest.fn().mockResolvedValue("Mock file content"),
|
||||
}))
|
||||
|
||||
jest.mock("../environment/getEnvironmentDetails", () => ({
|
||||
getEnvironmentDetails: jest.fn().mockResolvedValue(""),
|
||||
}))
|
||||
import { GlobalState } from "../../../schemas"
|
||||
import { Task } from "../Task"
|
||||
import { ClineProvider } from "../../webview/ClineProvider"
|
||||
import { ApiConfiguration, ModelInfo } from "../../../shared/api"
|
||||
import { ApiStreamChunk } from "../../../api/transform/stream"
|
||||
import { ContextProxy } from "../../config/ContextProxy"
|
||||
import { processUserContentMentions } from "../../mentions/processUserContentMentions"
|
||||
|
||||
jest.mock("execa", () => ({
|
||||
execa: jest.fn(),
|
||||
}))
|
||||
|
||||
// Mock RooIgnoreController
|
||||
jest.mock("../ignore/RooIgnoreController")
|
||||
|
||||
// Mock storagePathManager to prevent dynamic import issues
|
||||
jest.mock("../../shared/storagePathManager", () => ({
|
||||
getTaskDirectoryPath: jest
|
||||
.fn()
|
||||
.mockImplementation((globalStoragePath, taskId) => Promise.resolve(`${globalStoragePath}/tasks/${taskId}`)),
|
||||
getSettingsDirectoryPath: jest
|
||||
.fn()
|
||||
.mockImplementation((globalStoragePath) => Promise.resolve(`${globalStoragePath}/settings`)),
|
||||
}))
|
||||
|
||||
// Mock fileExistsAtPath
|
||||
jest.mock("../../utils/fs", () => ({
|
||||
fileExistsAtPath: jest.fn().mockImplementation((filePath) => {
|
||||
return filePath.includes("ui_messages.json") || filePath.includes("api_conversation_history.json")
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock fs/promises
|
||||
const mockMessages = [
|
||||
{
|
||||
ts: Date.now(),
|
||||
type: "say",
|
||||
say: "text",
|
||||
text: "historical task",
|
||||
},
|
||||
]
|
||||
|
||||
jest.mock("fs/promises", () => ({
|
||||
mkdir: jest.fn().mockResolvedValue(undefined),
|
||||
writeFile: jest.fn().mockResolvedValue(undefined),
|
||||
|
|
@ -93,35 +47,18 @@ jest.mock("fs/promises", () => ({
|
|||
rmdir: jest.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock("p-wait-for", () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockImplementation(async () => Promise.resolve()),
|
||||
}))
|
||||
|
||||
jest.mock("vscode", () => {
|
||||
const mockDisposable = { dispose: jest.fn() }
|
||||
const mockEventEmitter = {
|
||||
event: jest.fn(),
|
||||
fire: jest.fn(),
|
||||
}
|
||||
|
||||
const mockTextDocument = {
|
||||
uri: {
|
||||
fsPath: "/mock/workspace/path/file.ts",
|
||||
},
|
||||
}
|
||||
|
||||
const mockTextEditor = {
|
||||
document: mockTextDocument,
|
||||
}
|
||||
|
||||
const mockTab = {
|
||||
input: {
|
||||
uri: {
|
||||
fsPath: "/mock/workspace/path/file.ts",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const mockTabGroup = {
|
||||
tabs: [mockTab],
|
||||
}
|
||||
const mockEventEmitter = { event: jest.fn(), fire: jest.fn() }
|
||||
const mockTextDocument = { uri: { fsPath: "/mock/workspace/path/file.ts" } }
|
||||
const mockTextEditor = { document: mockTextDocument }
|
||||
const mockTab = { input: { uri: { fsPath: "/mock/workspace/path/file.ts" } } }
|
||||
const mockTabGroup = { tabs: [mockTab] }
|
||||
|
||||
return {
|
||||
CodeActionKind: {
|
||||
|
|
@ -142,9 +79,7 @@ jest.mock("vscode", () => {
|
|||
workspace: {
|
||||
workspaceFolders: [
|
||||
{
|
||||
uri: {
|
||||
fsPath: "/mock/workspace/path",
|
||||
},
|
||||
uri: { fsPath: "/mock/workspace/path" },
|
||||
name: "mock-workspace",
|
||||
index: 0,
|
||||
},
|
||||
|
|
@ -173,12 +108,52 @@ jest.mock("vscode", () => {
|
|||
}
|
||||
})
|
||||
|
||||
// Mock p-wait-for to resolve immediately
|
||||
jest.mock("p-wait-for", () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockImplementation(async () => Promise.resolve()),
|
||||
jest.mock("../../mentions", () => ({
|
||||
parseMentions: jest.fn().mockImplementation((text) => {
|
||||
return Promise.resolve(`processed: ${text}`)
|
||||
}),
|
||||
openMention: jest.fn(),
|
||||
getLatestTerminalOutput: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.mock("../../../integrations/misc/extract-text", () => ({
|
||||
extractTextFromFile: jest.fn().mockResolvedValue("Mock file content"),
|
||||
}))
|
||||
|
||||
jest.mock("../../environment/getEnvironmentDetails", () => ({
|
||||
getEnvironmentDetails: jest.fn().mockResolvedValue(""),
|
||||
}))
|
||||
|
||||
// Mock RooIgnoreController
|
||||
jest.mock("../../ignore/RooIgnoreController")
|
||||
|
||||
// Mock storagePathManager to prevent dynamic import issues
|
||||
jest.mock("../../../shared/storagePathManager", () => ({
|
||||
getTaskDirectoryPath: jest
|
||||
.fn()
|
||||
.mockImplementation((globalStoragePath, taskId) => Promise.resolve(`${globalStoragePath}/tasks/${taskId}`)),
|
||||
getSettingsDirectoryPath: jest
|
||||
.fn()
|
||||
.mockImplementation((globalStoragePath) => Promise.resolve(`${globalStoragePath}/settings`)),
|
||||
}))
|
||||
|
||||
// Mock fileExistsAtPath
|
||||
jest.mock("../../../utils/fs", () => ({
|
||||
fileExistsAtPath: jest.fn().mockImplementation((filePath) => {
|
||||
return filePath.includes("ui_messages.json") || filePath.includes("api_conversation_history.json")
|
||||
}),
|
||||
}))
|
||||
|
||||
// Mock fs/promises
|
||||
const mockMessages = [
|
||||
{
|
||||
ts: Date.now(),
|
||||
type: "say",
|
||||
say: "text",
|
||||
text: "historical task",
|
||||
},
|
||||
]
|
||||
|
||||
describe("Cline", () => {
|
||||
let mockProvider: jest.Mocked<ClineProvider>
|
||||
let mockApiConfig: ApiConfiguration
|
||||
|
|
@ -295,7 +270,7 @@ describe("Cline", () => {
|
|||
|
||||
describe("constructor", () => {
|
||||
it("should respect provided settings", async () => {
|
||||
const cline = new Cline({
|
||||
const cline = new Task({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
customInstructions: "custom instructions",
|
||||
|
|
@ -309,7 +284,7 @@ describe("Cline", () => {
|
|||
})
|
||||
|
||||
it("should use default fuzzy match threshold when not provided", async () => {
|
||||
const cline = new Cline({
|
||||
const cline = new Task({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
customInstructions: "custom instructions",
|
||||
|
|
@ -327,7 +302,7 @@ describe("Cline", () => {
|
|||
|
||||
it("should require either task or historyItem", () => {
|
||||
expect(() => {
|
||||
new Cline({ provider: mockProvider, apiConfiguration: mockApiConfig })
|
||||
new Task({ provider: mockProvider, apiConfiguration: mockApiConfig })
|
||||
}).toThrow("Either historyItem or task/images must be provided")
|
||||
})
|
||||
})
|
||||
|
|
@ -336,7 +311,7 @@ describe("Cline", () => {
|
|||
describe("API conversation handling", () => {
|
||||
it("should clean conversation history before sending to API", async () => {
|
||||
// Cline.create will now use our mocked getEnvironmentDetails
|
||||
const [cline, task] = Cline.create({
|
||||
const [cline, task] = Task.create({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
task: "test task",
|
||||
|
|
@ -444,7 +419,7 @@ describe("Cline", () => {
|
|||
]
|
||||
|
||||
// Test with model that supports images
|
||||
const [clineWithImages, taskWithImages] = Cline.create({
|
||||
const [clineWithImages, taskWithImages] = Task.create({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: configWithImages,
|
||||
task: "test task",
|
||||
|
|
@ -467,7 +442,7 @@ describe("Cline", () => {
|
|||
clineWithImages.apiConversationHistory = conversationHistory
|
||||
|
||||
// Test with model that doesn't support images
|
||||
const [clineWithoutImages, taskWithoutImages] = Cline.create({
|
||||
const [clineWithoutImages, taskWithoutImages] = Task.create({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: configWithoutImages,
|
||||
task: "test task",
|
||||
|
|
@ -558,7 +533,7 @@ describe("Cline", () => {
|
|||
})
|
||||
|
||||
it.skip("should handle API retry with countdown", async () => {
|
||||
const [cline, task] = Cline.create({
|
||||
const [cline, task] = Task.create({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
task: "test task",
|
||||
|
|
@ -682,7 +657,7 @@ describe("Cline", () => {
|
|||
})
|
||||
|
||||
it.skip("should not apply retry delay twice", async () => {
|
||||
const [cline, task] = Cline.create({
|
||||
const [cline, task] = Task.create({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
task: "test task",
|
||||
|
|
@ -806,7 +781,7 @@ describe("Cline", () => {
|
|||
|
||||
describe("processUserContentMentions", () => {
|
||||
it("should process mentions in task and feedback tags", async () => {
|
||||
const [cline, task] = Cline.create({
|
||||
const [cline, task] = Task.create({
|
||||
provider: mockProvider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
task: "test task",
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { describe, expect, it, jest, beforeEach } from "@jest/globals"
|
||||
|
||||
import { Cline } from "../../Cline"
|
||||
import { Task } from "../../task/Task"
|
||||
import { formatResponse } from "../../prompts/responses"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../../shared/tools"
|
||||
import { ToolUsage } from "../../../schemas"
|
||||
|
|
@ -13,7 +13,7 @@ jest.mock("execa", () => ({
|
|||
execa: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.mock("../../Cline")
|
||||
jest.mock("../../task/Task")
|
||||
jest.mock("../../prompts/responses")
|
||||
|
||||
// Create a mock for the executeCommand function
|
||||
|
|
@ -74,7 +74,7 @@ beforeEach(() => {
|
|||
|
||||
describe("executeCommandTool", () => {
|
||||
// Setup common test variables
|
||||
let mockCline: jest.Mocked<Partial<Cline>> & { consecutiveMistakeCount: number; didRejectTool: boolean }
|
||||
let mockCline: jest.Mocked<Partial<Task>> & { consecutiveMistakeCount: number; didRejectTool: boolean }
|
||||
let mockAskApproval: jest.Mock
|
||||
let mockHandleError: jest.Mock
|
||||
let mockPushToolResult: jest.Mock
|
||||
|
|
@ -160,7 +160,7 @@ describe("executeCommandTool", () => {
|
|||
|
||||
// Execute
|
||||
await executeCommandTool(
|
||||
mockCline as unknown as Cline,
|
||||
mockCline as unknown as Task,
|
||||
mockToolUse,
|
||||
mockAskApproval as unknown as AskApproval,
|
||||
mockHandleError as unknown as HandleError,
|
||||
|
|
@ -181,7 +181,7 @@ describe("executeCommandTool", () => {
|
|||
|
||||
// Execute
|
||||
await executeCommandTool(
|
||||
mockCline as unknown as Cline,
|
||||
mockCline as unknown as Task,
|
||||
mockToolUse,
|
||||
mockAskApproval as unknown as AskApproval,
|
||||
mockHandleError as unknown as HandleError,
|
||||
|
|
@ -204,7 +204,7 @@ describe("executeCommandTool", () => {
|
|||
|
||||
// Execute
|
||||
await executeCommandTool(
|
||||
mockCline as unknown as Cline,
|
||||
mockCline as unknown as Task,
|
||||
mockToolUse,
|
||||
mockAskApproval as unknown as AskApproval,
|
||||
mockHandleError as unknown as HandleError,
|
||||
|
|
@ -228,7 +228,7 @@ describe("executeCommandTool", () => {
|
|||
|
||||
// Execute
|
||||
await executeCommandTool(
|
||||
mockCline as unknown as Cline,
|
||||
mockCline as unknown as Task,
|
||||
mockToolUse,
|
||||
mockAskApproval as unknown as AskApproval,
|
||||
mockHandleError as unknown as HandleError,
|
||||
|
|
@ -258,7 +258,7 @@ describe("executeCommandTool", () => {
|
|||
|
||||
// Execute
|
||||
await executeCommandTool(
|
||||
mockCline as unknown as Cline,
|
||||
mockCline as unknown as Task,
|
||||
mockToolUse,
|
||||
mockAskApproval as unknown as AskApproval,
|
||||
mockHandleError as unknown as HandleError,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { ClineAskUseMcpServer } from "../../shared/ExtensionMessage"
|
||||
import { ToolUse, RemoveClosingTag, AskApproval, HandleError, PushToolResult } from "../../shared/tools"
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
|
||||
export async function accessMcpResourceTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import fs from "fs/promises"
|
|||
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { getReadablePath } from "../../utils/path"
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ToolUse, RemoveClosingTag } from "../../shared/tools"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { AskApproval, HandleError, PushToolResult } from "../../shared/tools"
|
||||
|
|
@ -14,7 +14,7 @@ import { telemetryService } from "../../services/telemetry/TelemetryService"
|
|||
import { unescapeHtmlEntities } from "../../utils/text-normalization"
|
||||
|
||||
export async function applyDiffTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { parseXml } from "../../utils/xml"
|
||||
|
||||
export async function askFollowupQuestionTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Anthropic from "@anthropic-ai/sdk"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import {
|
||||
ToolResponse,
|
||||
ToolUse,
|
||||
|
|
@ -16,7 +16,7 @@ import { telemetryService } from "../../services/telemetry/TelemetryService"
|
|||
import { type ExecuteCommandOptions, executeCommand } from "./executeCommandTool"
|
||||
|
||||
export async function attemptCompletionTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import {
|
||||
BrowserAction,
|
||||
|
|
@ -9,7 +9,7 @@ import {
|
|||
import { formatResponse } from "../prompts/responses"
|
||||
|
||||
export async function browserActionTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import * as path from "path"
|
|||
|
||||
import delay from "delay"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { CommandExecutionStatus } from "../../schemas"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolResponse } from "../../shared/tools"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
|
|
@ -16,7 +16,7 @@ import { Terminal } from "../../integrations/terminal/Terminal"
|
|||
class ShellIntegrationError extends Error {}
|
||||
|
||||
export async function executeCommandTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
@ -114,7 +114,7 @@ export type ExecuteCommandOptions = {
|
|||
}
|
||||
|
||||
export async function executeCommand(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
{
|
||||
executionId,
|
||||
command,
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { fetchInstructions } from "../prompts/instructions/instructions"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult } from "../../shared/tools"
|
||||
|
||||
export async function fetchInstructionsTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import fs from "fs/promises"
|
|||
import path from "path"
|
||||
|
||||
import { getReadablePath } from "../../utils/path"
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
|
|
@ -12,7 +12,7 @@ import { fileExistsAtPath } from "../../utils/fs"
|
|||
import { insertGroups } from "../diff/insert-groups"
|
||||
|
||||
export async function insertContentTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ import path from "path"
|
|||
import fs from "fs/promises"
|
||||
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { getReadablePath } from "../../utils/path"
|
||||
import { parseSourceCodeForDefinitionsTopLevel, parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
|
||||
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
|
||||
|
||||
export async function listCodeDefinitionNamesTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as path from "path"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { listFiles } from "../../services/glob/list-files"
|
||||
|
|
@ -23,7 +23,7 @@ import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } f
|
|||
*/
|
||||
|
||||
export async function listFilesTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import delay from "delay"
|
||||
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { defaultModeSlug, getModeBySlug } from "../../shared/modes"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
|
||||
export async function newTaskTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import path from "path"
|
||||
import { isBinaryFile } from "isbinaryfile"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { t } from "../../i18n"
|
||||
|
|
@ -15,7 +15,7 @@ import { extractTextFromFile, addLineNumbers } from "../../integrations/misc/ext
|
|||
import { parseSourceCodeDefinitionsForFile } from "../../services/tree-sitter"
|
||||
|
||||
export async function readFileTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import fs from "fs/promises"
|
|||
import delay from "delay"
|
||||
|
||||
// Internal imports
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { AskApproval, HandleError, PushToolResult, RemoveClosingTag, ToolUse } from "../../shared/tools"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
|
|
@ -21,7 +21,7 @@ import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
|
|||
* Validates required parameters for search and replace operation
|
||||
*/
|
||||
async function validateParams(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
relPath: string | undefined,
|
||||
search: string | undefined,
|
||||
replace: string | undefined,
|
||||
|
|
@ -61,7 +61,7 @@ async function validateParams(
|
|||
* @param removeClosingTag - Function to remove closing tags
|
||||
*/
|
||||
export async function searchAndReplaceTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import path from "path"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { getReadablePath } from "../../utils/path"
|
||||
import { regexSearchFiles } from "../../services/ripgrep"
|
||||
|
||||
export async function searchFilesTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import delay from "delay"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { defaultModeSlug, getModeBySlug } from "../../shared/modes"
|
||||
|
||||
export async function switchModeTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { ClineAskUseMcpServer } from "../../shared/ExtensionMessage"
|
||||
|
||||
export async function useMcpToolTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import path from "path"
|
|||
import delay from "delay"
|
||||
import * as vscode from "vscode"
|
||||
|
||||
import { Cline } from "../Cline"
|
||||
import { Task } from "../task/Task"
|
||||
import { ClineSayTool } from "../../shared/ExtensionMessage"
|
||||
import { formatResponse } from "../prompts/responses"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
|
|
@ -15,7 +15,7 @@ import { detectCodeOmission } from "../../integrations/editor/detect-omission"
|
|||
import { unescapeHtmlEntities } from "../../utils/text-normalization"
|
||||
|
||||
export async function writeToFileTool(
|
||||
cline: Cline,
|
||||
cline: Task,
|
||||
block: ToolUse,
|
||||
askApproval: AskApproval,
|
||||
handleError: HandleError,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ import { ProviderSettingsManager } from "../config/ProviderSettingsManager"
|
|||
import { CustomModesManager } from "../config/CustomModesManager"
|
||||
import { buildApiHandler } from "../../api"
|
||||
import { CodeActionName } from "../../activate/CodeActionProvider"
|
||||
import { Cline, ClineOptions } from "../Cline"
|
||||
import { Task, TaskOptions } from "../task/Task"
|
||||
import { getNonce } from "./getNonce"
|
||||
import { getUri } from "./getUri"
|
||||
import { getSystemPromptFilePath } from "../prompts/sections/custom-system-prompt"
|
||||
|
|
@ -57,7 +57,7 @@ import { WebviewMessage } from "../../shared/WebviewMessage"
|
|||
*/
|
||||
|
||||
export type ClineProviderEvents = {
|
||||
clineCreated: [cline: Cline]
|
||||
clineCreated: [cline: Task]
|
||||
}
|
||||
|
||||
export class ClineProvider extends EventEmitter<ClineProviderEvents> implements vscode.WebviewViewProvider {
|
||||
|
|
@ -66,7 +66,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
private static activeInstances: Set<ClineProvider> = new Set()
|
||||
private disposables: vscode.Disposable[] = []
|
||||
private view?: vscode.WebviewView | vscode.WebviewPanel
|
||||
private clineStack: Cline[] = []
|
||||
private clineStack: Task[] = []
|
||||
private _workspaceTracker?: WorkspaceTracker // workSpaceTracker read-only for access outside this class
|
||||
public get workspaceTracker(): WorkspaceTracker | undefined {
|
||||
return this._workspaceTracker
|
||||
|
|
@ -116,7 +116,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
// Adds a new Cline instance to clineStack, marking the start of a new task.
|
||||
// The instance is pushed to the top of the stack (LIFO order).
|
||||
// When the task is completed, the top instance is removed, reactivating the previous task.
|
||||
async addClineToStack(cline: Cline) {
|
||||
async addClineToStack(cline: Task) {
|
||||
console.log(`[subtasks] adding task ${cline.taskId}.${cline.instanceId} to stack`)
|
||||
|
||||
// Add this cline instance into the stack that represents the order of all the called tasks.
|
||||
|
|
@ -161,7 +161,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
|
||||
// returns the current cline object in the stack (the top one)
|
||||
// if the stack is empty, returns undefined
|
||||
getCurrentCline(): Cline | undefined {
|
||||
getCurrentCline(): Task | undefined {
|
||||
if (this.clineStack.length === 0) {
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -438,7 +438,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
this.log("Webview view resolved")
|
||||
}
|
||||
|
||||
public async initClineWithSubTask(parent: Cline, task?: string, images?: string[]) {
|
||||
public async initClineWithSubTask(parent: Task, task?: string, images?: string[]) {
|
||||
return this.initClineWithTask(task, images, parent)
|
||||
}
|
||||
|
||||
|
|
@ -451,10 +451,10 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
public async initClineWithTask(
|
||||
task?: string,
|
||||
images?: string[],
|
||||
parentTask?: Cline,
|
||||
parentTask?: Task,
|
||||
options: Partial<
|
||||
Pick<
|
||||
ClineOptions,
|
||||
TaskOptions,
|
||||
| "customInstructions"
|
||||
| "enableDiff"
|
||||
| "enableCheckpoints"
|
||||
|
|
@ -478,7 +478,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
const modePrompt = customModePrompts?.[mode] as PromptComponent
|
||||
const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n")
|
||||
|
||||
const cline = new Cline({
|
||||
const cline = new Task({
|
||||
provider: this,
|
||||
apiConfiguration,
|
||||
customInstructions: effectiveInstructions,
|
||||
|
|
@ -504,7 +504,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
return cline
|
||||
}
|
||||
|
||||
public async initClineWithHistoryItem(historyItem: HistoryItem & { rootTask?: Cline; parentTask?: Cline }) {
|
||||
public async initClineWithHistoryItem(historyItem: HistoryItem & { rootTask?: Task; parentTask?: Task }) {
|
||||
await this.removeClineFromStack()
|
||||
|
||||
const {
|
||||
|
|
@ -521,7 +521,7 @@ export class ClineProvider extends EventEmitter<ClineProviderEvents> implements
|
|||
const modePrompt = customModePrompts?.[mode] as PromptComponent
|
||||
const effectiveInstructions = [globalInstructions, modePrompt?.customInstructions].filter(Boolean).join("\n\n")
|
||||
|
||||
const cline = new Cline({
|
||||
const cline = new Task({
|
||||
provider: this,
|
||||
apiConfiguration,
|
||||
customInstructions: effectiveInstructions,
|
||||
|
|
|
|||
|
|
@ -1,52 +1,41 @@
|
|||
// npx jest src/core/webview/__tests__/ClineProvider.test.ts
|
||||
|
||||
import Anthropic from "@anthropic-ai/sdk"
|
||||
import * as vscode from "vscode"
|
||||
import axios from "axios"
|
||||
|
||||
import { ClineProvider } from "../ClineProvider"
|
||||
import { ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
|
||||
import { ClineMessage, ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessage"
|
||||
import { setSoundEnabled } from "../../../utils/sound"
|
||||
import { setTtsEnabled } from "../../../utils/tts"
|
||||
import { defaultModeSlug } from "../../../shared/modes"
|
||||
import { experimentDefault } from "../../../shared/experiments"
|
||||
import { ContextProxy } from "../../config/ContextProxy"
|
||||
import { Task, TaskOptions } from "../../task/Task"
|
||||
|
||||
// Mock setup must come before imports
|
||||
jest.mock("../../prompts/sections/custom-instructions")
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock("vscode")
|
||||
|
||||
jest.mock("delay")
|
||||
|
||||
// Mock BrowserSession
|
||||
jest.mock("../../../services/browser/BrowserSession", () => ({
|
||||
BrowserSession: jest.fn().mockImplementation(() => ({
|
||||
testConnection: jest.fn().mockImplementation(async (url) => {
|
||||
if (url === "http://localhost:9222") {
|
||||
return {
|
||||
success: true,
|
||||
message: "Successfully connected to Chrome",
|
||||
endpoint: "ws://localhost:9222/devtools/browser/123",
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to connect to Chrome",
|
||||
endpoint: undefined,
|
||||
}
|
||||
}
|
||||
}),
|
||||
})),
|
||||
jest.mock("p-wait-for", () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
|
||||
// Mock browserDiscovery
|
||||
jest.mock("../../../services/browser/browserDiscovery", () => ({
|
||||
discoverChromeHostUrl: jest.fn().mockImplementation(async () => {
|
||||
return "http://localhost:9222"
|
||||
}),
|
||||
tryChromeHostUrl: jest.fn().mockImplementation(async (url) => {
|
||||
return url === "http://localhost:9222"
|
||||
}),
|
||||
jest.mock("fs/promises", () => ({
|
||||
mkdir: jest.fn(),
|
||||
writeFile: jest.fn(),
|
||||
readFile: jest.fn(),
|
||||
unlink: jest.fn(),
|
||||
rmdir: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.mock("axios", () => ({
|
||||
get: jest.fn().mockResolvedValue({ data: { data: [] } }),
|
||||
post: jest.fn(),
|
||||
}))
|
||||
|
||||
jest.mock(
|
||||
|
|
@ -74,6 +63,35 @@ jest.mock(
|
|||
{ virtual: true },
|
||||
)
|
||||
|
||||
jest.mock("../../../services/browser/BrowserSession", () => ({
|
||||
BrowserSession: jest.fn().mockImplementation(() => ({
|
||||
testConnection: jest.fn().mockImplementation(async (url) => {
|
||||
if (url === "http://localhost:9222") {
|
||||
return {
|
||||
success: true,
|
||||
message: "Successfully connected to Chrome",
|
||||
endpoint: "ws://localhost:9222/devtools/browser/123",
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: "Failed to connect to Chrome",
|
||||
endpoint: undefined,
|
||||
}
|
||||
}
|
||||
}),
|
||||
})),
|
||||
}))
|
||||
|
||||
jest.mock("../../../services/browser/browserDiscovery", () => ({
|
||||
discoverChromeHostUrl: jest.fn().mockImplementation(async () => {
|
||||
return "http://localhost:9222"
|
||||
}),
|
||||
tryChromeHostUrl: jest.fn().mockImplementation(async (url) => {
|
||||
return url === "http://localhost:9222"
|
||||
}),
|
||||
}))
|
||||
|
||||
// Initialize mocks
|
||||
const mockAddCustomInstructions = jest.fn().mockResolvedValue("Combined instructions")
|
||||
|
||||
|
|
@ -115,7 +133,6 @@ jest.mock(
|
|||
{ virtual: true },
|
||||
)
|
||||
|
||||
// Mock dependencies
|
||||
jest.mock("vscode", () => ({
|
||||
ExtensionContext: jest.fn(),
|
||||
OutputChannel: jest.fn(),
|
||||
|
|
@ -156,50 +173,24 @@ jest.mock("vscode", () => ({
|
|||
},
|
||||
}))
|
||||
|
||||
// Mock sound utility
|
||||
jest.mock("../../../utils/sound", () => ({
|
||||
setSoundEnabled: jest.fn(),
|
||||
}))
|
||||
|
||||
// Mock tts utility
|
||||
jest.mock("../../../utils/tts", () => ({
|
||||
setTtsEnabled: jest.fn(),
|
||||
setTtsSpeed: jest.fn(),
|
||||
}))
|
||||
|
||||
// Mock ESM modules
|
||||
jest.mock("p-wait-for", () => ({
|
||||
__esModule: true,
|
||||
default: jest.fn().mockResolvedValue(undefined),
|
||||
}))
|
||||
|
||||
// Mock fs/promises
|
||||
jest.mock("fs/promises", () => ({
|
||||
mkdir: jest.fn(),
|
||||
writeFile: jest.fn(),
|
||||
readFile: jest.fn(),
|
||||
unlink: jest.fn(),
|
||||
rmdir: jest.fn(),
|
||||
}))
|
||||
|
||||
// Mock axios
|
||||
jest.mock("axios", () => ({
|
||||
get: jest.fn().mockResolvedValue({ data: { data: [] } }),
|
||||
post: jest.fn(),
|
||||
}))
|
||||
|
||||
// Mock buildApiHandler
|
||||
jest.mock("../../../api", () => ({
|
||||
buildApiHandler: jest.fn(),
|
||||
}))
|
||||
|
||||
// Mock system prompt
|
||||
jest.mock("../../prompts/system", () => ({
|
||||
SYSTEM_PROMPT: jest.fn().mockImplementation(async () => "mocked system prompt"),
|
||||
codeMode: "code",
|
||||
}))
|
||||
|
||||
// Mock WorkspaceTracker
|
||||
jest.mock("../../../integrations/workspace/WorkspaceTracker", () => {
|
||||
return jest.fn().mockImplementation(() => ({
|
||||
initializeFilePaths: jest.fn(),
|
||||
|
|
@ -207,9 +198,8 @@ jest.mock("../../../integrations/workspace/WorkspaceTracker", () => {
|
|||
}))
|
||||
})
|
||||
|
||||
// Mock Cline
|
||||
jest.mock("../../Cline", () => ({
|
||||
Cline: jest
|
||||
jest.mock("../../task/Task", () => ({
|
||||
Task: jest
|
||||
.fn()
|
||||
.mockImplementation(
|
||||
(_provider, _apiConfiguration, _customInstructions, _diffEnabled, _fuzzyMatchThreshold, _task, taskId) => ({
|
||||
|
|
@ -229,7 +219,6 @@ jest.mock("../../Cline", () => ({
|
|||
),
|
||||
}))
|
||||
|
||||
// Mock extract-text
|
||||
jest.mock("../../../integrations/misc/extract-text", () => ({
|
||||
extractTextFromFile: jest.fn().mockImplementation(async (_filePath: string) => {
|
||||
const content = "const x = 1;\nconst y = 2;\nconst z = 3;"
|
||||
|
|
@ -249,6 +238,8 @@ afterAll(() => {
|
|||
})
|
||||
|
||||
describe("ClineProvider", () => {
|
||||
let defaultTaskOptions: TaskOptions
|
||||
|
||||
let provider: ClineProvider
|
||||
let mockContext: vscode.ExtensionContext
|
||||
let mockOutputChannel: vscode.OutputChannel
|
||||
|
|
@ -327,6 +318,13 @@ describe("ClineProvider", () => {
|
|||
|
||||
provider = new ClineProvider(mockContext, mockOutputChannel, "sidebar", new ContextProxy(mockContext))
|
||||
|
||||
defaultTaskOptions = {
|
||||
provider,
|
||||
apiConfiguration: {
|
||||
apiProvider: "openrouter",
|
||||
},
|
||||
}
|
||||
|
||||
// @ts-ignore - Access private property for testing
|
||||
updateGlobalStateSpy = jest.spyOn(provider.contextProxy, "setValue")
|
||||
|
||||
|
|
@ -451,8 +449,7 @@ describe("ClineProvider", () => {
|
|||
|
||||
test("clearTask aborts current task", async () => {
|
||||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline = new Cline() // Create a new mocked instance
|
||||
const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
|
||||
|
||||
// add the mock object to the stack
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
|
@ -475,9 +472,8 @@ describe("ClineProvider", () => {
|
|||
|
||||
test("addClineToStack adds multiple Cline instances to the stack", async () => {
|
||||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline1 = new Cline() // Create a new mocked instance
|
||||
const mockCline2 = new Cline() // Create a new mocked instance
|
||||
const mockCline1 = new Task(defaultTaskOptions) // Create a new mocked instance
|
||||
const mockCline2 = new Task(defaultTaskOptions) // Create a new mocked instance
|
||||
Object.defineProperty(mockCline1, "taskId", { value: "test-task-id-1", writable: true })
|
||||
Object.defineProperty(mockCline2, "taskId", { value: "test-task-id-2", writable: true })
|
||||
|
||||
|
|
@ -833,15 +829,11 @@ describe("ClineProvider", () => {
|
|||
experiments: experimentDefault,
|
||||
} as any)
|
||||
|
||||
// Reset Cline mock
|
||||
const { Cline } = require("../../Cline")
|
||||
;(Cline as jest.Mock).mockClear()
|
||||
|
||||
// Initialize Cline with a task
|
||||
await provider.initClineWithTask("Test task")
|
||||
|
||||
// Verify Cline was initialized with mode-specific instructions
|
||||
expect(Cline).toHaveBeenCalledWith({
|
||||
expect(Task).toHaveBeenCalledWith({
|
||||
provider,
|
||||
apiConfiguration: mockApiConfig,
|
||||
customInstructions: modeCustomInstructions,
|
||||
|
|
@ -958,13 +950,19 @@ describe("ClineProvider", () => {
|
|||
{ ts: 4000, type: "say", say: "browser_action" }, // Response to delete
|
||||
{ ts: 5000, type: "say", say: "user_feedback" }, // Next user message
|
||||
{ ts: 6000, type: "say", say: "user_feedback" }, // Final message
|
||||
]
|
||||
] as ClineMessage[]
|
||||
|
||||
const mockApiHistory = [{ ts: 1000 }, { ts: 2000 }, { ts: 3000 }, { ts: 4000 }, { ts: 5000 }, { ts: 6000 }]
|
||||
const mockApiHistory = [
|
||||
{ ts: 1000 },
|
||||
{ ts: 2000 },
|
||||
{ ts: 3000 },
|
||||
{ ts: 4000 },
|
||||
{ ts: 5000 },
|
||||
{ ts: 6000 },
|
||||
] as (Anthropic.MessageParam & { ts?: number })[]
|
||||
|
||||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline = new Cline() // Create a new mocked instance
|
||||
// Setup Task instance with auto-mock from the top of the file
|
||||
const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
|
||||
mockCline.clineMessages = mockMessages // Set test-specific messages
|
||||
mockCline.apiConversationHistory = mockApiHistory // Set API history
|
||||
await provider.addClineToStack(mockCline) // Add the mocked instance to the stack
|
||||
|
|
@ -1005,13 +1003,19 @@ describe("ClineProvider", () => {
|
|||
{ ts: 2000, type: "say", say: "text", value: 3000 }, // Message to delete
|
||||
{ ts: 3000, type: "say", say: "user_feedback" },
|
||||
{ ts: 4000, type: "say", say: "user_feedback" },
|
||||
]
|
||||
] as ClineMessage[]
|
||||
|
||||
const mockApiHistory = [{ ts: 1000 }, { ts: 2000 }, { ts: 3000 }, { ts: 4000 }]
|
||||
const mockApiHistory = [
|
||||
{ ts: 1000 },
|
||||
{ ts: 2000 },
|
||||
{ ts: 3000 },
|
||||
{ ts: 4000 },
|
||||
] as (Anthropic.MessageParam & {
|
||||
ts?: number
|
||||
})[]
|
||||
|
||||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline = new Cline() // Create a new mocked instance
|
||||
const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
|
||||
mockCline.clineMessages = mockMessages
|
||||
mockCline.apiConversationHistory = mockApiHistory
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
|
@ -1037,10 +1041,11 @@ describe("ClineProvider", () => {
|
|||
;(vscode.window.showInformationMessage as jest.Mock).mockResolvedValue("Cancel")
|
||||
|
||||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline = new Cline() // Create a new mocked instance
|
||||
mockCline.clineMessages = [{ ts: 1000 }, { ts: 2000 }]
|
||||
mockCline.apiConversationHistory = [{ ts: 1000 }, { ts: 2000 }]
|
||||
const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
|
||||
mockCline.clineMessages = [{ ts: 1000 }, { ts: 2000 }] as ClineMessage[]
|
||||
mockCline.apiConversationHistory = [{ ts: 1000 }, { ts: 2000 }] as (Anthropic.MessageParam & {
|
||||
ts?: number
|
||||
})[]
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
||||
// Trigger message deletion
|
||||
|
|
@ -1212,15 +1217,16 @@ describe("ClineProvider", () => {
|
|||
})
|
||||
|
||||
test("passes diffEnabled: false to SYSTEM_PROMPT when diff is disabled", async () => {
|
||||
// Setup Cline instance with mocked api.getModel()
|
||||
const { Cline } = require("../../Cline")
|
||||
const mockCline = new Cline()
|
||||
// Setup Task instance with mocked api.getModel()
|
||||
const mockCline = new Task(defaultTaskOptions)
|
||||
|
||||
mockCline.api = {
|
||||
getModel: jest.fn().mockReturnValue({
|
||||
id: "claude-3-sonnet",
|
||||
info: { supportsComputerUse: true },
|
||||
}),
|
||||
}
|
||||
} as any
|
||||
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
||||
// Mock getState to return diffEnabled: false
|
||||
|
|
@ -1742,9 +1748,8 @@ describe("ClineProvider", () => {
|
|||
.mockResolvedValue([{ name: "test-config", id: "test-id", apiProvider: "anthropic" }]),
|
||||
} as any
|
||||
|
||||
// Setup Cline instance with auto-mock from the top of the file
|
||||
const { Cline } = require("../../Cline") // Get the mocked class
|
||||
const mockCline = new Cline() // Create a new mocked instance
|
||||
// Setup Task instance with auto-mock from the top of the file
|
||||
const mockCline = new Task(defaultTaskOptions) // Create a new mocked instance
|
||||
await provider.addClineToStack(mockCline)
|
||||
|
||||
const testApiConfig = {
|
||||
|
|
@ -2084,6 +2089,7 @@ describe.skip("ContextProxy integration", () => {
|
|||
})
|
||||
|
||||
describe("getTelemetryProperties", () => {
|
||||
let defaultTaskOptions: TaskOptions
|
||||
let provider: ClineProvider
|
||||
let mockContext: vscode.ExtensionContext
|
||||
let mockOutputChannel: vscode.OutputChannel
|
||||
|
|
@ -2113,9 +2119,15 @@ describe("getTelemetryProperties", () => {
|
|||
mockOutputChannel = { appendLine: jest.fn() } as unknown as vscode.OutputChannel
|
||||
provider = new ClineProvider(mockContext, mockOutputChannel, "sidebar", new ContextProxy(mockContext))
|
||||
|
||||
// Setup Cline instance with mocked getModel method
|
||||
const { Cline } = require("../../Cline")
|
||||
mockCline = new Cline()
|
||||
defaultTaskOptions = {
|
||||
provider,
|
||||
apiConfiguration: {
|
||||
apiProvider: "openrouter",
|
||||
},
|
||||
}
|
||||
|
||||
// Setup Task instance with mocked getModel method
|
||||
mockCline = new Task(defaultTaskOptions)
|
||||
mockCline.api = {
|
||||
getModel: jest.fn().mockReturnValue({
|
||||
id: "claude-3-7-sonnet-20250219",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue