From 5adf96dc82b90474ab8455bcbba2dac072747863 Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Thu, 31 Oct 2024 20:26:04 -0400 Subject: [PATCH 01/18] Fixes --- src/core/Cline.ts | 22 ++++++++++--------- .../src/components/settings/SettingsView.tsx | 4 ++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/core/Cline.ts b/src/core/Cline.ts index 6e0a0db..c63a704 100644 --- a/src/core/Cline.ts +++ b/src/core/Cline.ts @@ -1032,16 +1032,18 @@ export class Cline { newContent = newContent.split("\n").slice(0, -1).join("\n").trim() } - // it seems not just llama models are doing this, but also gemini and potentially others - if ( - newContent.includes(">") || - newContent.includes("<") || - newContent.includes(""") - ) { - newContent = newContent - .replace(/>/g, ">") - .replace(/</g, "<") - .replace(/"/g, '"') + if (!this.api.getModel().id.includes("claude")) { + // it seems not just llama models are doing this, but also gemini and potentially others + if ( + newContent.includes(">") || + newContent.includes("<") || + newContent.includes(""") + ) { + newContent = newContent + .replace(/>/g, ">") + .replace(/</g, "<") + .replace(/"/g, '"') + } } const sharedMessageProps: ClineSayTool = { diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index ca14435..ad7ff80 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -125,8 +125,8 @@ const SettingsView = ({ onDone }: SettingsViewProps) => { marginTop: "5px", color: "var(--vscode-descriptionForeground)", }}> - When enabled, Cline will automatically read files, view directories, and inspect sites without - requiring you to click the Approve button. + When enabled, Cline will automatically view directory contents and read files without requiring + you to click the Approve button.
From efacc1a83af146f9ee2b0c27bd7082d43f3a5948 Mon Sep 17 00:00:00 2001 From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com> Date: Thu, 31 Oct 2024 23:11:43 -0400 Subject: [PATCH 02/18] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 28a1e7a..d12693a 100644 --- a/README.md +++ b/README.md @@ -76,13 +76,13 @@ All changes made by Cline are recorded in your file's Timeline, providing an eas
Date: Fri, 8 Nov 2024 04:57:03 +1100
Subject: [PATCH 12/18] Fix: Add missing sonnet model to bedrock (#633)
---
src/shared/api.ts | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/shared/api.ts b/src/shared/api.ts
index 721e669..a466972 100644
--- a/src/shared/api.ts
+++ b/src/shared/api.ts
@@ -136,6 +136,14 @@ export const bedrockModels = {
inputPrice: 15.0,
outputPrice: 75.0,
},
+ "anthropic.claude-3-sonnet-20240229-v1:0": {
+ maxTokens: 4096,
+ contextWindow: 200_000,
+ supportsImages: true,
+ supportsPromptCache: false,
+ inputPrice: 3.0,
+ outputPrice: 15.0,
+ },
"anthropic.claude-3-haiku-20240307-v1:0": {
maxTokens: 4096,
contextWindow: 200_000,
From ad29ff2a03ddfd94249f4901826a7f1b02692f57 Mon Sep 17 00:00:00 2001
From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Date: Thu, 7 Nov 2024 13:51:13 -0500
Subject: [PATCH 13/18] Add AWS cross-region inference toggle
---
src/api/providers/bedrock.ts | 22 ++++++++++++++++++-
src/core/webview/ClineProvider.ts | 6 +++++
src/shared/api.ts | 1 +
.../src/components/settings/ApiOptions.tsx | 8 +++++++
4 files changed, 36 insertions(+), 1 deletion(-)
diff --git a/src/api/providers/bedrock.ts b/src/api/providers/bedrock.ts
index ad6e8df..58f75ad 100644
--- a/src/api/providers/bedrock.ts
+++ b/src/api/providers/bedrock.ts
@@ -25,8 +25,28 @@ export class AwsBedrockHandler implements ApiHandler {
}
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
+ // cross region inference requires prefixing the model id with the region
+ let modelId: string
+ if (this.options.awsUseCrossRegionInference) {
+ let regionPrefix = (this.options.awsRegion || "").slice(0, 3)
+ switch (regionPrefix) {
+ case "us-":
+ modelId = `us.${this.getModel().id}`
+ break
+ case "eu-":
+ modelId = `eu.${this.getModel().id}`
+ break
+ default:
+ // cross region inference is not supported in this region, falling back to default model
+ modelId = this.getModel().id
+ break
+ }
+ } else {
+ modelId = this.getModel().id
+ }
+
const stream = await this.client.messages.create({
- model: this.getModel().id,
+ model: modelId,
max_tokens: this.getModel().info.maxTokens || 8192,
temperature: 0,
system: systemPrompt,
diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts
index 6f19138..6d24ce8 100644
--- a/src/core/webview/ClineProvider.ts
+++ b/src/core/webview/ClineProvider.ts
@@ -40,6 +40,7 @@ type GlobalStateKey =
| "apiProvider"
| "apiModelId"
| "awsRegion"
+ | "awsUseCrossRegionInference"
| "vertexProjectId"
| "vertexRegion"
| "lastShownAnnouncementId"
@@ -350,6 +351,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
awsSecretKey,
awsSessionToken,
awsRegion,
+ awsUseCrossRegionInference,
vertexProjectId,
vertexRegion,
openAiBaseUrl,
@@ -372,6 +374,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.storeSecret("awsSecretKey", awsSecretKey)
await this.storeSecret("awsSessionToken", awsSessionToken)
await this.updateGlobalState("awsRegion", awsRegion)
+ await this.updateGlobalState("awsUseCrossRegionInference", awsUseCrossRegionInference)
await this.updateGlobalState("vertexProjectId", vertexProjectId)
await this.updateGlobalState("vertexRegion", vertexRegion)
await this.updateGlobalState("openAiBaseUrl", openAiBaseUrl)
@@ -824,6 +827,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
awsSecretKey,
awsSessionToken,
awsRegion,
+ awsUseCrossRegionInference,
vertexProjectId,
vertexRegion,
openAiBaseUrl,
@@ -850,6 +854,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
this.getSecret("awsSecretKey") as Promise
Date: Thu, 7 Nov 2024 13:54:38 -0500
Subject: [PATCH 14/18] Prepare for release
---
CHANGELOG.md | 4 ++++
package.json | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b7ced78..83a83f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Change Log
+## [2.1.4]
+
+- AWS Bedrock fixes (add missing regions, support for cross-region inference, and older Sonnet model for regions where new model is not available)
+
## [2.1.3]
- Add support for Claude 3.5 Haiku, 66% cheaper than Sonnet with similar intelligence
diff --git a/package.json b/package.json
index 4ce8282..f00b52e 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "claude-dev",
"displayName": "Cline (prev. Claude Dev)",
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
- "version": "2.1.3",
+ "version": "2.1.4",
"icon": "assets/icons/icon.png",
"galleryBanner": {
"color": "#617A91",
From ff725d35ff081f8c0a102d9dcf4618d892d8a440 Mon Sep 17 00:00:00 2001
From: Mark Percival
+ LM Studio allows you to run models locally on your computer. For instructions on how to get
+ started, see their
+ Local Development Instructions
-1. Clone the repository:
+1. Clone the repository *(Requires [git-lfs](https://git-lfs.com/))*:
```bash
git clone https://github.com/cline/cline.git
```
From bac0b1a0cbf44f936b0afe794f5ee035101cb06e Mon Sep 17 00:00:00 2001
From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Date: Tue, 12 Nov 2024 18:35:51 -0500
Subject: [PATCH 16/18] Add prompt caching for new model ids on openrouter
---
CHANGELOG.md | 4 ++++
package.json | 2 +-
src/api/providers/openrouter.ts | 16 ++++++++++++++++
3 files changed, 21 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 83a83f1..2e0b3d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
# Change Log
+## [2.1.5]
+
+- Add support for prompt caching for new Claude model IDs on OpenRouter (e.g. `anthropic/claude-3.5-sonnet-20240620`)
+
## [2.1.4]
- AWS Bedrock fixes (add missing regions, support for cross-region inference, and older Sonnet model for regions where new model is not available)
diff --git a/package.json b/package.json
index f00b52e..ed79817 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "claude-dev",
"displayName": "Cline (prev. Claude Dev)",
"description": "Autonomous coding agent right in your IDE, capable of creating/editing files, running commands, using the browser, and more with your permission every step of the way.",
- "version": "2.1.4",
+ "version": "2.1.5",
"icon": "assets/icons/icon.png",
"galleryBanner": {
"color": "#617A91",
diff --git a/src/api/providers/openrouter.ts b/src/api/providers/openrouter.ts
index 2227c3e..93bbaba 100644
--- a/src/api/providers/openrouter.ts
+++ b/src/api/providers/openrouter.ts
@@ -31,9 +31,19 @@ export class OpenRouterHandler implements ApiHandler {
]
// prompt caching: https://openrouter.ai/docs/prompt-caching
+ // this is specifically for claude models (some models may 'support prompt caching' automatically without this)
switch (this.getModel().id) {
+ case "anthropic/claude-3.5-sonnet":
case "anthropic/claude-3.5-sonnet:beta":
+ case "anthropic/claude-3.5-sonnet-20240620":
+ case "anthropic/claude-3.5-sonnet-20240620:beta":
+ case "anthropic/claude-3-5-haiku":
+ case "anthropic/claude-3-5-haiku:beta":
+ case "anthropic/claude-3-5-haiku-20241022":
+ case "anthropic/claude-3-5-haiku-20241022:beta":
+ case "anthropic/claude-3-haiku":
case "anthropic/claude-3-haiku:beta":
+ case "anthropic/claude-3-opus":
case "anthropic/claude-3-opus:beta":
openAiMessages[0] = {
role: "system",
@@ -76,6 +86,12 @@ export class OpenRouterHandler implements ApiHandler {
switch (this.getModel().id) {
case "anthropic/claude-3.5-sonnet":
case "anthropic/claude-3.5-sonnet:beta":
+ case "anthropic/claude-3.5-sonnet-20240620":
+ case "anthropic/claude-3.5-sonnet-20240620:beta":
+ case "anthropic/claude-3-5-haiku":
+ case "anthropic/claude-3-5-haiku:beta":
+ case "anthropic/claude-3-5-haiku-20241022":
+ case "anthropic/claude-3-5-haiku-20241022:beta":
maxTokens = 8_192
break
}
From 39bc35eec1ba83355b5c96363a7bb833a1b1bb61 Mon Sep 17 00:00:00 2001
From: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Date: Tue, 12 Nov 2024 22:02:42 -0500
Subject: [PATCH 17/18] Add LM Studio provider
---
.github/ISSUE_TEMPLATE/bug_report.yml | 1 +
README.md | 4 +-
src/api/index.ts | 3 +
src/api/providers/lmstudio.ts | 56 +++++++++++
src/core/webview/ClineProvider.ts | 35 +++++++
src/shared/ExtensionMessage.ts | 2 +
src/shared/WebviewMessage.ts | 1 +
src/shared/api.ts | 3 +
webview-ui/src/components/chat/TaskHeader.tsx | 1 +
.../src/components/settings/ApiOptions.tsx | 96 +++++++++++++++++--
.../src/context/ExtensionStateContext.tsx | 1 +
webview-ui/src/utils/validate.ts | 5 +
12 files changed, 199 insertions(+), 9 deletions(-)
create mode 100644 src/api/providers/lmstudio.ts
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index bf95687..eb61061 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -15,6 +15,7 @@ body:
- AWS Bedrock
- OpenAI
- OpenAI Compatible
+ - LM Studio
- Ollama
validations:
required: true
diff --git a/README.md b/README.md
index 45aff0f..6fa1a76 100644
--- a/README.md
+++ b/README.md
@@ -44,7 +44,7 @@ Thanks to [Claude 3.5 Sonnet's agentic coding capabilities](https://www-cdn.ant
### Use any API and Model
-Cline supports API providers like OpenRouter, Anthropic, OpenAI, Google Gemini, AWS Bedrock, Azure, and GCP Vertex. You can also configure any OpenAI compatible API, or use a local model through Ollama. If you're using OpenRouter, the extension fetches their latest model list, allowing you to use the newest models as soon as they're available.
+Cline supports API providers like OpenRouter, Anthropic, OpenAI, Google Gemini, AWS Bedrock, Azure, and GCP Vertex. You can also configure any OpenAI compatible API, or use a local model through LM Studio/Ollama. If you're using OpenRouter, the extension fetches their latest model list, allowing you to use the newest models as soon as they're available.
The extension also keeps track of total tokens and API usage cost for the entire task loop and individual requests, keeping you informed of spend every step of the way.
@@ -104,7 +104,7 @@ To contribute to the project, start by exploring [open issues](https://github.co
Local Development Instructions
-1. Clone the repository *(Requires [git-lfs](https://git-lfs.com/))*:
+1. Clone the repository _(Requires [git-lfs](https://git-lfs.com/))_:
```bash
git clone https://github.com/cline/cline.git
```
diff --git a/src/api/index.ts b/src/api/index.ts
index 388b9ce..ec35c2a 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -6,6 +6,7 @@ import { OpenRouterHandler } from "./providers/openrouter"
import { VertexHandler } from "./providers/vertex"
import { OpenAiHandler } from "./providers/openai"
import { OllamaHandler } from "./providers/ollama"
+import { LmStudioHandler } from "./providers/lmstudio"
import { GeminiHandler } from "./providers/gemini"
import { OpenAiNativeHandler } from "./providers/openai-native"
import { ApiStream } from "./transform/stream"
@@ -30,6 +31,8 @@ export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
return new OpenAiHandler(options)
case "ollama":
return new OllamaHandler(options)
+ case "lmstudio":
+ return new LmStudioHandler(options)
case "gemini":
return new GeminiHandler(options)
case "openai-native":
diff --git a/src/api/providers/lmstudio.ts b/src/api/providers/lmstudio.ts
new file mode 100644
index 0000000..1c085f7
--- /dev/null
+++ b/src/api/providers/lmstudio.ts
@@ -0,0 +1,56 @@
+import { Anthropic } from "@anthropic-ai/sdk"
+import OpenAI from "openai"
+import { ApiHandler } from "../"
+import { ApiHandlerOptions, ModelInfo, openAiModelInfoSaneDefaults } from "../../shared/api"
+import { convertToOpenAiMessages } from "../transform/openai-format"
+import { ApiStream } from "../transform/stream"
+
+export class LmStudioHandler implements ApiHandler {
+ private options: ApiHandlerOptions
+ private client: OpenAI
+
+ constructor(options: ApiHandlerOptions) {
+ this.options = options
+ this.client = new OpenAI({
+ baseURL: (this.options.lmStudioBaseUrl || "http://localhost:1234") + "/v1",
+ apiKey: "noop",
+ })
+ }
+
+ async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
+ const openAiMessages: OpenAI.Chat.ChatCompletionMessageParam[] = [
+ { role: "system", content: systemPrompt },
+ ...convertToOpenAiMessages(messages),
+ ]
+
+ try {
+ const stream = await this.client.chat.completions.create({
+ model: this.getModel().id,
+ messages: openAiMessages,
+ temperature: 0,
+ stream: true,
+ })
+ for await (const chunk of stream) {
+ const delta = chunk.choices[0]?.delta
+ if (delta?.content) {
+ yield {
+ type: "text",
+ text: delta.content,
+ }
+ }
+ }
+ } catch (error) {
+ // LM Studio doesn't return an error code/body for now
+ throw new Error(
+ "Please check the LM Studio developer logs to debug what went wrong. You may need to load the model with a larger context length to work with Cline's prompts."
+ )
+ }
+ }
+
+ getModel(): { id: string; info: ModelInfo } {
+ return {
+ id: this.options.lmStudioModelId || "",
+ info: openAiModelInfoSaneDefaults,
+ }
+ }
+}
diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts
index 6d24ce8..2642d10 100644
--- a/src/core/webview/ClineProvider.ts
+++ b/src/core/webview/ClineProvider.ts
@@ -51,6 +51,8 @@ type GlobalStateKey =
| "openAiModelId"
| "ollamaModelId"
| "ollamaBaseUrl"
+ | "lmStudioModelId"
+ | "lmStudioBaseUrl"
| "anthropicBaseUrl"
| "azureApiVersion"
| "openRouterModelId"
@@ -359,6 +361,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
openAiModelId,
ollamaModelId,
ollamaBaseUrl,
+ lmStudioModelId,
+ lmStudioBaseUrl,
anthropicBaseUrl,
geminiApiKey,
openAiNativeApiKey,
@@ -382,6 +386,8 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.updateGlobalState("openAiModelId", openAiModelId)
await this.updateGlobalState("ollamaModelId", ollamaModelId)
await this.updateGlobalState("ollamaBaseUrl", ollamaBaseUrl)
+ await this.updateGlobalState("lmStudioModelId", lmStudioModelId)
+ await this.updateGlobalState("lmStudioBaseUrl", lmStudioBaseUrl)
await this.updateGlobalState("anthropicBaseUrl", anthropicBaseUrl)
await this.storeSecret("geminiApiKey", geminiApiKey)
await this.storeSecret("openAiNativeApiKey", openAiNativeApiKey)
@@ -442,6 +448,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
const ollamaModels = await this.getOllamaModels(message.text)
this.postMessageToWebview({ type: "ollamaModels", ollamaModels })
break
+ case "requestLmStudioModels":
+ const lmStudioModels = await this.getLmStudioModels(message.text)
+ this.postMessageToWebview({ type: "lmStudioModels", lmStudioModels })
+ break
case "refreshOpenRouterModels":
await this.refreshOpenRouterModels()
break
@@ -509,6 +519,25 @@ export class ClineProvider implements vscode.WebviewViewProvider {
}
}
+ // LM Studio
+
+ async getLmStudioModels(baseUrl?: string) {
+ try {
+ if (!baseUrl) {
+ baseUrl = "http://localhost:1234"
+ }
+ if (!URL.canParse(baseUrl)) {
+ return []
+ }
+ const response = await axios.get(`${baseUrl}/v1/models`)
+ const modelsArray = response.data?.data?.map((model: any) => model.id) || []
+ const models = [...new Set