Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/api/providers/fetchers/litellm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ export async function getLiteLLMModels(apiKey: string, baseUrl: string): Promise
outputPrice: modelInfo.output_cost_per_token
? modelInfo.output_cost_per_token * 1000000
: undefined,
cacheWritesPrice: modelInfo.cache_creation_input_token_cost ? modelInfo.cache_creation_input_token_cost * 1000000 : undefined,
cacheReadsPrice: modelInfo.cache_read_input_token_cost ? modelInfo.cache_read_input_token_cost * 1000000 : undefined,
cacheWritesPrice: modelInfo.cache_creation_input_token_cost
? modelInfo.cache_creation_input_token_cost * 1000000
: undefined,
cacheReadsPrice: modelInfo.cache_read_input_token_cost
? modelInfo.cache_read_input_token_cost * 1000000
: undefined,
description: `${modelName} via LiteLLM proxy`,
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/api/providers/lite-llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,13 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa
cacheReadTokens: lastUsage.prompt_tokens_details?.cached_tokens || 0,
}

usageData.totalCost = calculateApiCostOpenAI(info, usageData.inputTokens, usageData.outputTokens, usageData.cacheWriteTokens, usageData.cacheReadTokens)
usageData.totalCost = calculateApiCostOpenAI(
info,
usageData.inputTokens,
usageData.outputTokens,
usageData.cacheWriteTokens,
usageData.cacheReadTokens,
)

yield usageData
}
Expand Down Expand Up @@ -129,4 +135,4 @@ export class LiteLLMHandler extends RouterProvider implements SingleCompletionHa
// LiteLLM usage may include an extra field for Anthropic use cases.
interface LiteLLMUsage extends OpenAI.CompletionUsage {
cache_creation_input_tokens?: number
}
}
106 changes: 57 additions & 49 deletions src/core/tools/__tests__/readFileTool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,15 @@ jest.mock("../../../services/tree-sitter")

// Then create the mock functions
const addLineNumbersMock = jest.fn().mockImplementation((text, startLine = 1) => {
if (!text) return ""
const lines = typeof text === "string" ? text.split("\n") : [text]
return lines.map((line, i) => `${startLine + i} | ${line}`).join("\n")
if (!text) return ""
const lines = typeof text === "string" ? text.split("\n") : [text]
return lines.map((line, i) => `${startLine + i} | ${line}`).join("\n")
})

const extractTextFromFileMock = jest.fn().mockImplementation((_filePath) => {
// Call addLineNumbersMock to register the call
addLineNumbersMock(mockInputContent)
return Promise.resolve(addLineNumbersMock(mockInputContent))
// Call addLineNumbersMock to register the call
addLineNumbersMock(mockInputContent)
return Promise.resolve(addLineNumbersMock(mockInputContent))
})

// Now assign the mocks to the module
Expand Down Expand Up @@ -104,7 +104,7 @@ describe("read_file tool with maxReadFileLine setting", () => {
// Setup the extractTextFromFile mock implementation with the current mockInputContent
// Reset the spy before each test
addLineNumbersMock.mockClear()

// Setup the extractTextFromFile mock to call our spy
mockedExtractTextFromFile.mockImplementation((_filePath) => {
// Call the spy and return its result
Expand Down Expand Up @@ -170,7 +170,6 @@ describe("read_file tool with maxReadFileLine setting", () => {
}
argsContent += `</file>`


// Create a tool use object
const toolUse: ReadFileToolUse = {
type: "tool_use",
Expand All @@ -190,7 +189,6 @@ describe("read_file tool with maxReadFileLine setting", () => {
(_: ToolParamName, content?: string) => content ?? "",
)


return toolResult
}

Expand All @@ -208,7 +206,6 @@ describe("read_file tool with maxReadFileLine setting", () => {
// Don't check exact content or exact function calls
})


it("should not show line snippet in approval message when maxReadFileLine is -1", async () => {
// This test verifies the line snippet behavior for the approval message
// Setup - use default mockInputContent
Expand Down Expand Up @@ -341,7 +338,7 @@ describe("read_file tool with maxReadFileLine setting", () => {

// Make sure mockCline.ask returns approval
mockCline.ask = jest.fn().mockResolvedValue({ response: "yesButtonClicked" })

// Execute - skip addLineNumbers check
const result = await executeReadFileTool(
{},
Expand All @@ -367,10 +364,13 @@ describe("read_file tool with maxReadFileLine setting", () => {
mockedReadLines.mockResolvedValue("Line 2\nLine 3\nLine 4")

// Execute using executeReadFileTool with range parameters
const rangeResult = await executeReadFileTool({},{
start_line: "2",
end_line: "4",
})
const rangeResult = await executeReadFileTool(
{},
{
start_line: "2",
end_line: "4",
},
)

// Verify - just check that the result contains the expected elements
expect(rangeResult).toContain(`<file><path>${testFilePath}</path>`)
Expand Down Expand Up @@ -469,15 +469,12 @@ describe("read_file tool XML output structure", () => {
mockedIsBinaryFile.mockResolvedValue(isBinary)
mockCline.rooIgnoreController.validateAccess = jest.fn().mockReturnValue(validateAccess)



let argsContent = `<file><path>${options.path || testFilePath}</path>`
if (options.start_line && options.end_line) {
argsContent += `<line_range>${options.start_line}-${options.end_line}</line_range>`
}
argsContent += `</file>`


// Create a tool use object
const toolUse: ReadFileToolUse = {
type: "tool_use",
Expand All @@ -486,7 +483,6 @@ describe("read_file tool XML output structure", () => {
partial: false,
}


// Execute the tool
await readFileTool(
mockCline,
Expand All @@ -507,7 +503,7 @@ describe("read_file tool XML output structure", () => {
// Skip this test for now - it requires more complex mocking
// of the formatResponse module which is causing issues
expect(true).toBe(true)

mockedCountFileLines.mockResolvedValue(1)

// Execute
Expand All @@ -520,15 +516,15 @@ describe("read_file tool XML output structure", () => {
// Skip this test for now - it requires more complex mocking
// of the formatResponse module which is causing issues
expect(true).toBe(true)

// Mock the file content
mockInputContent = "Test content"

// Mock the extractTextFromFile to return numbered content
mockedExtractTextFromFile.mockImplementation(() => {
return Promise.resolve("1 | Test content")
})

mockedCountFileLines.mockResolvedValue(1)

// Execute
Expand Down Expand Up @@ -605,30 +601,33 @@ describe("read_file tool XML output structure", () => {
// Setup
const startLine = 2
const endLine = 5

// For line range tests, we need to mock both readLines and addLineNumbers
const content = "Line 2\nLine 3\nLine 4\nLine 5"
const numberedContent = "2 | Line 2\n3 | Line 3\n4 | Line 4\n5 | Line 5"

// Mock readLines to return the content
mockedReadLines.mockResolvedValue(content)

// Mock addLineNumbers to return the numbered content
addLineNumbersMock.mockImplementation((_text?: any, start?: any) => {
if (start === 2) {
return numberedContent
}
return _text || ""
})

mockedCountFileLines.mockResolvedValue(endLine)
mockProvider.getState.mockResolvedValue({ maxReadFileLine: endLine })

// Execute with line range parameters
const result = await executeReadFileTool({}, {
start_line: startLine.toString(),
end_line: endLine.toString()
})
const result = await executeReadFileTool(
{},
{
start_line: startLine.toString(),
end_line: endLine.toString(),
},
)

// Verify
expect(result).toBe(
Expand All @@ -641,27 +640,30 @@ describe("read_file tool XML output structure", () => {
const endLine = 3
const content = "Line 1\nLine 2\nLine 3"
const numberedContent = "1 | Line 1\n2 | Line 2\n3 | Line 3"

// Mock readLines to return the content
mockedReadLines.mockResolvedValue(content)

// Mock addLineNumbers to return the numbered content
addLineNumbersMock.mockImplementation((_text?: any, start?: any) => {
if (start === 1) {
return numberedContent
}
return _text || ""
})

mockedCountFileLines.mockResolvedValue(endLine)
mockProvider.getState.mockResolvedValue({ maxReadFileLine: 500 })

// Execute with line range parameters
const result = await executeReadFileTool({}, {
start_line: "1",
end_line: endLine.toString(),
totalLines: endLine
})
const result = await executeReadFileTool(
{},
{
start_line: "1",
end_line: endLine.toString(),
totalLines: endLine,
},
)

// Verify
expect(result).toBe(
Expand Down Expand Up @@ -727,27 +729,30 @@ describe("read_file tool XML output structure", () => {
const startLine = 3
const content = "Line 3\nLine 4\nLine 5"
const numberedContent = "3 | Line 3\n4 | Line 4\n5 | Line 5"

// Mock readLines to return the content
mockedReadLines.mockResolvedValue(content)

// Mock addLineNumbers to return the numbered content
addLineNumbersMock.mockImplementation((_text?: any, start?: any) => {
if (start === 3) {
return numberedContent
}
return _text || ""
})

mockedCountFileLines.mockResolvedValue(totalLines)
mockProvider.getState.mockResolvedValue({ maxReadFileLine: totalLines })

// Execute with line range parameters
const result = await executeReadFileTool({}, {
start_line: startLine.toString(),
end_line: totalLines.toString(),
totalLines
})
const result = await executeReadFileTool(
{},
{
start_line: startLine.toString(),
end_line: totalLines.toString(),
totalLines,
},
)

// Should adjust to actual file length
expect(result).toBe(
Expand Down Expand Up @@ -780,11 +785,14 @@ describe("read_file tool XML output structure", () => {
mockedReadLines.mockResolvedValue(rangeContent)

// Execute
const result = await executeReadFileTool({},
const result = await executeReadFileTool(
{},
{
start_line: startLine.toString(),
end_line: endLine.toString(),
maxReadFileLine, totalLines },
maxReadFileLine,
totalLines,
},
)

// Verify
Expand Down
2 changes: 1 addition & 1 deletion src/integrations/misc/__tests__/read-file-tool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,4 @@ describe("read_file tool with maxReadFileLine setting", () => {
expect(readLines).toHaveBeenCalledWith(filePath, maxReadFileLine - 1, 0)
expect(addLineNumbers).toHaveBeenCalled()
})
})
})
1 change: 0 additions & 1 deletion src/shared/__tests__/experiments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ describe("experiments", () => {
const experiments: Record<ExperimentId, boolean> = {
powerSteering: false,
concurrentFileReads: false,

}
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
})
Expand Down