Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
a79c3d0
Follow symlinks in rooignore checks (#7405)
mrubens Aug 26, 2025
572fa50
Sonic -> Grok Code Fast (#7426)
mrubens Aug 26, 2025
f9921ff
chore: add changeset for v3.26.0 (#7428)
mrubens Aug 26, 2025
7c91e4f
Changeset version bump (#7429)
github-actions[bot] Aug 26, 2025
934bfd0
feat: Add Vercel AI Gateway provider integration (#7396)
joshualipman123 Aug 26, 2025
11c454f
feat: Enable on-disk storage for Qdrant vectors and HNSW index (#7182)
daniel-lxs Aug 26, 2025
ff1f4f0
fix: use anthropic protocol for token counting when using anthropic m…
daniel-lxs Aug 27, 2025
3528f51
fix: remove duplicate cache display in task header (#7443)
mrubens Aug 27, 2025
f02a2bb
Random chat text area cleanup (#7436)
cte Aug 27, 2025
02f551c
Update @roo-code/cloud to enable roomote control for cloud agents (#7…
cte Aug 27, 2025
c479678
Always set remoteControlEnabled to true for cloud agents (#7448)
cte Aug 27, 2025
46b6fdd
chore: add changeset for v3.26.1 (#7459)
mrubens Aug 27, 2025
faf5734
feat: show model ID in API configuration dropdown (#7423)
daniel-lxs Aug 27, 2025
33a8573
feat: update tooltip component to match native VSCode tooltip shadow …
roomote-v0[bot] Aug 27, 2025
1ad2129
Add support for Vercel embeddings (#7445)
mrubens Aug 27, 2025
94f3b2a
Remove dot before model display (#7461)
mrubens Aug 27, 2025
68e4629
Update contributors list (#7109)
github-actions[bot] Aug 27, 2025
bf9e447
Update 3.26.1 changeset (#7463)
mrubens Aug 27, 2025
d23bc01
Changeset version bump (#7460)
github-actions[bot] Aug 27, 2025
0f6079a
Add type for RooCodeEventName.TaskSpawned (#7465)
mrubens Aug 27, 2025
3cb489d
fix: hide .rooignore'd files from environment details by default (#7369)
roomote-v0[bot] Aug 27, 2025
d4a16f4
fix: exclude browser scroll actions from repetition detection (#7471)
roomote-v0[bot] Aug 28, 2025
2204457
Fix GPT-5 Responses API issues with condensing and image support (#7067)
daniel-lxs Aug 28, 2025
d1122ea
Bump cloud to 0.25.0 (#7475)
mrubens Aug 28, 2025
2092fb1
feat: add image generation tool with OpenRouter integration (#7474)
daniel-lxs Aug 28, 2025
548d3b4
Make the default image filename more generic (#7479)
mrubens Aug 28, 2025
43597b3
Release v3.26.2 (#7490)
mrubens Aug 28, 2025
bea0684
Support free imagegen (#7493)
mrubens Aug 28, 2025
8e66607
feat: update OpenRouter API to support input/output modalities and fi…
daniel-lxs Aug 28, 2025
6ef9dbd
Add padding to image model picker (#7494)
mrubens Aug 28, 2025
622da63
fix: prevent dirty state on initial mount in ImageGenerationSettings …
daniel-lxs Aug 28, 2025
8840902
Changeset version bump (#7491)
github-actions[bot] Aug 28, 2025
aee531a
Show console logging in vitests when the --no-silent flag is set (#7467)
hassoncs Aug 28, 2025
cd9e92f
Move @roo-code/cloud to the Roo-Code repo (#7503)
cte Aug 28, 2025
1e4c46f
Refactor the extension bridge (#7515)
cte Aug 29, 2025
1d46bd1
Implement deferred task subscriptions (#7517)
cte Aug 29, 2025
b22a618
feat: add optional input image parameter to image generation tool (#7…
roomote-v0[bot] Aug 29, 2025
01458f1
feat: sync extension bridge settings with cloud (#7535)
roomote-v0[bot] Aug 29, 2025
c3d84d2
refactor: flatten image generation settings structure (#7536)
daniel-lxs Aug 29, 2025
63e40d2
chore: add changeset for v3.26.3 (#7541)
mrubens Aug 29, 2025
a1f9b7d
Changeset version bump (#7542)
github-actions[bot] Aug 29, 2025
20929b0
Mode and provider profile selector (#7545)
cte Aug 29, 2025
0e95f93
Putting the Roo in Roo-leases (#7546)
mrubens Aug 30, 2025
c7d7ad8
Fix evals (#7547)
cte Aug 30, 2025
88bb813
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Aug 30, 2025
47f594f
fix: special tokens should not break task processing (#7540)
pwilkin Aug 30, 2025
4557000
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Aug 30, 2025
958df13
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Aug 30, 2025
c9ff380
docs: update PR template branding from Roo Code to Costrict
mini2s Aug 30, 2025
fad219e
feat: optimize memory usage for image handling in webview (#7556)
daniel-lxs Aug 30, 2025
f5e0525
feat: rename Account tab to Cloud tab (#7558)
roomote-v0[bot] Aug 30, 2025
63b71d8
feat: add Ollama API key support for Turbo mode (#7425)
roomote-v0[bot] Aug 30, 2025
5746dfc
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Aug 31, 2025
e0bd19d
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Aug 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/build/src/__tests__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ describe("generatePackageJson", () => {
when: "activeWebviewPanelId == zgsm.TabPanelProvider",
},
{
command: "zgsm.accountButtonClicked",
command: "zgsm.cloudButtonClicked",
group: "navigation@6",
when: "activeWebviewPanelId == zgsm.TabPanelProvider",
},
Expand Down Expand Up @@ -181,7 +181,7 @@ describe("generatePackageJson", () => {
when: "activeWebviewPanelId == roo-code-nightly.TabPanelProvider",
},
{
command: "roo-code-nightly.accountButtonClicked",
command: "roo-code-nightly.cloudButtonClicked",
group: "navigation@6",
when: "activeWebviewPanelId == roo-code-nightly.TabPanelProvider",
},
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export const SECRET_STATE_KEYS = [
"awsSecretKey",
"awsSessionToken",
"openAiApiKey",
"ollamaApiKey",
"geminiApiKey",
"openAiNativeApiKey",
"cerebrasApiKey",
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ export const clineSays = [
"api_req_retry_delayed",
"api_req_deleted",
"text",
"image",
"reasoning",
"completion_result",
"user_feedback",
Expand Down
1 change: 1 addition & 0 deletions packages/types/src/provider-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ const openAiSchema = baseProviderSettingsSchema.extend({
const ollamaSchema = baseProviderSettingsSchema.extend({
ollamaModelId: z.string().optional(),
ollamaBaseUrl: z.string().optional(),
ollamaApiKey: z.string().optional(),
})

const vsCodeLmSchema = baseProviderSettingsSchema.extend({
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const commandIds = [
"historyButtonClicked",
"marketplaceButtonClicked",
"popoutButtonClicked",
"accountButtonClicked",
"cloudButtonClicked",
"settingsButtonClicked",

"openInNewTab",
Expand Down
6 changes: 3 additions & 3 deletions src/activate/registerCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,16 @@ export const registerCommands = (options: RegisterCommandOptions) => {

const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOptions): Record<CommandId, any> => ({
activationCompleted: () => {},
accountButtonClicked: () => {
cloudButtonClicked: () => {
const visibleProvider = getVisibleProviderOrLog(outputChannel)

if (!visibleProvider) {
return
}

TelemetryService.instance.captureTitleButtonClicked("account")
TelemetryService.instance.captureTitleButtonClicked("cloud")

visibleProvider.postMessageToWebview({ type: "action", action: "accountButtonClicked" })
visibleProvider.postMessageToWebview({ type: "action", action: "cloudButtonClicked" })
},
plusButtonClicked: async () => {
const visibleProvider = getVisibleProviderOrLog(outputChannel)
Expand Down
11 changes: 11 additions & 0 deletions src/api/providers/__tests__/ollama.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,17 @@ describe("OllamaHandler", () => {
})
expect(handlerWithoutUrl).toBeInstanceOf(OllamaHandler)
})

it("should use API key when provided", () => {
const handlerWithApiKey = new OllamaHandler({
apiModelId: "llama2",
ollamaModelId: "llama2",
ollamaBaseUrl: "https://ollama.com",
ollamaApiKey: "test-api-key",
})
expect(handlerWithApiKey).toBeInstanceOf(OllamaHandler)
// The API key will be used in the Authorization header
})
})

describe("createMessage", () => {
Expand Down
15 changes: 12 additions & 3 deletions src/api/providers/native-ollama.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Anthropic } from "@anthropic-ai/sdk"
import { Message, Ollama } from "ollama"
import { Message, Ollama, type Config as OllamaOptions } from "ollama"
import { ModelInfo, openAiModelInfoSaneDefaults, DEEP_SEEK_DEFAULT_TEMPERATURE } from "@roo-code/types"
import { ApiStream } from "../transform/stream"
import { BaseProvider } from "./base-provider"
Expand Down Expand Up @@ -140,10 +140,19 @@ export class NativeOllamaHandler extends BaseProvider implements SingleCompletio
private ensureClient(): Ollama {
if (!this.client) {
try {
this.client = new Ollama({
const clientOptions: OllamaOptions = {
host: this.options.ollamaBaseUrl || "http://localhost:11434",
// Note: The ollama npm package handles timeouts internally
})
}

// Add API key if provided (for Ollama cloud or authenticated instances)
if (this.options.ollamaApiKey) {
clientOptions.headers = {
Authorization: `Bearer ${this.options.ollamaApiKey}`,
}
}

this.client = new Ollama(clientOptions)
} catch (error: any) {
throw new Error(`Error creating Ollama client: ${error.message}`)
}
Expand Down
12 changes: 11 additions & 1 deletion src/api/providers/ollama.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,20 @@ export class OllamaHandler extends BaseProvider implements SingleCompletionHandl
super()
this.options = options

// Use the API key if provided (for Ollama cloud or authenticated instances)
// Otherwise use "ollama" as a placeholder for local instances
const apiKey = this.options.ollamaApiKey || "ollama"

const headers: Record<string, string> = {}
if (this.options.ollamaApiKey) {
headers["Authorization"] = `Bearer ${this.options.ollamaApiKey}`
}

this.client = new OpenAI({
baseURL: (this.options.ollamaBaseUrl || "http://localhost:11434") + "/v1",
apiKey: "ollama",
apiKey: apiKey,
timeout: getApiRequestTimeout(),
defaultHeaders: headers,
})
}

Expand Down
13 changes: 9 additions & 4 deletions src/core/tools/generateImageTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { fileExistsAtPath } from "../../utils/fs"
import { getReadablePath } from "../../utils/path"
import { isPathOutsideWorkspace } from "../../utils/pathUtils"
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
import { safeWriteJson } from "../../utils/safeWriteJson"
import { OpenRouterHandler } from "../../api/providers/openrouter"

// Hardcoded list of image generation models for now
Expand Down Expand Up @@ -237,12 +236,18 @@ export async function generateImageTool(

cline.didEditFile = true

// Display the generated image in the chat using a text message with the image
await cline.say("text", getReadablePath(cline.cwd, finalPath), [result.imageData])

// Record successful tool usage
cline.recordToolUsage("generate_image")

// Get the webview URI for the image
const provider = cline.providerRef.deref()
const fullImagePath = path.join(cline.cwd, finalPath)

// Convert to webview URI if provider is available
const imageUri = provider?.convertToWebviewUri?.(fullImagePath) ?? vscode.Uri.file(fullImagePath).toString()

// Send the image with the webview URI
await cline.say("image", JSON.stringify({ imageUri, imagePath: fullImagePath }))
pushToolResult(formatResponse.toolResult(getReadablePath(cline.cwd, finalPath)))

return
Expand Down
49 changes: 46 additions & 3 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,17 @@ export class ClineProvider
setTtsSpeed(ttsSpeed ?? 1)
})

// Set up webview options with proper resource roots
const resourceRoots = [this.contextProxy.extensionUri]

// Add workspace folders to allow access to workspace files
if (vscode.workspace.workspaceFolders) {
resourceRoots.push(...vscode.workspace.workspaceFolders.map((folder) => folder.uri))
}

webviewView.webview.options = {
enableScripts: true,
localResourceRoots: [this.contextProxy.extensionUri],
localResourceRoots: resourceRoots,
}

webviewView.webview.html =
Expand Down Expand Up @@ -1421,7 +1429,7 @@ export class ClineProvider
// Check MDM compliance and send user to account tab if not compliant
// Only redirect if there's an actual MDM policy requiring authentication
if (this.mdmService?.requiresCloudAuth() && !this.checkMdmCompliance()) {
await this.postMessageToWebview({ type: "action", action: "accountButtonClicked" })
await this.postMessageToWebview({ type: "action", action: "cloudButtonClicked" })
}
}

Expand Down Expand Up @@ -2590,12 +2598,47 @@ export class ClineProvider
public get cwd() {
return getWorkspacePath()
}

public getZgsmAuthCommands() {
return this.zgsmAuthCommands
}

public setZgsmAuthCommands(zgsmAuthCommands: ZgsmAuthCommands) {
this.zgsmAuthCommands = zgsmAuthCommands
}

/**
* Convert a file path to a webview-accessible URI
* This method safely converts file paths to URIs that can be loaded in the webview
*
* @param filePath - The absolute file path to convert
* @returns The webview URI string, or the original file URI if conversion fails
* @throws {Error} When webview is not available
* @throws {TypeError} When file path is invalid
*/
public convertToWebviewUri(filePath: string): string {
try {
const fileUri = vscode.Uri.file(filePath)

// Check if we have a webview available
if (this.view?.webview) {
const webviewUri = this.view.webview.asWebviewUri(fileUri)
return webviewUri.toString()
}

// Specific error for no webview available
const error = new Error("No webview available for URI conversion")
console.error(error.message)
// Fallback to file URI if no webview available
return fileUri.toString()
} catch (error) {
// More specific error handling
if (error instanceof TypeError) {
console.error("Invalid file path provided for URI conversion:", error)
} else {
console.error("Failed to convert to webview URI:", error)
}
// Return file URI as fallback
return vscode.Uri.file(filePath).toString()
}
}
}
6 changes: 3 additions & 3 deletions src/core/webview/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2128,9 +2128,9 @@ export const webviewMessageHandler = async (
await provider.postStateToWebview()
break
}
case "accountButtonClicked": {
// Navigate to the account tab.
provider.postMessageToWebview({ type: "action", action: "accountButtonClicked" })
case "cloudButtonClicked": {
// Navigate to the cloud tab.
provider.postMessageToWebview({ type: "action", action: "cloudButtonClicked" })
break
}
case "rooCloudSignIn": {
Expand Down
42 changes: 40 additions & 2 deletions src/integrations/misc/image-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,46 @@ import * as vscode from "vscode"
import { getWorkspacePath } from "../../utils/path"
import { t } from "../../i18n"

export async function openImage(dataUri: string, options?: { values?: { action?: string } }) {
const matches = dataUri.match(/^data:image\/([a-zA-Z]+);base64,(.+)$/)
export async function openImage(dataUriOrPath: string, options?: { values?: { action?: string } }) {
// Check if it's a file path (absolute or relative)
const isFilePath =
!dataUriOrPath.startsWith("data:") &&
!dataUriOrPath.startsWith("http:") &&
!dataUriOrPath.startsWith("https:") &&
!dataUriOrPath.startsWith("vscode-resource:") &&
!dataUriOrPath.startsWith("file+.vscode-resource")

if (isFilePath) {
// Handle file path - open directly in VSCode
try {
// Resolve the path relative to workspace if needed
let filePath = dataUriOrPath
if (!path.isAbsolute(filePath)) {
const workspacePath = getWorkspacePath()
if (workspacePath) {
filePath = path.join(workspacePath, filePath)
}
}

const fileUri = vscode.Uri.file(filePath)

// Check if this is a copy action
if (options?.values?.action === "copy") {
await vscode.env.clipboard.writeText(filePath)
vscode.window.showInformationMessage(t("common:info.path_copied_to_clipboard"))
return
}

// Open the image file directly
await vscode.commands.executeCommand("vscode.open", fileUri)
} catch (error) {
vscode.window.showErrorMessage(t("common:errors.error_opening_image", { error }))
}
return
}

// Handle data URI (existing logic)
const matches = dataUriOrPath.match(/^data:image\/([a-zA-Z]+);base64,(.+)$/)
if (!matches) {
vscode.window.showErrorMessage(t("common:errors.invalid_data_uri"))
return
Expand Down
8 changes: 4 additions & 4 deletions src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,8 @@
"icon": "$(link-external)"
},
{
"command": "zgsm.accountButtonClicked",
"title": "%command.account.title%",
"command": "zgsm.cloudButtonClicked",
"title": "%command.cloud.title%",
"icon": "$(account)"
},
{
Expand Down Expand Up @@ -323,7 +323,7 @@
"when": "view == zgsm.SidebarProvider"
},
{
"command": "zgsm.accountButtonClicked",
"command": "zgsm.cloudButtonClicked",
"group": "navigation@4",
"when": "view == zgsm.SidebarProvider"
},
Expand Down Expand Up @@ -370,7 +370,7 @@
"when": "activeWebviewPanelId == zgsm.TabPanelProvider"
},
{
"command": "zgsm.accountButtonClicked",
"command": "zgsm.cloudButtonClicked",
"group": "navigation@4",
"when": "activeWebviewPanelId == zgsm.TabPanelProvider"
},
Expand Down
2 changes: 1 addition & 1 deletion src/package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"command.history.title": "History",
"command.marketplace.title": "Marketplace",
"command.openInEditor.title": "Open in Editor",
"command.account.title": "Account",
"command.cloud.title": "Account",
"command.settings.title": "Settings",
"command.documentation.title": "Documentation",
"command.openInNewTab.title": "Open In New Tab",
Expand Down
2 changes: 1 addition & 1 deletion src/package.nls.zh-CN.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/package.nls.zh-TW.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export interface ExtensionMessage {
| "historyButtonClicked"
| "promptsButtonClicked"
| "marketplaceButtonClicked"
| "accountButtonClicked"
| "cloudButtonClicked"
| "zgsmAccountButtonClicked"
| "didBecomeVisible"
| "focusInput"
Expand Down
4 changes: 2 additions & 2 deletions src/shared/WebviewMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export interface WebviewMessage {
| "toggleApiConfigPin"
| "setHistoryPreviewCollapsed"
| "hasOpenedModeSelector"
| "accountButtonClicked"
| "cloudButtonClicked"
| "rooCloudSignIn"
| "rooCloudSignOut"
| "condenseTaskContextRequest"
Expand Down Expand Up @@ -238,7 +238,7 @@ export interface WebviewMessage {
| "openRouterImageGenerationSelectedModel"
text?: string
editedMessageContent?: string
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "account" | "zgsm-account"
tab?: "settings" | "history" | "mcp" | "modes" | "chat" | "marketplace" | "cloud" | "zgsm-account"
disabled?: boolean
context?: string
dataUri?: string
Expand Down
Loading
Loading