Merge remote-tracking branch 'origin/main' into mrubens-patch-4

This commit is contained in:
Roo Code 2025-02-09 00:53:18 -05:00
commit e38d9ecb22
20 changed files with 576 additions and 59 deletions

View file

@ -1,5 +0,0 @@
---
"roo-cline": patch
---
Add a copy button to the recent tasks

View file

@ -1,5 +0,0 @@
---
"roo-cline": patch
---
Improve the user experience for adding a new configuration profile

View file

@ -1,5 +0,0 @@
---
"roo-cline": patch
---
Style and copy updates to advanced settings

View file

@ -0,0 +1,5 @@
---
"roo-cline": patch
---
Support Volcano Ark platform through OpenAI compatible

View file

@ -0,0 +1,5 @@
---
"roo-cline": patch
---
Fix jumpiness while entering API config by updating on blur instead of input

View file

@ -1,5 +0,0 @@
---
"roo-cline": patch
---
v3.3.15

View file

@ -1,5 +1,13 @@
# Roo Code Changelog
## [3.3.15]
- Improvements to MCP initialization and server restarts (thanks @MuriloFP and @hannesrudolph!)
- Add a copy button to the recent tasks (thanks @hannesrudolph!)
- Improve the user experience for adding a new API profile
- Another significant fix to API profile switching on the settings screen
- Opt-in experimental version of checkpoints in the advanced settings
## [3.3.14]
- Should have skipped floor 13 like an elevator. This fixes the broken 3.3.13 release by reverting some changes to the deployment scripts.

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "roo-cline",
"version": "3.3.14",
"version": "3.3.15",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "roo-cline",
"version": "3.3.14",
"version": "3.3.15",
"dependencies": {
"@anthropic-ai/bedrock-sdk": "^0.10.2",
"@anthropic-ai/sdk": "^0.26.0",

View file

@ -3,7 +3,7 @@
"displayName": "Roo Code (prev. Roo Cline)",
"description": "A VS Code plugin that enhances coding with AI-powered automation, multi-model support, and experimental features.",
"publisher": "RooVeterinaryInc",
"version": "3.3.14",
"version": "3.3.15",
"icon": "assets/icons/rocket.png",
"galleryBanner": {
"color": "#617A91",

View file

@ -10,6 +10,7 @@ import {
import { ApiHandler, SingleCompletionHandler } from "../index"
import { convertToOpenAiMessages } from "../transform/openai-format"
import { convertToR1Format } from "../transform/r1-format"
import { convertToSimpleMessages } from "../transform/simple-format"
import { ApiStream } from "../transform/stream"
export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
@ -46,21 +47,31 @@ export class OpenAiHandler implements ApiHandler, SingleCompletionHandler {
async *createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[]): ApiStream {
const modelInfo = this.getModel().info
const modelUrl = this.options.openAiBaseUrl ?? ""
const modelId = this.options.openAiModelId ?? ""
const deepseekReasoner = modelId.includes("deepseek-reasoner")
const ark = modelUrl.includes(".volces.com")
if (this.options.openAiStreamingEnabled ?? true) {
const systemMessage: OpenAI.Chat.ChatCompletionSystemMessageParam = {
role: "system",
content: systemPrompt,
}
let convertedMessages
if (deepseekReasoner) {
convertedMessages = convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
} else if (ark) {
convertedMessages = [systemMessage, ...convertToSimpleMessages(messages)]
} else {
convertedMessages = [systemMessage, ...convertToOpenAiMessages(messages)]
}
const requestOptions: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = {
model: modelId,
temperature: 0,
messages: deepseekReasoner
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
: [systemMessage, ...convertToOpenAiMessages(messages)],
messages: convertedMessages,
stream: true as const,
stream_options: { include_usage: true },
}

View file

@ -0,0 +1,138 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { convertToSimpleContent, convertToSimpleMessages } from "../simple-format"
describe("simple-format", () => {
describe("convertToSimpleContent", () => {
it("returns string content as-is", () => {
const content = "Hello world"
expect(convertToSimpleContent(content)).toBe("Hello world")
})
it("extracts text from text blocks", () => {
const content = [
{ type: "text", text: "Hello" },
{ type: "text", text: "world" },
] as Anthropic.Messages.TextBlockParam[]
expect(convertToSimpleContent(content)).toBe("Hello\nworld")
})
it("converts image blocks to descriptive text", () => {
const content = [
{ type: "text", text: "Here's an image:" },
{
type: "image",
source: {
type: "base64",
media_type: "image/png",
data: "base64data",
},
},
] as Array<Anthropic.Messages.TextBlockParam | Anthropic.Messages.ImageBlockParam>
expect(convertToSimpleContent(content)).toBe("Here's an image:\n[Image: image/png]")
})
it("converts tool use blocks to descriptive text", () => {
const content = [
{ type: "text", text: "Using a tool:" },
{
type: "tool_use",
id: "tool-1",
name: "read_file",
input: { path: "test.txt" },
},
] as Array<Anthropic.Messages.TextBlockParam | Anthropic.Messages.ToolUseBlockParam>
expect(convertToSimpleContent(content)).toBe("Using a tool:\n[Tool Use: read_file]")
})
it("handles string tool result content", () => {
const content = [
{ type: "text", text: "Tool result:" },
{
type: "tool_result",
tool_use_id: "tool-1",
content: "Result text",
},
] as Array<Anthropic.Messages.TextBlockParam | Anthropic.Messages.ToolResultBlockParam>
expect(convertToSimpleContent(content)).toBe("Tool result:\nResult text")
})
it("handles array tool result content with text and images", () => {
const content = [
{
type: "tool_result",
tool_use_id: "tool-1",
content: [
{ type: "text", text: "Result 1" },
{
type: "image",
source: {
type: "base64",
media_type: "image/jpeg",
data: "base64data",
},
},
{ type: "text", text: "Result 2" },
],
},
] as Anthropic.Messages.ToolResultBlockParam[]
expect(convertToSimpleContent(content)).toBe("Result 1\n[Image: image/jpeg]\nResult 2")
})
it("filters out empty strings", () => {
const content = [
{ type: "text", text: "Hello" },
{ type: "text", text: "" },
{ type: "text", text: "world" },
] as Anthropic.Messages.TextBlockParam[]
expect(convertToSimpleContent(content)).toBe("Hello\nworld")
})
})
describe("convertToSimpleMessages", () => {
it("converts messages with string content", () => {
const messages = [
{ role: "user", content: "Hello" },
{ role: "assistant", content: "Hi there" },
] as Anthropic.Messages.MessageParam[]
expect(convertToSimpleMessages(messages)).toEqual([
{ role: "user", content: "Hello" },
{ role: "assistant", content: "Hi there" },
])
})
it("converts messages with complex content", () => {
const messages = [
{
role: "user",
content: [
{ type: "text", text: "Look at this:" },
{
type: "image",
source: {
type: "base64",
media_type: "image/png",
data: "base64data",
},
},
],
},
{
role: "assistant",
content: [
{ type: "text", text: "I see the image" },
{
type: "tool_use",
id: "tool-1",
name: "analyze_image",
input: { data: "base64data" },
},
],
},
] as Anthropic.Messages.MessageParam[]
expect(convertToSimpleMessages(messages)).toEqual([
{ role: "user", content: "Look at this:\n[Image: image/png]" },
{ role: "assistant", content: "I see the image\n[Tool Use: analyze_image]" },
])
})
})
})

View file

@ -0,0 +1,67 @@
import { Anthropic } from "@anthropic-ai/sdk"
/**
* Convert complex content blocks to simple string content
*/
export function convertToSimpleContent(
content:
| string
| Array<
| Anthropic.Messages.TextBlockParam
| Anthropic.Messages.ImageBlockParam
| Anthropic.Messages.ToolUseBlockParam
| Anthropic.Messages.ToolResultBlockParam
>,
): string {
if (typeof content === "string") {
return content
}
// Extract text from content blocks
return content
.map((block) => {
if (block.type === "text") {
return block.text
}
if (block.type === "image") {
return `[Image: ${block.source.media_type}]`
}
if (block.type === "tool_use") {
return `[Tool Use: ${block.name}]`
}
if (block.type === "tool_result") {
if (typeof block.content === "string") {
return block.content
}
if (Array.isArray(block.content)) {
return block.content
.map((part) => {
if (part.type === "text") {
return part.text
}
if (part.type === "image") {
return `[Image: ${part.source.media_type}]`
}
return ""
})
.join("\n")
}
return ""
}
return ""
})
.filter(Boolean)
.join("\n")
}
/**
* Convert Anthropic messages to simple format with string content
*/
export function convertToSimpleMessages(
messages: Anthropic.Messages.MessageParam[],
): Array<{ role: "user" | "assistant"; content: string }> {
return messages.map((message) => ({
role: message.role,
content: convertToSimpleContent(message.content),
}))
}

View file

@ -5,10 +5,6 @@ import path from "path"
import debug from "debug"
import simpleGit, { SimpleGit, CleanOptions } from "simple-git"
if (process.env.NODE_ENV !== "test") {
debug.enable("simple-git")
}
export type CheckpointServiceOptions = {
taskId: string
git?: SimpleGit

View file

@ -13,6 +13,7 @@
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/vite": "^4.0.0",
"@vscode/webview-ui-toolkit": "^1.4.0",
"class-variance-authority": "^0.7.1",
@ -4185,6 +4186,187 @@
}
}
},
"node_modules/@radix-ui/react-tooltip": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.1.8.tgz",
"integrity": "sha512-YAA2cu48EkJZdAMHC0dqo9kialOcRStbtiY4nJPaht7Ptrhcvpo+eDChaM6BIs8kL6a8Z5l5poiqLnXcNduOkA==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-dismissable-layer": "1.1.5",
"@radix-ui/react-id": "1.1.0",
"@radix-ui/react-popper": "1.2.2",
"@radix-ui/react-portal": "1.1.4",
"@radix-ui/react-presence": "1.1.2",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-slot": "1.1.2",
"@radix-ui/react-use-controllable-state": "1.1.0",
"@radix-ui/react-visually-hidden": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
"integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-primitive": "2.0.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
"integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.1",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-escape-keydown": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
"integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
"license": "MIT",
"dependencies": {
"@floating-ui/react-dom": "^2.0.0",
"@radix-ui/react-arrow": "1.1.2",
"@radix-ui/react-compose-refs": "1.1.1",
"@radix-ui/react-context": "1.1.1",
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-use-callback-ref": "1.1.0",
"@radix-ui/react-use-layout-effect": "1.1.0",
"@radix-ui/react-use-rect": "1.1.0",
"@radix-ui/react-use-size": "1.1.0",
"@radix-ui/rect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
"integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-primitive": "2.0.2",
"@radix-ui/react-use-layout-effect": "1.1.0"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
"integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
@ -4287,6 +4469,70 @@
}
}
},
"node_modules/@radix-ui/react-visually-hidden": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz",
"integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-primitive": "2.0.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-slot": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.2.tgz",
"integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/rect": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",

View file

@ -20,6 +20,7 @@
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-popover": "^1.1.6",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-tooltip": "^1.1.8",
"@tailwindcss/vite": "^4.0.0",
"@vscode/webview-ui-toolkit": "^1.4.0",
"class-variance-authority": "^0.7.1",

View file

@ -3,7 +3,16 @@ import { CheckIcon, Cross2Icon } from "@radix-ui/react-icons"
import { vscode } from "../../../utils/vscode"
import { Button, Popover, PopoverContent, PopoverTrigger } from "@/components/ui"
import {
Button,
Popover,
PopoverContent,
PopoverTrigger,
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui"
type CheckpointMenuProps = {
ts: number
@ -43,9 +52,16 @@ export const CheckpointMenu = ({ ts, commitHash, currentCheckpointHash }: Checkp
return (
<div className="flex flex-row gap-1">
<Button variant="ghost" size="icon" onClick={onCheckpointDiff}>
<span className="codicon codicon-diff-single" />
</Button>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon" onClick={onCheckpointDiff}>
<span className="codicon codicon-diff-single" />
</Button>
</TooltipTrigger>
<TooltipContent align="end">View Diff</TooltipContent>
</Tooltip>
</TooltipProvider>
<Popover
open={isOpen}
onOpenChange={(open) => {
@ -53,9 +69,16 @@ export const CheckpointMenu = ({ ts, commitHash, currentCheckpointHash }: Checkp
setIsConfirming(false)
}}>
<PopoverTrigger asChild>
<Button variant="ghost" size="icon">
<span className="codicon codicon-history" />
</Button>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon">
<span className="codicon codicon-history" />
</Button>
</TooltipTrigger>
<TooltipContent align="end">Restore Checkpoint</TooltipContent>
</Tooltip>
</TooltipProvider>
</PopoverTrigger>
<PopoverContent align="end" container={portalContainer}>
<div className="flex flex-col gap-2">

View file

@ -41,7 +41,6 @@ import { UnboundModelPicker } from "./UnboundModelPicker"
import { ModelInfoView } from "./ModelInfoView"
import { DROPDOWN_Z_INDEX } from "./styles"
interface ApiOptionsProps {
apiErrorMessage?: string
modelIdErrorMessage?: string
@ -164,7 +163,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.apiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("apiKey")}
onBlur={handleInputChange("apiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Anthropic API Key</span>
</VSCodeTextField>
@ -189,7 +188,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.anthropicBaseUrl || ""}
style={{ width: "100%", marginTop: 3 }}
type="url"
onInput={handleInputChange("anthropicBaseUrl")}
onBlur={handleInputChange("anthropicBaseUrl")}
placeholder="Default: https://api.anthropic.com"
/>
)}
@ -218,7 +217,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.glamaApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("glamaApiKey")}
onBlur={handleInputChange("glamaApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Glama API Key</span>
</VSCodeTextField>
@ -247,7 +246,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.openAiNativeApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("openAiNativeApiKey")}
onBlur={handleInputChange("openAiNativeApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>OpenAI API Key</span>
</VSCodeTextField>
@ -275,7 +274,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.mistralApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("mistralApiKey")}
onBlur={handleInputChange("mistralApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Mistral API Key</span>
</VSCodeTextField>
@ -306,7 +305,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.openRouterApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("openRouterApiKey")}
onBlur={handleInputChange("openRouterApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>OpenRouter API Key</span>
</VSCodeTextField>
@ -340,7 +339,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.openRouterBaseUrl || ""}
style={{ width: "100%", marginTop: 3 }}
type="url"
onInput={handleInputChange("openRouterBaseUrl")}
onBlur={handleInputChange("openRouterBaseUrl")}
placeholder="Default: https://openrouter.ai/api/v1"
/>
)}
@ -391,7 +390,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
<VSCodeTextField
value={apiConfiguration?.awsProfile || ""}
style={{ width: "100%" }}
onInput={handleInputChange("awsProfile")}
onBlur={handleInputChange("awsProfile")}
placeholder="Enter profile name">
<span style={{ fontWeight: 500 }}>AWS Profile Name</span>
</VSCodeTextField>
@ -402,7 +401,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.awsAccessKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("awsAccessKey")}
onBlur={handleInputChange("awsAccessKey")}
placeholder="Enter Access Key...">
<span style={{ fontWeight: 500 }}>AWS Access Key</span>
</VSCodeTextField>
@ -410,7 +409,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.awsSecretKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("awsSecretKey")}
onBlur={handleInputChange("awsSecretKey")}
placeholder="Enter Secret Key...">
<span style={{ fontWeight: 500 }}>AWS Secret Key</span>
</VSCodeTextField>
@ -418,7 +417,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.awsSessionToken || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("awsSessionToken")}
onBlur={handleInputChange("awsSessionToken")}
placeholder="Enter Session Token...">
<span style={{ fontWeight: 500 }}>AWS Session Token</span>
</VSCodeTextField>
@ -486,7 +485,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
<VSCodeTextField
value={apiConfiguration?.vertexProjectId || ""}
style={{ width: "100%" }}
onInput={handleInputChange("vertexProjectId")}
onBlur={handleInputChange("vertexProjectId")}
placeholder="Enter Project ID...">
<span style={{ fontWeight: 500 }}>Google Cloud Project ID</span>
</VSCodeTextField>
@ -544,7 +543,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.geminiApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("geminiApiKey")}
onBlur={handleInputChange("geminiApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>Gemini API Key</span>
</VSCodeTextField>
@ -572,7 +571,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.openAiBaseUrl || ""}
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("openAiBaseUrl")}
onBlur={handleInputChange("openAiBaseUrl")}
placeholder={"Enter base URL..."}>
<span style={{ fontWeight: 500 }}>Base URL</span>
</VSCodeTextField>
@ -580,7 +579,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.openAiApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("openAiApiKey")}
onBlur={handleInputChange("openAiApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>API Key</span>
</VSCodeTextField>
@ -623,7 +622,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
<VSCodeTextField
value={apiConfiguration?.azureApiVersion || ""}
style={{ width: "100%", marginTop: 3 }}
onInput={handleInputChange("azureApiVersion")}
onBlur={handleInputChange("azureApiVersion")}
placeholder={`Default: ${azureOpenAiDefaultApiVersion}`}
/>
)}
@ -1073,14 +1072,14 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.lmStudioBaseUrl || ""}
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("lmStudioBaseUrl")}
onBlur={handleInputChange("lmStudioBaseUrl")}
placeholder={"Default: http://localhost:1234"}>
<span style={{ fontWeight: 500 }}>Base URL (optional)</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.lmStudioModelId || ""}
style={{ width: "100%" }}
onInput={handleInputChange("lmStudioModelId")}
onBlur={handleInputChange("lmStudioModelId")}
placeholder={"e.g. meta-llama-3.1-8b-instruct"}>
<span style={{ fontWeight: 500 }}>Model ID</span>
</VSCodeTextField>
@ -1142,7 +1141,7 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.deepSeekApiKey || ""}
style={{ width: "100%" }}
type="password"
onInput={handleInputChange("deepSeekApiKey")}
onBlur={handleInputChange("deepSeekApiKey")}
placeholder="Enter API Key...">
<span style={{ fontWeight: 500 }}>DeepSeek API Key</span>
</VSCodeTextField>
@ -1232,14 +1231,14 @@ const ApiOptions = ({ apiErrorMessage, modelIdErrorMessage }: ApiOptionsProps) =
value={apiConfiguration?.ollamaBaseUrl || ""}
style={{ width: "100%" }}
type="url"
onInput={handleInputChange("ollamaBaseUrl")}
onBlur={handleInputChange("ollamaBaseUrl")}
placeholder={"Default: http://localhost:11434"}>
<span style={{ fontWeight: 500 }}>Base URL (optional)</span>
</VSCodeTextField>
<VSCodeTextField
value={apiConfiguration?.ollamaModelId || ""}
style={{ width: "100%" }}
onInput={handleInputChange("ollamaModelId")}
onBlur={handleInputChange("ollamaModelId")}
placeholder={"e.g. llama3.1"}>
<span style={{ fontWeight: 500 }}>Model ID</span>
</VSCodeTextField>

View file

@ -3,3 +3,4 @@ export * from "./command"
export * from "./dialog"
export * from "./dropdown-menu"
export * from "./popover"
export * from "./tooltip"

View file

@ -0,0 +1,30 @@
import * as React from "react"
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import { cn } from "@/lib/utils"
const TooltipProvider = TooltipPrimitive.Provider
const Tooltip = TooltipPrimitive.Root
const TooltipTrigger = TooltipPrimitive.Trigger
const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-xs bg-vscode-notifications-background border border-vscode-notifications-border px-3 py-1.5 text-xs text-vscode-notifications-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className,
)}
{...props}
/>
</TooltipPrimitive.Portal>
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

View file

@ -76,6 +76,13 @@
--color-vscode-input-background: var(--vscode-input-background);
--color-vscode-input-border: var(--vscode-input-border);
--color-vscode-badge-foreground: var(--vscode-badge-foreground);
--color-vscode-badge-background: var(--vscode-badge-background);
--color-vscode-notifications-foreground: var(--vscode-notifications-foreground);
--color-vscode-notifications-background: var(--vscode-notifications-background);
--color-vscode-notifications-border: var(--vscode-notifications-border);
}
@layer base {