mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-10-10 03:28:03 +00:00
Merge remote-tracking branch 'origin/main' into mrubens-patch-4
This commit is contained in:
commit
e38d9ecb22
20 changed files with 576 additions and 59 deletions
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Add a copy button to the recent tasks
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Improve the user experience for adding a new configuration profile
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Style and copy updates to advanced settings
|
||||
5
.changeset/spicy-pugs-guess.md
Normal file
5
.changeset/spicy-pugs-guess.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Support Volcano Ark platform through OpenAI compatible
|
||||
5
.changeset/stupid-masks-pay.md
Normal file
5
.changeset/stupid-masks-pay.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
Fix jumpiness while entering API config by updating on blur instead of input
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
---
|
||||
"roo-cline": patch
|
||||
---
|
||||
|
||||
v3.3.15
|
||||
|
|
@ -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
4
package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
}
|
||||
|
|
|
|||
138
src/api/transform/__tests__/simple-format.test.ts
Normal file
138
src/api/transform/__tests__/simple-format.test.ts
Normal 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]" },
|
||||
])
|
||||
})
|
||||
})
|
||||
})
|
||||
67
src/api/transform/simple-format.ts
Normal file
67
src/api/transform/simple-format.ts
Normal 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),
|
||||
}))
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
246
webview-ui/package-lock.json
generated
246
webview-ui/package-lock.json
generated
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ export * from "./command"
|
|||
export * from "./dialog"
|
||||
export * from "./dropdown-menu"
|
||||
export * from "./popover"
|
||||
export * from "./tooltip"
|
||||
|
|
|
|||
30
webview-ui/src/components/ui/tooltip.tsx
Normal file
30
webview-ui/src/components/ui/tooltip.tsx
Normal 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 }
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue