mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-06 08:18:39 +00:00
Ported from upstream Cline repository PR #5697 Original PR: https://github.com/cline/cline/pull/5697 - Added GroqUsage interface to handle cached token fields - Implemented proper cost calculation with cache read discounts - Enabled prompt caching for Kimi K2 model with 50% discount on cached tokens - Updated tests to verify caching functionality Co-authored-by: Cline Contributors <cline@github.com>
89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
import { type GroqModelId, groqDefaultModelId, groqModels } from "@roo-code/types"
|
|
import { Anthropic } from "@anthropic-ai/sdk"
|
|
import OpenAI from "openai"
|
|
|
|
import type { ApiHandlerOptions } from "../../shared/api"
|
|
import type { ApiHandlerCreateMessageMetadata } from "../index"
|
|
import { ApiStream } from "../transform/stream"
|
|
import { convertToOpenAiMessages } from "../transform/openai-format"
|
|
import { calculateApiCostOpenAI } from "../../shared/cost"
|
|
|
|
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
|
|
|
|
// Enhanced usage interface to support Groq's cached token fields
|
|
interface GroqUsage extends OpenAI.CompletionUsage {
|
|
prompt_tokens_details?: {
|
|
cached_tokens?: number
|
|
}
|
|
}
|
|
|
|
export class GroqHandler extends BaseOpenAiCompatibleProvider<GroqModelId> {
|
|
constructor(options: ApiHandlerOptions) {
|
|
super({
|
|
...options,
|
|
providerName: "Groq",
|
|
baseURL: "https://api.groq.com/openai/v1",
|
|
apiKey: options.groqApiKey,
|
|
defaultProviderModelId: groqDefaultModelId,
|
|
providerModels: groqModels,
|
|
defaultTemperature: 0.5,
|
|
})
|
|
}
|
|
|
|
override async *createMessage(
|
|
systemPrompt: string,
|
|
messages: Anthropic.Messages.MessageParam[],
|
|
metadata?: ApiHandlerCreateMessageMetadata,
|
|
): ApiStream {
|
|
const stream = await this.createStream(systemPrompt, messages, metadata)
|
|
|
|
for await (const chunk of stream) {
|
|
const delta = chunk.choices[0]?.delta
|
|
|
|
if (delta?.content) {
|
|
yield {
|
|
type: "text",
|
|
text: delta.content,
|
|
}
|
|
}
|
|
|
|
if (chunk.usage) {
|
|
yield* this.yieldUsage(chunk.usage as GroqUsage)
|
|
}
|
|
}
|
|
}
|
|
|
|
private async *yieldUsage(usage: GroqUsage | undefined): ApiStream {
|
|
const { info } = this.getModel()
|
|
const inputTokens = usage?.prompt_tokens || 0
|
|
const outputTokens = usage?.completion_tokens || 0
|
|
|
|
const cacheReadTokens = usage?.prompt_tokens_details?.cached_tokens || 0
|
|
|
|
// Groq does not track cache writes
|
|
const cacheWriteTokens = 0
|
|
|
|
// Calculate cost using OpenAI-compatible cost calculation
|
|
const totalCost = calculateApiCostOpenAI(info, inputTokens, outputTokens, cacheWriteTokens, cacheReadTokens)
|
|
|
|
// Calculate non-cached input tokens for proper reporting
|
|
const nonCachedInputTokens = Math.max(0, inputTokens - cacheReadTokens - cacheWriteTokens)
|
|
|
|
console.log("usage", {
|
|
inputTokens: nonCachedInputTokens,
|
|
outputTokens,
|
|
cacheWriteTokens,
|
|
cacheReadTokens,
|
|
totalCost,
|
|
})
|
|
|
|
yield {
|
|
type: "usage",
|
|
inputTokens: nonCachedInputTokens,
|
|
outputTokens,
|
|
cacheWriteTokens,
|
|
cacheReadTokens,
|
|
totalCost,
|
|
}
|
|
}
|
|
}
|