mirror of
https://github.com/cline/cline.git
synced 2026-09-06 12:28:08 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 347cdcb5a7 | |||
| 2315e49c82 |
@@ -47,6 +47,7 @@ export type CommonApiHandlerOptions = {
|
||||
}
|
||||
|
||||
export interface ApiHandler {
|
||||
id: string
|
||||
createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[], tools?: ClineTool[]): ApiStream
|
||||
getModel(): ApiHandlerModel
|
||||
getApiStreamUsage?(): Promise<ApiStreamUsageChunk | undefined>
|
||||
@@ -75,7 +76,7 @@ function createHandlerForProvider(
|
||||
): ApiHandler {
|
||||
switch (apiProvider) {
|
||||
case "anthropic":
|
||||
return new AnthropicHandler({
|
||||
return new AnthropicHandler("anthropic", {
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
apiKey: options.apiKey,
|
||||
anthropicBaseUrl: options.anthropicBaseUrl,
|
||||
@@ -406,7 +407,7 @@ function createHandlerForProvider(
|
||||
hicapModelId: mode === "plan" ? options.planModeHicapModelId : options.actModeHicapModelId,
|
||||
})
|
||||
default:
|
||||
return new AnthropicHandler({
|
||||
return new AnthropicHandler(apiProvider, {
|
||||
onRetryAttempt: options.onRetryAttempt,
|
||||
apiKey: options.apiKey,
|
||||
anthropicBaseUrl: options.anthropicBaseUrl,
|
||||
|
||||
@@ -18,7 +18,10 @@ export class AnthropicHandler implements ApiHandler {
|
||||
private options: AnthropicHandlerOptions
|
||||
private client: Anthropic | undefined
|
||||
|
||||
constructor(options: AnthropicHandlerOptions) {
|
||||
constructor(
|
||||
public readonly id = "anthropic",
|
||||
options: AnthropicHandlerOptions,
|
||||
) {
|
||||
this.options = options
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ type AskSageResponse = {
|
||||
}
|
||||
|
||||
export class AskSageHandler implements ApiHandler {
|
||||
public readonly id = "asksage"
|
||||
private options: AskSageHandlerOptions
|
||||
private apiUrl: string
|
||||
private apiKey: string
|
||||
|
||||
@@ -15,6 +15,7 @@ interface BasetenHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class BasetenHandler implements ApiHandler {
|
||||
public readonly id = "baseten"
|
||||
private options: BasetenHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -114,6 +114,7 @@ const JP_SUPPORTED_CRIS_MODELS = ["anthropic.claude-sonnet-4-5-20250929-v1:0", "
|
||||
|
||||
// https://docs.anthropic.com/en/api/claude-on-amazon-bedrock
|
||||
export class AwsBedrockHandler implements ApiHandler {
|
||||
public readonly id = "bedrock"
|
||||
private options: AwsBedrockHandlerOptions
|
||||
|
||||
constructor(options: AwsBedrockHandlerOptions) {
|
||||
|
||||
@@ -11,6 +11,7 @@ interface CerebrasHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class CerebrasHandler implements ApiHandler {
|
||||
public readonly id = "cerebras"
|
||||
private options: CerebrasHandlerOptions
|
||||
private client: Cerebras | undefined
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ interface ClaudeCodeHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class ClaudeCodeHandler implements ApiHandler {
|
||||
public readonly id = "claude-code"
|
||||
private options: ClaudeCodeHandlerOptions
|
||||
|
||||
constructor(options: ClaudeCodeHandlerOptions) {
|
||||
|
||||
@@ -28,6 +28,7 @@ interface ClineHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class ClineHandler implements ApiHandler {
|
||||
public readonly id = "cline"
|
||||
private options: ClineHandlerOptions
|
||||
private clineAccountService = ClineAccountService.getInstance()
|
||||
private _authService: AuthService
|
||||
|
||||
@@ -16,6 +16,7 @@ interface DeepSeekHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class DeepSeekHandler implements ApiHandler {
|
||||
public readonly id = "deepseek"
|
||||
private options: DeepSeekHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ interface DifyConversationResponse {
|
||||
}
|
||||
|
||||
export class DifyHandler implements ApiHandler {
|
||||
public readonly id = "dify"
|
||||
private options: DifyHandlerOptions
|
||||
private baseUrl: string
|
||||
private apiKey: string
|
||||
|
||||
@@ -12,6 +12,7 @@ interface DoubaoHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class DoubaoHandler implements ApiHandler {
|
||||
public readonly id = "doubao"
|
||||
private options: DoubaoHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
constructor(options: DoubaoHandlerOptions) {
|
||||
|
||||
@@ -14,6 +14,7 @@ interface FireworksHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class FireworksHandler implements ApiHandler {
|
||||
public readonly id = "fireworks"
|
||||
private options: FireworksHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ interface GeminiHandlerOptions extends CommonApiHandlerOptions {
|
||||
* 4. Separating immediate costs from ongoing costs to avoid double-counting
|
||||
*/
|
||||
export class GeminiHandler implements ApiHandler {
|
||||
public readonly id = "gemini"
|
||||
private options: GeminiHandlerOptions
|
||||
private client: GoogleGenAI | undefined
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ const MODEL_FAMILIES: Record<string, GroqModelFamily> = {
|
||||
}
|
||||
|
||||
export class GroqHandler implements ApiHandler {
|
||||
public readonly id = "groq"
|
||||
private options: GroqHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ interface OpenAiHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class HicapHandler implements ApiHandler {
|
||||
public readonly id = "hicap"
|
||||
private options: OpenAiHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ interface HuaweiCloudMaaSHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class HuaweiCloudMaaSHandler implements ApiHandler {
|
||||
public readonly id = "huawei-cloud-maas"
|
||||
private options: HuaweiCloudMaaSHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
constructor(options: HuaweiCloudMaaSHandlerOptions) {
|
||||
|
||||
@@ -16,6 +16,7 @@ interface HuggingFaceHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class HuggingFaceHandler implements ApiHandler {
|
||||
public readonly id = "huggingface"
|
||||
private options: HuggingFaceHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
private cachedModel: { id: HuggingFaceModelId; info: ModelInfo } | undefined
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface LiteLlmModelInfoResponse {
|
||||
}
|
||||
|
||||
export class LiteLlmHandler implements ApiHandler {
|
||||
public readonly id = "litellm"
|
||||
private options: LiteLlmHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
private modelInfoCache: LiteLlmModelInfoResponse | undefined
|
||||
|
||||
@@ -15,6 +15,7 @@ interface LmStudioHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class LmStudioHandler implements ApiHandler {
|
||||
public readonly id = "lmstudio"
|
||||
private options: LmStudioHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ interface MinimaxHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class MinimaxHandler implements ApiHandler {
|
||||
public readonly id = "minimax"
|
||||
private options: MinimaxHandlerOptions
|
||||
private client: Anthropic | undefined
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ interface MistralHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class MistralHandler implements ApiHandler {
|
||||
public readonly id = "mistral"
|
||||
private options: MistralHandlerOptions
|
||||
private client: Mistral | undefined
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ interface MoonshotHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class MoonshotHandler implements ApiHandler {
|
||||
public readonly id = "moonshot"
|
||||
private client: OpenAI | undefined
|
||||
|
||||
constructor(private readonly options: MoonshotHandlerOptions) {}
|
||||
|
||||
@@ -15,6 +15,7 @@ interface NebiusHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class NebiusHandler implements ApiHandler {
|
||||
public readonly id = "nebius"
|
||||
private client: OpenAI | undefined
|
||||
|
||||
constructor(private readonly options: NebiusHandlerOptions) {}
|
||||
|
||||
@@ -28,6 +28,7 @@ export interface OcaHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class OcaHandler implements ApiHandler {
|
||||
public readonly id = "oca"
|
||||
protected options: OcaHandlerOptions
|
||||
protected client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ interface OllamaHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
const DEFAULT_CONTEXT_WINDOW = 32768
|
||||
|
||||
export class OllamaHandler implements ApiHandler {
|
||||
public readonly id = "ollama"
|
||||
private options: OllamaHandlerOptions
|
||||
private client: Ollama | undefined
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ interface OpenAiNativeHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class OpenAiNativeHandler implements ApiHandler {
|
||||
public readonly id = "openai-native"
|
||||
private options: OpenAiNativeHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ interface OpenAiHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class OpenAiHandler implements ApiHandler {
|
||||
public readonly id = "openai"
|
||||
private options: OpenAiHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ interface OpenRouterHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class OpenRouterHandler implements ApiHandler {
|
||||
public readonly id = "openrouter"
|
||||
private options: OpenRouterHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
lastGenerationId?: string
|
||||
|
||||
@@ -49,6 +49,7 @@ function objectToUrlEncoded(data: Record<string, string>): string {
|
||||
}
|
||||
|
||||
export class QwenCodeHandler implements ApiHandler {
|
||||
public readonly id = "qwen-code"
|
||||
private options: QwenCodeHandlerOptions
|
||||
private credentials: QwenOAuthCredentials | null = null
|
||||
private client: OpenAI | undefined
|
||||
|
||||
@@ -26,6 +26,7 @@ interface QwenHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class QwenHandler implements ApiHandler {
|
||||
public readonly id = "qwen"
|
||||
private options: QwenHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ interface RequestyUsage extends OpenAI.CompletionUsage {
|
||||
}
|
||||
|
||||
export class RequestyHandler implements ApiHandler {
|
||||
public readonly id = "requesty"
|
||||
private options: RequestyHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ interface SambanovaHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class SambanovaHandler implements ApiHandler {
|
||||
public readonly id = "sambanova"
|
||||
private options: SambanovaHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -352,6 +352,7 @@ namespace Gemini {
|
||||
}
|
||||
|
||||
export class SapAiCoreHandler implements ApiHandler {
|
||||
public readonly id = "sapaicore"
|
||||
private options: SapAiCoreHandlerOptions
|
||||
private token?: Token
|
||||
private deployments?: Deployment[]
|
||||
|
||||
@@ -15,6 +15,7 @@ interface TogetherHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class TogetherHandler implements ApiHandler {
|
||||
public readonly id = "together"
|
||||
private options: TogetherHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ interface VercelAIGatewayHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class VercelAIGatewayHandler implements ApiHandler {
|
||||
public readonly id = "vercel-ai-gateway"
|
||||
private options: VercelAIGatewayHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ interface VertexHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class VertexHandler implements ApiHandler {
|
||||
public readonly id = "vertex"
|
||||
private geminiHandler: GeminiHandler | undefined
|
||||
private clientAnthropic: AnthropicVertex | undefined
|
||||
private options: VertexHandlerOptions
|
||||
|
||||
@@ -128,6 +128,7 @@ declare module "vscode" {
|
||||
* ```
|
||||
*/
|
||||
export class VsCodeLmHandler implements ApiHandler, SingleCompletionHandler {
|
||||
public readonly id = "vscode-lm"
|
||||
private options: VsCodeLmHandlerOptions
|
||||
private client: vscode.LanguageModelChat | null
|
||||
private disposable: vscode.Disposable | null
|
||||
|
||||
@@ -17,6 +17,7 @@ interface XAIHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class XAIHandler implements ApiHandler {
|
||||
public readonly id = "xai"
|
||||
private options: XAIHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ interface ZAiHandlerOptions extends CommonApiHandlerOptions {
|
||||
}
|
||||
|
||||
export class ZAiHandler implements ApiHandler {
|
||||
public readonly id = "zai"
|
||||
private options: ZAiHandlerOptions
|
||||
private client: OpenAI | undefined
|
||||
constructor(options: ZAiHandlerOptions) {
|
||||
|
||||
@@ -1889,9 +1889,7 @@ export class Task {
|
||||
|
||||
private getCurrentProviderInfo(): ApiProviderInfo {
|
||||
const model = this.api.getModel()
|
||||
const apiConfig = this.stateManager.getApiConfiguration()
|
||||
const mode = this.stateManager.getGlobalSettingsKey("mode")
|
||||
const providerId = (mode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
const providerId = this.api.id
|
||||
const customPrompt = this.stateManager.getGlobalSettingsKey("customPrompt")
|
||||
return { model, providerId, customPrompt }
|
||||
}
|
||||
|
||||
@@ -45,10 +45,8 @@ export class AccessMcpResourceHandler implements IFullyManagedTool {
|
||||
const server_name: string | undefined = block.params.server_name
|
||||
const uri: string | undefined = block.params.uri
|
||||
|
||||
// Extract provider using the proven pattern from ReportBugHandler
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
// Validate required parameters
|
||||
if (!server_name) {
|
||||
@@ -80,7 +78,7 @@ export class AccessMcpResourceHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("use_mcp_server", completeMessage, undefined, undefined, false)
|
||||
|
||||
// Capture telemetry
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, true, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
const notificationMessage = `Cline wants to access ${uri || "unknown resource"} on ${server_name || "unknown server"}`
|
||||
@@ -92,10 +90,10 @@ export class AccessMcpResourceHandler implements IFullyManagedTool {
|
||||
|
||||
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("use_mcp_server", completeMessage, config)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, false)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false)
|
||||
return formatResponse.toolDenied()
|
||||
} else {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -942,16 +942,15 @@ export class ApplyPatchHandler implements IFullyManagedTool {
|
||||
primaryFile: string,
|
||||
): Promise<boolean> {
|
||||
// Extract provider using the proven pattern from ReportBugHandler
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
const messageStr = JSON.stringify(message)
|
||||
const shouldAutoApprove = await config.callbacks.shouldAutoApproveToolWithPath(block.name, primaryFile)
|
||||
|
||||
if (shouldAutoApprove) {
|
||||
await config.callbacks.say("tool", messageStr, undefined, undefined, false)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, true, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -971,7 +970,7 @@ export class ApplyPatchHandler implements IFullyManagedTool {
|
||||
|
||||
const approved = response === "yesButtonClicked"
|
||||
config.taskState.didRejectTool = !approved
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, approved)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, approved)
|
||||
|
||||
return approved
|
||||
}
|
||||
|
||||
@@ -53,10 +53,8 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
|
||||
const timeoutParam: string | undefined = block.params.timeout
|
||||
let timeoutSeconds: number | undefined
|
||||
|
||||
// Extract provider using the proven pattern from ReportBugHandler
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
// Validate required parameters
|
||||
if (!command) {
|
||||
@@ -78,7 +76,7 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
|
||||
}
|
||||
|
||||
// Pre-process command for certain models
|
||||
if (config.api.getModel().id.includes("gemini")) {
|
||||
if (modelId.includes("gemini")) {
|
||||
command = fixModelHtmlEscaping(command)
|
||||
}
|
||||
|
||||
@@ -158,15 +156,7 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "command")
|
||||
await config.callbacks.say("command", actualCommand, undefined, undefined, false)
|
||||
didAutoApprove = true
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
true,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true, workspaceContext)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
showNotificationForApproval(
|
||||
@@ -180,26 +170,10 @@ export class ExecuteCommandToolHandler implements IFullyManagedTool {
|
||||
config,
|
||||
)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
false,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false, workspaceContext)
|
||||
return formatResponse.toolDenied()
|
||||
}
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true, workspaceContext)
|
||||
}
|
||||
|
||||
// Setup timeout notification for long-running auto-approved commands
|
||||
|
||||
@@ -50,11 +50,6 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
|
||||
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
|
||||
const relDirPath: string | undefined = block.params.path
|
||||
|
||||
// Extract provider using the proven pattern from ReportBugHandler
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
|
||||
// Validate required parameters
|
||||
const pathValidation = this.validator.assertRequiredParams(block, "path")
|
||||
if (!pathValidation.ok) {
|
||||
@@ -80,6 +75,9 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
|
||||
operationIsLocatedInWorkspace: await isLocatedInWorkspace(relDirPath!),
|
||||
}
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
const completeMessage = JSON.stringify(sharedMessageProps)
|
||||
|
||||
if (await config.callbacks.shouldAutoApproveToolWithPath(block.name, relDirPath)) {
|
||||
@@ -88,7 +86,7 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("tool", completeMessage, undefined, undefined, false)
|
||||
|
||||
// Capture telemetry
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, true, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
const notificationMessage = `Cline wants to analyze code definitions in ${getWorkspaceBasename(absolutePath, "ListCodeDefinitionNamesToolHandler.notification")}`
|
||||
@@ -100,10 +98,10 @@ export class ListCodeDefinitionNamesToolHandler implements IFullyManagedTool {
|
||||
|
||||
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("tool", completeMessage, config)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, false)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false)
|
||||
return formatResponse.toolDenied()
|
||||
} else {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,11 +56,6 @@ export class ListFilesToolHandler implements IFullyManagedTool {
|
||||
const recursiveRaw: string | undefined = block.params.recursive
|
||||
const recursive = recursiveRaw?.toLowerCase() === "true"
|
||||
|
||||
// Extract provider using the proven pattern from ReportBugHandler
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
|
||||
// Validate required parameters
|
||||
const pathValidation = this.validator.assertRequiredParams(block, "path")
|
||||
if (!pathValidation.ok) {
|
||||
@@ -97,6 +92,9 @@ export class ListFilesToolHandler implements IFullyManagedTool {
|
||||
operationIsLocatedInWorkspace: await isLocatedInWorkspace(relDirPath!),
|
||||
}
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
const completeMessage = JSON.stringify(sharedMessageProps)
|
||||
|
||||
if (await config.callbacks.shouldAutoApproveToolWithPath(block.name, relDirPath)) {
|
||||
@@ -105,15 +103,7 @@ export class ListFilesToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("tool", completeMessage, undefined, undefined, false)
|
||||
|
||||
// Capture telemetry
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
true,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true, workspaceContext)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
const notificationMessage = `Cline wants to view directory ${getWorkspaceBasename(absolutePath, "ListFilesToolHandler.notification")}/`
|
||||
@@ -125,26 +115,10 @@ export class ListFilesToolHandler implements IFullyManagedTool {
|
||||
|
||||
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("tool", completeMessage, config)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
false,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false, workspaceContext)
|
||||
return formatResponse.toolDenied()
|
||||
} else {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true, workspaceContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,11 +52,6 @@ export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
async execute(config: TaskConfig, block: ToolUse): Promise<ToolResponse> {
|
||||
const relPath: string | undefined = block.params.path
|
||||
|
||||
// Extract provider information for telemetry
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
|
||||
// Validate required parameters
|
||||
const pathValidation = this.validator.assertRequiredParams(block, "path")
|
||||
if (!pathValidation.ok) {
|
||||
@@ -95,6 +90,9 @@ export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
operationIsLocatedInWorkspace: await isLocatedInWorkspace(relPath!),
|
||||
} satisfies ClineSayTool
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
const completeMessage = JSON.stringify(sharedMessageProps)
|
||||
|
||||
if (await config.callbacks.shouldAutoApproveToolWithPath(block.name, relPath)) {
|
||||
@@ -103,15 +101,7 @@ export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("tool", completeMessage, undefined, undefined, false)
|
||||
|
||||
// Capture telemetry
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
true,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true, workspaceContext)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
const notificationMessage = `Cline wants to read ${getWorkspaceBasename(absolutePath, "ReadFileToolHandler.notification")}`
|
||||
@@ -123,26 +113,10 @@ export class ReadFileToolHandler implements IFullyManagedTool {
|
||||
|
||||
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("tool", completeMessage, config)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
false,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false, workspaceContext)
|
||||
return formatResponse.toolDenied()
|
||||
} else {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true, workspaceContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,13 +74,13 @@ export class ReportBugHandler implements IToolHandler, IPartialBlockHandler {
|
||||
|
||||
// Derive system information values algorithmically
|
||||
const operatingSystem = os.platform() + " " + os.release()
|
||||
const currentMode = config.mode
|
||||
const clineVersion = ExtensionRegistryInfo.version
|
||||
const host = await HostProvider.env.getHostVersion({})
|
||||
const systemInfo = `${host.platform}: ${host.version}, Node.js: ${process.version}, Architecture: ${os.arch()}`
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const apiProvider = currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider
|
||||
const providerAndModel = `${apiProvider} / ${config.api.getModel().id}`
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
const providerAndModel = `${providerId} / ${modelId}`
|
||||
|
||||
// Ask user for confirmation
|
||||
const bugReportData = JSON.stringify({
|
||||
|
||||
@@ -207,11 +207,6 @@ export class SearchFilesToolHandler implements IFullyManagedTool {
|
||||
const regex: string | undefined = block.params.regex
|
||||
const filePattern: string | undefined = block.params.file_pattern
|
||||
|
||||
// Extract provider information for telemetry
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
|
||||
// Validate required parameters
|
||||
const pathValidation = this.validator.assertRequiredParams(block, "path")
|
||||
if (!pathValidation.ok) {
|
||||
@@ -303,6 +298,9 @@ export class SearchFilesToolHandler implements IFullyManagedTool {
|
||||
operationIsLocatedInWorkspace: await isLocatedInWorkspace(parsedPath),
|
||||
} satisfies ClineSayTool
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
const completeMessage = JSON.stringify(sharedMessageProps)
|
||||
|
||||
if (await config.callbacks.shouldAutoApproveToolWithPath(block.name, relDirPath)) {
|
||||
@@ -311,15 +309,7 @@ export class SearchFilesToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("tool", completeMessage, undefined, undefined, false)
|
||||
|
||||
// Capture telemetry
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
true,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true, workspaceContext)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
const notificationMessage = `Cline wants to search files for ${regex}`
|
||||
@@ -331,26 +321,10 @@ export class SearchFilesToolHandler implements IFullyManagedTool {
|
||||
|
||||
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("tool", completeMessage, config)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
false,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false, workspaceContext)
|
||||
return formatResponse.toolDenied()
|
||||
} else {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true, workspaceContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,11 +47,6 @@ export class UseMcpToolHandler implements IFullyManagedTool {
|
||||
const tool_name: string | undefined = block.params.tool_name
|
||||
const mcp_arguments: string | undefined = block.params.arguments
|
||||
|
||||
// Extract provider information for telemetry
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
|
||||
// Validate required parameters
|
||||
if (!server_name) {
|
||||
config.taskState.consecutiveMistakeCount++
|
||||
@@ -85,6 +80,9 @@ export class UseMcpToolHandler implements IFullyManagedTool {
|
||||
arguments: mcp_arguments,
|
||||
} satisfies ClineAskUseMcpServer)
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
const isToolAutoApproved = config.services.mcpHub.connections
|
||||
?.find((conn: any) => conn.server.name === server_name)
|
||||
?.server.tools?.find((tool: any) => tool.name === tool_name)?.autoApprove
|
||||
@@ -95,7 +93,7 @@ export class UseMcpToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("use_mcp_server", completeMessage, undefined, undefined, false)
|
||||
|
||||
// Capture telemetry
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, true, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
const notificationMessage = `Cline wants to use ${tool_name || "unknown tool"} on ${server_name || "unknown server"}`
|
||||
@@ -107,10 +105,10 @@ export class UseMcpToolHandler implements IFullyManagedTool {
|
||||
|
||||
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("use_mcp_server", completeMessage, config)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, false)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false)
|
||||
return formatResponse.toolDenied()
|
||||
} else {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,6 @@ export class WebFetchToolHandler implements IFullyManagedTool {
|
||||
try {
|
||||
const url: string | undefined = block.params.url
|
||||
|
||||
// Extract provider information for telemetry
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
|
||||
// Validate required parameter
|
||||
if (!url) {
|
||||
config.taskState.consecutiveMistakeCount++
|
||||
@@ -60,11 +55,14 @@ export class WebFetchToolHandler implements IFullyManagedTool {
|
||||
}
|
||||
const completeMessage = JSON.stringify(sharedMessageProps)
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
if (config.callbacks.shouldAutoApproveTool(this.name)) {
|
||||
// Auto-approve flow
|
||||
await config.callbacks.removeLastPartialMessageIfExistsWithType("ask", "tool")
|
||||
await config.callbacks.say("tool", completeMessage, undefined, undefined, false)
|
||||
telemetryService.captureToolUsage(config.ulid, "web_fetch", config.api.getModel().id, provider, true, true)
|
||||
telemetryService.captureToolUsage(config.ulid, "web_fetch", modelId, providerId, true, true)
|
||||
} else {
|
||||
// Manual approval flow
|
||||
showNotificationForApproval(
|
||||
@@ -75,10 +73,10 @@ export class WebFetchToolHandler implements IFullyManagedTool {
|
||||
|
||||
const didApprove = await ToolResultUtils.askApprovalAndPushFeedback("tool", completeMessage, config)
|
||||
if (!didApprove) {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, false)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, false)
|
||||
return formatResponse.toolDenied()
|
||||
} else {
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, config.api.getModel().id, provider, false, true)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,11 +92,6 @@ export class WriteToFileToolHandler implements IFullyManagedTool {
|
||||
const rawContent = block.params.content // for write_to_file
|
||||
const rawDiff = block.params.diff // for replace_in_file
|
||||
|
||||
// Extract provider information for telemetry
|
||||
const apiConfig = config.services.stateManager.getApiConfiguration()
|
||||
const currentMode = config.services.stateManager.getGlobalSettingsKey("mode")
|
||||
const provider = (currentMode === "plan" ? apiConfig.planModeApiProvider : apiConfig.actModeApiProvider) as string
|
||||
|
||||
// Validate required parameters based on tool type
|
||||
if (!rawRelPath) {
|
||||
config.taskState.consecutiveMistakeCount++
|
||||
@@ -156,6 +151,9 @@ export class WriteToFileToolHandler implements IFullyManagedTool {
|
||||
await config.services.diffViewProvider.scrollToFirstDiff()
|
||||
// showOmissionWarning(this.diffViewProvider.originalContent || "", newContent)
|
||||
|
||||
const modelId = config.api.getModel().id
|
||||
const providerId = config.api.id
|
||||
|
||||
const completeMessage = JSON.stringify({
|
||||
...sharedMessageProps,
|
||||
content: diff || content,
|
||||
@@ -174,15 +172,7 @@ export class WriteToFileToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("tool", completeMessage, undefined, undefined, false)
|
||||
|
||||
// Capture telemetry
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
true,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, true, true, workspaceContext)
|
||||
|
||||
// we need an artificial delay to let the diagnostics catch up to the changes
|
||||
await setTimeoutPromise(3_500)
|
||||
@@ -230,8 +220,8 @@ export class WriteToFileToolHandler implements IFullyManagedTool {
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
modelId,
|
||||
providerId,
|
||||
false,
|
||||
false,
|
||||
workspaceContext,
|
||||
@@ -257,15 +247,7 @@ export class WriteToFileToolHandler implements IFullyManagedTool {
|
||||
await config.callbacks.say("user_feedback", text, images, files)
|
||||
}
|
||||
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
block.name,
|
||||
config.api.getModel().id,
|
||||
provider,
|
||||
false,
|
||||
true,
|
||||
workspaceContext,
|
||||
)
|
||||
telemetryService.captureToolUsage(config.ulid, block.name, modelId, providerId, false, true, workspaceContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user