mirror of
https://github.com/cline/cline.git
synced 2026-09-16 21:01:52 +08:00
added cline provider + making sure welcome page closes
This commit is contained in:
@@ -13,6 +13,7 @@ import { ApiStream } from "./transform/stream"
|
||||
import { DeepSeekHandler } from "./providers/deepseek"
|
||||
import { MistralHandler } from "./providers/mistral"
|
||||
import { VsCodeLmHandler } from "./providers/vscode-lm"
|
||||
import { ClineHandler } from "./providers/cline"
|
||||
|
||||
export interface ApiHandler {
|
||||
createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream
|
||||
@@ -50,6 +51,8 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
|
||||
return new MistralHandler(options)
|
||||
case "vscode-lm":
|
||||
return new VsCodeLmHandler(options)
|
||||
case "cline":
|
||||
return new ClineHandler(options)
|
||||
default:
|
||||
return new AnthropicHandler(options)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { Anthropic } from "@anthropic-ai/sdk"
|
||||
import { Stream as AnthropicStream } from "@anthropic-ai/sdk/streaming"
|
||||
import { ApiHandler } from "../"
|
||||
import { ApiHandlerOptions, ModelInfo } from "../../shared/api"
|
||||
import { ApiStream } from "../transform/stream"
|
||||
|
||||
export class ClineHandler implements ApiHandler {
|
||||
private options: ApiHandlerOptions
|
||||
private client: Anthropic
|
||||
|
||||
constructor(options: ApiHandlerOptions) {
|
||||
this.options = options
|
||||
this.client = new Anthropic({
|
||||
apiKey: this.options.clineApiKey || "",
|
||||
baseURL: "https://api.cline.bot/v1",
|
||||
defaultHeaders: {
|
||||
"X-Firebase-Token": this.options.authToken || "",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
|
||||
const model = this.getModel()
|
||||
const stream = await this.client.messages.create({
|
||||
model: model.id,
|
||||
max_tokens: model.info.maxTokens || 8192,
|
||||
temperature: 0,
|
||||
system: [{ text: systemPrompt, type: "text" }],
|
||||
messages,
|
||||
stream: true,
|
||||
})
|
||||
|
||||
for await (const chunk of stream) {
|
||||
switch (chunk.type) {
|
||||
case "message_start":
|
||||
const usage = chunk.message.usage as any
|
||||
const result: any = {
|
||||
type: "usage",
|
||||
inputTokens: usage.input_tokens || 0,
|
||||
outputTokens: usage.output_tokens || 0,
|
||||
}
|
||||
if (usage.cache_creation_input_tokens) {
|
||||
result.cacheWriteTokens = usage.cache_creation_input_tokens
|
||||
}
|
||||
if (usage.cache_read_input_tokens) {
|
||||
result.cacheReadTokens = usage.cache_read_input_tokens
|
||||
}
|
||||
yield result
|
||||
break
|
||||
case "message_delta":
|
||||
yield {
|
||||
type: "usage",
|
||||
inputTokens: 0,
|
||||
outputTokens: chunk.usage.output_tokens || 0,
|
||||
}
|
||||
break
|
||||
case "content_block_start":
|
||||
switch (chunk.content_block.type) {
|
||||
case "text":
|
||||
if (chunk.index > 0) {
|
||||
yield {
|
||||
type: "text",
|
||||
text: "\n",
|
||||
}
|
||||
}
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.content_block.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
case "content_block_delta":
|
||||
switch (chunk.delta.type) {
|
||||
case "text_delta":
|
||||
yield {
|
||||
type: "text",
|
||||
text: chunk.delta.text,
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getModel() {
|
||||
return {
|
||||
id: "claude-3-5-sonnet",
|
||||
info: {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 200_000,
|
||||
supportsImages: true,
|
||||
supportsComputerUse: true,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 3.0,
|
||||
outputPrice: 15.0,
|
||||
cacheWritesPrice: 3.75,
|
||||
cacheReadsPrice: 0.3,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,6 +139,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
async handleSignOut() {
|
||||
try {
|
||||
await this.authManager.signOut()
|
||||
await this.storeSecret("authToken", undefined)
|
||||
await this.storeSecret("clineApiKey", undefined)
|
||||
await this.updateGlobalState("apiProvider", "openrouter")
|
||||
await this.postStateToWebview()
|
||||
vscode.window.showInformationMessage("Successfully logged out of Cline")
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage("Logout failed")
|
||||
@@ -849,6 +853,19 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
const clineProvider: ApiProvider = "cline"
|
||||
await this.updateGlobalState("apiProvider", clineProvider)
|
||||
|
||||
// Update API configuration with the new provider and auth token
|
||||
const { apiConfiguration } = await this.getState()
|
||||
const updatedConfig = {
|
||||
...apiConfiguration,
|
||||
apiProvider: clineProvider,
|
||||
clineApiKey: apiKey,
|
||||
authToken: token,
|
||||
}
|
||||
|
||||
if (this.cline) {
|
||||
this.cline.api = buildApiHandler(updatedConfig)
|
||||
}
|
||||
|
||||
await this.postStateToWebview()
|
||||
vscode.window.showInformationMessage("Successfully logged in to Cline")
|
||||
} catch (error) {
|
||||
@@ -1236,6 +1253,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
apiModelId,
|
||||
apiKey,
|
||||
openRouterApiKey,
|
||||
clineApiKey,
|
||||
awsAccessKey,
|
||||
awsSecretKey,
|
||||
awsSessionToken,
|
||||
@@ -1267,11 +1285,13 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
vsCodeLmModelSelector,
|
||||
localeLanguage,
|
||||
userInfo,
|
||||
authToken,
|
||||
] = await Promise.all([
|
||||
this.getGlobalState("apiProvider") as Promise<ApiProvider | undefined>,
|
||||
this.getGlobalState("apiModelId") as Promise<string | undefined>,
|
||||
this.getSecret("apiKey") as Promise<string | undefined>,
|
||||
this.getSecret("openRouterApiKey") as Promise<string | undefined>,
|
||||
this.getSecret("clineApiKey") as Promise<string | undefined>,
|
||||
this.getSecret("awsAccessKey") as Promise<string | undefined>,
|
||||
this.getSecret("awsSecretKey") as Promise<string | undefined>,
|
||||
this.getSecret("awsSessionToken") as Promise<string | undefined>,
|
||||
@@ -1303,6 +1323,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
this.getGlobalState("vsCodeLmModelSelector") as Promise<vscode.LanguageModelChatSelector | undefined>,
|
||||
this.getGlobalState("localeLanguage") as Promise<string | undefined>,
|
||||
this.getGlobalState("userInfo") as Promise<UserInfo | undefined>,
|
||||
this.getSecret("authToken") as Promise<string | undefined>,
|
||||
])
|
||||
|
||||
let apiProvider: ApiProvider
|
||||
@@ -1325,6 +1346,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
apiModelId,
|
||||
apiKey,
|
||||
openRouterApiKey,
|
||||
clineApiKey,
|
||||
awsAccessKey,
|
||||
awsSecretKey,
|
||||
awsSessionToken,
|
||||
@@ -1348,6 +1370,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
openRouterModelId,
|
||||
openRouterModelInfo,
|
||||
vsCodeLmModelSelector,
|
||||
authToken,
|
||||
},
|
||||
lastShownAnnouncementId,
|
||||
customInstructions,
|
||||
@@ -1434,6 +1457,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
||||
"deepSeekApiKey",
|
||||
"mistralApiKey",
|
||||
"authToken",
|
||||
"clineApiKey",
|
||||
]
|
||||
for (const key of secretKeys) {
|
||||
await this.storeSecret(key, undefined)
|
||||
|
||||
@@ -17,6 +17,7 @@ export interface ApiHandlerOptions {
|
||||
apiModelId?: string
|
||||
apiKey?: string // anthropic
|
||||
clineApiKey?: string
|
||||
authToken?: string // firebase auth token for cline provider
|
||||
anthropicBaseUrl?: string
|
||||
openRouterApiKey?: string
|
||||
openRouterModelId?: string
|
||||
|
||||
@@ -43,6 +43,11 @@ export function validateApiConfiguration(apiConfiguration?: ApiConfiguration): s
|
||||
return "You must provide a valid API key or choose a different provider."
|
||||
}
|
||||
break
|
||||
case "cline":
|
||||
if (!apiConfiguration.clineApiKey) {
|
||||
return "You must provide a valid API key or choose a different provider."
|
||||
}
|
||||
break
|
||||
case "openai":
|
||||
if (!apiConfiguration.openAiBaseUrl || !apiConfiguration.openAiApiKey || !apiConfiguration.openAiModelId) {
|
||||
return "You must provide a valid base URL, API key, and model ID."
|
||||
|
||||
Reference in New Issue
Block a user