Skip to content
Merged
2 changes: 2 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
}
],
"@typescript-eslint/semi": "off",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_" }],
"eqeqeq": "warn",
"no-throw-literal": "warn",
"semi": "off"
Expand Down
9 changes: 0 additions & 9 deletions e2e/src/suite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,6 @@ export async function run() {
apiProvider: "openrouter" as const,
openRouterApiKey: process.env.OPENROUTER_API_KEY!,
openRouterModelId: "google/gemini-2.0-flash-001",
openRouterModelInfo: {
maxTokens: 8192,
contextWindow: 1000000,
supportsImages: true,
supportsPromptCache: false,
inputPrice: 0.1,
outputPrice: 0.4,
thinking: false,
},
})

await vscode.commands.executeCommand("roo-cline.SidebarProvider.focus")
Expand Down
2 changes: 0 additions & 2 deletions e2e/src/suite/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import * as vscode from "vscode"

import type { RooCodeAPI } from "../../../src/exports/roo-code"

type WaitForOptions = {
Expand Down
3 changes: 1 addition & 2 deletions evals/apps/web/src/app/runs/new/new-run.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ export function NewRun() {
}

const openRouterModelId = openRouterModel.id
const openRouterModelInfo = openRouterModel.modelInfo
values.settings = { ...(values.settings || {}), openRouterModelId, openRouterModelInfo }
values.settings = { ...(values.settings || {}), openRouterModelId }
}

const { id } = await createRun(values)
Expand Down
8 changes: 0 additions & 8 deletions evals/packages/types/src/roo-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,10 @@ export const providerSettingsSchema = z.object({
anthropicUseAuthToken: z.boolean().optional(),
// Glama
glamaModelId: z.string().optional(),
glamaModelInfo: modelInfoSchema.optional(),
glamaApiKey: z.string().optional(),
// OpenRouter
openRouterApiKey: z.string().optional(),
openRouterModelId: z.string().optional(),
openRouterModelInfo: modelInfoSchema.optional(),
openRouterBaseUrl: z.string().optional(),
openRouterSpecificProvider: z.string().optional(),
openRouterUseMiddleOutTransform: z.boolean().optional(),
Expand Down Expand Up @@ -371,11 +369,9 @@ export const providerSettingsSchema = z.object({
// Unbound
unboundApiKey: z.string().optional(),
unboundModelId: z.string().optional(),
unboundModelInfo: modelInfoSchema.optional(),
// Requesty
requestyApiKey: z.string().optional(),
requestyModelId: z.string().optional(),
requestyModelInfo: modelInfoSchema.optional(),
// Claude 3.7 Sonnet Thinking
modelMaxTokens: z.number().optional(), // Currently only used by Anthropic hybrid thinking models.
modelMaxThinkingTokens: z.number().optional(), // Currently only used by Anthropic hybrid thinking models.
Expand All @@ -401,12 +397,10 @@ const providerSettingsRecord: ProviderSettingsRecord = {
anthropicUseAuthToken: undefined,
// Glama
glamaModelId: undefined,
glamaModelInfo: undefined,
glamaApiKey: undefined,
// OpenRouter
openRouterApiKey: undefined,
openRouterModelId: undefined,
openRouterModelInfo: undefined,
openRouterBaseUrl: undefined,
openRouterSpecificProvider: undefined,
openRouterUseMiddleOutTransform: undefined,
Expand Down Expand Up @@ -460,11 +454,9 @@ const providerSettingsRecord: ProviderSettingsRecord = {
// Unbound
unboundApiKey: undefined,
unboundModelId: undefined,
unboundModelInfo: undefined,
// Requesty
requestyApiKey: undefined,
requestyModelId: undefined,
requestyModelInfo: undefined,
// Claude 3.7 Sonnet Thinking
modelMaxTokens: undefined,
modelMaxThinkingTokens: undefined,
Expand Down
4 changes: 2 additions & 2 deletions src/__mocks__/McpHub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ export class McpHub {
this.callTool = jest.fn()
}

async toggleToolAlwaysAllow(serverName: string, toolName: string, shouldAllow: boolean): Promise<void> {
async toggleToolAlwaysAllow(_serverName: string, _toolName: string, _shouldAllow: boolean): Promise<void> {
return Promise.resolve()
}

async callTool(serverName: string, toolName: string, toolArguments?: Record<string, unknown>): Promise<any> {
async callTool(_serverName: string, _toolName: string, _toolArguments?: Record<string, unknown>): Promise<any> {
return Promise.resolve({ result: "success" })
}
}
5 changes: 0 additions & 5 deletions src/__tests__/migrateSettings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ jest.mock("vscode")
jest.mock("fs/promises")
jest.mock("fs")
jest.mock("../utils/fs")
// We're testing the real migrateSettings function

describe("Settings Migration", () => {
let mockContext: vscode.ExtensionContext
Expand Down Expand Up @@ -52,8 +51,6 @@ describe("Settings Migration", () => {
})

it("should migrate custom modes file if old file exists and new file doesn't", async () => {
const mockCustomModesContent = '{"customModes":[{"slug":"test-mode"}]}' as string

// Mock file existence checks
;(fileExistsAtPath as jest.Mock).mockImplementation(async (path: string) => {
if (path === mockSettingsDir) return true
Expand All @@ -69,8 +66,6 @@ describe("Settings Migration", () => {
})

it("should migrate MCP settings file if old file exists and new file doesn't", async () => {
const mockMcpSettingsContent = '{"mcpServers":{"test-server":{}}}' as string

// Mock file existence checks
;(fileExistsAtPath as jest.Mock).mockImplementation(async (path: string) => {
if (path === mockSettingsDir) return true
Expand Down
1 change: 0 additions & 1 deletion src/activate/registerCodeActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import * as vscode from "vscode"
import { ACTION_NAMES, COMMAND_IDS } from "../core/CodeActionProvider"
import { EditorUtils } from "../core/EditorUtils"
import { ClineProvider } from "../core/webview/ClineProvider"
import { telemetryService } from "../services/telemetry/TelemetryService"

export const registerCodeActions = (context: vscode.ExtensionContext) => {
registerCodeActionPair(
Expand Down
12 changes: 7 additions & 5 deletions src/activate/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import * as vscode from "vscode"
import delay from "delay"

import { ClineProvider } from "../core/webview/ClineProvider"
import { ContextProxy } from "../core/config/ContextProxy"

import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRelayResponse } from "./humanRelay"
import { handleNewTask } from "./handleTask"

/**
* Helper to get the visible ClineProvider instance or log if not found.
Expand All @@ -15,9 +19,6 @@ export function getVisibleProviderOrLog(outputChannel: vscode.OutputChannel): Cl
return visibleProvider
}

import { registerHumanRelayCallback, unregisterHumanRelayCallback, handleHumanRelayResponse } from "./humanRelay"
import { handleNewTask } from "./handleTask"

// Store panel references in both modes
let sidebarPanel: vscode.WebviewView | undefined = undefined
let tabPanel: vscode.WebviewPanel | undefined = undefined
Expand Down Expand Up @@ -53,7 +54,7 @@ export type RegisterCommandOptions = {
}

export const registerCommands = (options: RegisterCommandOptions) => {
const { context, outputChannel } = options
const { context } = options

for (const [command, callback] of Object.entries(getCommandsMap(options))) {
context.subscriptions.push(vscode.commands.registerCommand(command, callback))
Expand Down Expand Up @@ -142,7 +143,8 @@ export const openClineInNewTab = async ({ context, outputChannel }: Omit<Registe
// deserialize cached webview, but since we use retainContextWhenHidden, we
// don't need to use that event).
// https://github.com/microsoft/vscode-extension-samples/blob/main/webview-sample/src/extension.ts
const tabProvider = new ClineProvider(context, outputChannel, "editor")
const contextProxy = await ContextProxy.getInstance(context)
const tabProvider = new ClineProvider(context, outputChannel, "editor", contextProxy)
const lastCol = Math.max(...vscode.window.visibleTextEditors.map((editor) => editor.viewColumn || 0))

// Check if there are any visible text editors, otherwise open a new group
Expand Down
89 changes: 26 additions & 63 deletions src/api/providers/__tests__/glama.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// npx jest src/api/providers/__tests__/glama.test.ts

import { Anthropic } from "@anthropic-ai/sdk"
import axios from "axios"

import { GlamaHandler } from "../glama"
import { ApiHandlerOptions } from "../../../shared/api"
Expand All @@ -20,31 +19,18 @@ jest.mock("openai", () => {
const stream = {
[Symbol.asyncIterator]: async function* () {
yield {
choices: [
{
delta: { content: "Test response" },
index: 0,
},
],
choices: [{ delta: { content: "Test response" }, index: 0 }],
usage: null,
}
yield {
choices: [
{
delta: {},
index: 0,
},
],
usage: {
prompt_tokens: 10,
completion_tokens: 5,
total_tokens: 15,
},
choices: [{ delta: {}, index: 0 }],
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
}
},
}

const result = mockCreate(...args)

if (args[0].stream) {
mockWithResponse.mockReturnValue(
Promise.resolve({
Expand All @@ -59,6 +45,7 @@ jest.mock("openai", () => {
)
result.withResponse = mockWithResponse
}

return result
},
},
Expand All @@ -73,10 +60,10 @@ describe("GlamaHandler", () => {

beforeEach(() => {
mockOptions = {
apiModelId: "anthropic/claude-3-7-sonnet",
glamaModelId: "anthropic/claude-3-7-sonnet",
glamaApiKey: "test-api-key",
glamaModelId: "anthropic/claude-3-7-sonnet",
}

handler = new GlamaHandler(mockOptions)
mockCreate.mockClear()
mockWithResponse.mockClear()
Expand All @@ -102,7 +89,7 @@ describe("GlamaHandler", () => {
describe("constructor", () => {
it("should initialize with provided options", () => {
expect(handler).toBeInstanceOf(GlamaHandler)
expect(handler.getModel().id).toBe(mockOptions.apiModelId)
expect(handler.getModel().id).toBe(mockOptions.glamaModelId)
})
})

Expand All @@ -116,40 +103,15 @@ describe("GlamaHandler", () => {
]

it("should handle streaming responses", async () => {
// Mock axios for token usage request
const mockAxios = jest.spyOn(axios, "get").mockResolvedValueOnce({
data: {
tokenUsage: {
promptTokens: 10,
completionTokens: 5,
cacheCreationInputTokens: 0,
cacheReadInputTokens: 0,
},
totalCostUsd: "0.00",
},
})

const stream = handler.createMessage(systemPrompt, messages)
const chunks: any[] = []

for await (const chunk of stream) {
chunks.push(chunk)
}

expect(chunks.length).toBe(2) // Text chunk and usage chunk
expect(chunks[0]).toEqual({
type: "text",
text: "Test response",
})
expect(chunks[1]).toEqual({
type: "usage",
inputTokens: 10,
outputTokens: 5,
cacheWriteTokens: 0,
cacheReadTokens: 0,
totalCost: 0,
})

mockAxios.mockRestore()
expect(chunks.length).toBe(1)
expect(chunks[0]).toEqual({ type: "text", text: "Test response" })
})

it("should handle API errors", async () => {
Expand Down Expand Up @@ -178,7 +140,7 @@ describe("GlamaHandler", () => {
expect(result).toBe("Test response")
expect(mockCreate).toHaveBeenCalledWith(
expect.objectContaining({
model: mockOptions.apiModelId,
model: mockOptions.glamaModelId,
messages: [{ role: "user", content: "Test prompt" }],
temperature: 0,
max_tokens: 8192,
Expand All @@ -204,22 +166,16 @@ describe("GlamaHandler", () => {
mockCreate.mockClear()

const nonAnthropicOptions = {
apiModelId: "openai/gpt-4",
glamaModelId: "openai/gpt-4",
glamaApiKey: "test-key",
glamaModelInfo: {
maxTokens: 4096,
contextWindow: 8192,
supportsImages: true,
supportsPromptCache: false,
},
glamaModelId: "openai/gpt-4o",
}

const nonAnthropicHandler = new GlamaHandler(nonAnthropicOptions)

await nonAnthropicHandler.completePrompt("Test prompt")
expect(mockCreate).toHaveBeenCalledWith(
expect.objectContaining({
model: "openai/gpt-4",
model: "openai/gpt-4o",
messages: [{ role: "user", content: "Test prompt" }],
temperature: 0,
}),
Expand All @@ -228,13 +184,20 @@ describe("GlamaHandler", () => {
})
})

describe("getModel", () => {
it("should return model info", () => {
const modelInfo = handler.getModel()
expect(modelInfo.id).toBe(mockOptions.apiModelId)
describe("fetchModel", () => {
it("should return model info", async () => {
const modelInfo = await handler.fetchModel()
expect(modelInfo.id).toBe(mockOptions.glamaModelId)
expect(modelInfo.info).toBeDefined()
expect(modelInfo.info.maxTokens).toBe(8192)
expect(modelInfo.info.contextWindow).toBe(200_000)
})

it("should return default model when invalid model provided", async () => {
const handlerWithInvalidModel = new GlamaHandler({ ...mockOptions, glamaModelId: "invalid/model" })
const modelInfo = await handlerWithInvalidModel.fetchModel()
expect(modelInfo.id).toBe("anthropic/claude-3-7-sonnet")
expect(modelInfo.info).toBeDefined()
})
})
})
Loading
Loading