Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
167 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
c970274
Disconnect extension bridge on logout (#7563)
mrubens Sep 1, 2025
97cfb96
Fix claudeCode.notFound translation key (#7571)
chrarnoldus Sep 1, 2025
00d26ee
v3.26.4 (#7579)
mrubens Sep 1, 2025
5092cdf
Update contributors list (#7462)
github-actions[bot] Sep 1, 2025
ae8a639
Changeset version bump (#7580)
github-actions[bot] Sep 1, 2025
fe2b612
feat: add configurable embedding batch size for code indexing (#7464)
roomote-v0[bot] Sep 2, 2025
2e59347
Shows a pill with the base Roo Code Cloud URL when not pointing to pr…
brunobergher Sep 2, 2025
d396555
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 2, 2025
23fcc30
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 2, 2025
59d6e74
Cloud: fix provider syncing (#7603)
jr Sep 2, 2025
d1baa6e
fix: add cache reporting support for OpenAI-Native provider (#7602)
hannesrudolph Sep 2, 2025
7e24600
feat: add auto-approve support for MCP access_resource tool (#7606)
daniel-lxs Sep 3, 2025
5196c75
Move message queue to the extension host (#7604)
cte Sep 3, 2025
641c058
Send custom modes to the extension bridge (#7612)
cte Sep 3, 2025
f8973d9
Never give up in socket transport (#7616)
mrubens Sep 3, 2025
1c17366
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 3, 2025
c1509da
Fix socket-io client event handling (#7618)
cte Sep 3, 2025
aa4144e
More socket-io client fixes from PR feedback (#7619)
cte Sep 3, 2025
bcb71db
More socket-io client logging improvements (#7620)
cte Sep 3, 2025
43ff486
Publish subtask events (#7626)
cte Sep 3, 2025
c3e748b
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 3, 2025
cb81377
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 3, 2025
84bc703
Update chutes.ts to add Qwen3 235B A22B Thinking 2507 model (#7578)
mohammad154 Sep 3, 2025
7f5d82f
chore: add changeset for v3.26.5 (#7628)
mrubens Sep 3, 2025
c0b9e7a
Update contributors list (#7629)
github-actions[bot] Sep 3, 2025
130ce29
Changeset version bump (#7630)
github-actions[bot] Sep 3, 2025
d789692
feat: add run_slash_command tool for executing slash commands (#7473)
roomote-v0[bot] Sep 3, 2025
280b75d
Focus the extension when receiving bridge commands (#7633)
cte Sep 3, 2025
8dbd30a
Release: v1.73.0 (#7636)
mrubens Sep 3, 2025
f12f193
Cloud: remove extension_bridge_enabled for personal users (#7638)
jr Sep 3, 2025
c25cfde
Publish token usage metrics (#7637)
cte Sep 3, 2025
1f5ee43
fix: preserve scroll position when switching tabs in settings (#7587)
DC-Dancao Sep 3, 2025
0126c5d
feat: add Kimi K2 Turbo model configuration to moonshotModels (#7593)
wangxiaolong100 Sep 4, 2025
e7f599b
fix: use askApproval wrapper in insert_content and search_and_replace…
roomote-v0[bot] Sep 4, 2025
e2c1a20
Release v3.26.6 (#7650)
mrubens Sep 4, 2025
08a825f
Changeset version bump (#7651)
github-actions[bot] Sep 4, 2025
a0384f3
Delete .github/workflows/discord-pr-notify.yml
mrubens Sep 4, 2025
e1dfe25
Remove unused slack notif (#7655)
mrubens Sep 4, 2025
966ed76
Handle zsh process substitution correctly (#7658)
mrubens Sep 4, 2025
b50104c
Handle zsh glob qualifiers correctly (#7667)
mrubens Sep 4, 2025
b48b0be
Minor zh-TW Traditional Chinese locale typo fix (#7672)
PeterDaveHello Sep 4, 2025
72502d8
feat: Add DeepInfra as a model provider in Roo Code (#7677)
Thachnh Sep 4, 2025
7935c94
fix: validate MCP tool exists before execution (#7632)
roomote-v0[bot] Sep 4, 2025
65146b1
fix: add error transform to cryptic openAI SDK errors when API key is…
roomote-v0[bot] Sep 5, 2025
571d1a4
feat: OpenAI Responses API service tiers (flex/priority) β€” UI selecto…
hannesrudolph Sep 5, 2025
de12ec1
fix: prevent countdown timer from showing in history for answered fol…
daniel-lxs Sep 5, 2025
bca6e86
fix: Fix the issue of Moonshot's maximum return token count being lim…
wangxiaolong100 Sep 5, 2025
d9f80f1
feat: update kimi-k2-0905-preview and kimi-k2-turbo-preview (#7663)
CellenLee Sep 5, 2025
2b73251
Fix test
mrubens Sep 5, 2025
282a75b
Release v3.26.7 (#7691)
mrubens Sep 5, 2025
146d849
Delete .changeset/petite-rats-admire.md
mrubens Sep 5, 2025
4ad1a26
feat: Add Kimi K2 0905 model to Groq, Moonshot, and Fireworks provide…
daniel-lxs Sep 5, 2025
467c9f5
Use an allowlist to keep the prompt default shell sane (#7681)
jr Sep 5, 2025
90e7d09
Changeset version bump (#7690)
github-actions[bot] Sep 5, 2025
55ea328
Fix: Improve WelcomeView styling and readability (#7682)
daniel-lxs Sep 5, 2025
2c8c140
feat: add Kimi K2-0905 model to Chutes provider (#7701)
roomote-v0[bot] Sep 5, 2025
2b53399
fix: handle array paths from VSCode terminal profiles (#7697)
roomote-v0[bot] Sep 5, 2025
e559ac6
Edit/Delete User Message (#7447)
NaccOll Sep 5, 2025
0510c03
fix: prevent stack overflow in codebase indexing for large projects (…
daniel-lxs Sep 5, 2025
1e403a7
fix: identify mcp and slash command config path in multiple folder wo…
NaccOll Sep 5, 2025
687b379
fix: resolve CI e2e test ETIMEDOUT errors when downloading VS Code (#…
daniel-lxs Sep 5, 2025
c206da4
fix: Tackling Race/State condition issue by Changing the Code Design …
HahaBill Sep 5, 2025
49b50c8
fix: preserve context by retrying with full conversation on invalid p…
daniel-lxs Sep 5, 2025
ae01a90
chore: add changeset for v3.26.8 (#7715)
mrubens Sep 5, 2025
ed765a3
feat(checkpoints): create checkpoint when user sends a message (#7713)
roomote-v0[bot] Sep 5, 2025
e3facc1
Bump to 3.27.0 (#7719)
mrubens Sep 5, 2025
8864651
Changeset version bump (#7716)
github-actions[bot] Sep 5, 2025
e8deedd
fix: update DeepSeek pricing to new unified rates effective Sept 5, 2…
roomote-v0[bot] Sep 5, 2025
079b37a
feat: replace cloud waitlist ad with direct Cloud link in navigation …
roomote-v0[bot] Sep 6, 2025
9378a4e
feat: show dash instead of zero for missing data on evals page (#7748)
roomote-v0[bot] Sep 6, 2025
18cf33f
Feature/update vertex ai models and regions (#7727)
ssweens Sep 7, 2025
247da38
Add model info to eval runs table (#7749)
cte Sep 7, 2025
28d46cd
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 7, 2025
480670e
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 7, 2025
888bd2d
chore(deps): update dependency eslint-config-prettier to v10.1.8 (#6464)
renovate[bot] Sep 7, 2025
408ea44
chore(deps): update dependency esbuild to v0.25.9 (#5455)
renovate[bot] Sep 7, 2025
8f2d40d
chore(deps): update dependency @changesets/cli to v2.29.6 (#7376)
renovate[bot] Sep 7, 2025
4e5e3ed
chore(deps): update dependency nock to v14.0.10 (#6465)
renovate[bot] Sep 7, 2025
2571781
chore(deps): update dependency eslint-plugin-turbo to v2.5.6 (#7764)
renovate[bot] Sep 8, 2025
b4d34df
refactor(utils): simplify shell detection logic
mini2s Sep 8, 2025
de2f3fc
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 8, 2025
97c3257
test: update shell detection test expectation and mocks
mini2s Sep 8, 2025
acd07b0
test: add mock cleanup in shell detection tests
mini2s Sep 8, 2025
42e316b
test: update shell detection tests to prioritize PowerShell 7
mini2s Sep 8, 2025
a3f61d1
fix(workspace-event-monitor): increase max retries and improve retry …
mini2s Sep 8, 2025
d46c50b
refactor(codebase): improve error handling and workspace validation
mini2s Sep 8, 2025
f7d814c
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 8, 2025
212badc
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 8, 2025
0ce4e89
Revert PR #7188 - Restore temperature parameter to fix TabbyApi/ExLla…
daniel-lxs Sep 8, 2025
0188159
fix: reduce CodeBlock button z-index to prevent overlap with popovers…
daniel-lxs Sep 9, 2025
76c6745
Make ollama models info transport work like lmstudio (#7679)
ItsOnlyBinary Sep 9, 2025
195f4eb
feat: add click-to-edit, ESC-to-cancel, and fix padding consistency f…
roomote-v0[bot] Sep 9, 2025
5d3e603
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 9, 2025
5780659
Let people paste in the auth redirect url (#7805)
mrubens Sep 9, 2025
3c79656
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 9, 2025
a8d903f
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 9, 2025
433e249
test: change console.error to console.warn in tests
mini2s Sep 9, 2025
88b5d66
fix: resolve chat message edit/delete duplication issues (#7793)
daniel-lxs Sep 9, 2025
39030bf
fix: add GIT_EDITOR env var to merge-resolver mode for non-interactiv…
daniel-lxs Sep 9, 2025
bbd3d98
UI: Render reasoning as plain italic (match <thinking>) (#7752)
roomote-v0[bot] Sep 9, 2025
dbb4fed
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 9, 2025
de0cd99
Add taskSyncEnabled to userSettingsConfigSchema (#7827)
roomote-v0[bot] Sep 9, 2025
d2e07ec
Release: v1.75.0 (#7829)
jr Sep 9, 2025
48d592f
fix: prevent negative cost values and improve label visibility in eva…
roomote-v0[bot] Sep 9, 2025
18d16a7
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 10, 2025
7cd6520
Fix Groq context window display (#7839)
mrubens Sep 10, 2025
18c3116
Merge remote-tracking branch 'upstream/main' into roo-to-main
mini2s Sep 10, 2025
ad61a6c
test: enhance vscode mock implementations and error handling
mini2s Sep 10, 2025
c0dd987
feat(chat): replace edit button with copy functionality
mini2s Sep 10, 2025
d572681
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 10, 2025
2d576f9
Merge branch 'main' of github.com:zgsm-ai/costrict into roo-to-main
mini2s Sep 10, 2025
b033fbf
refactor(core): enhance binary file detection and encoding handling
mini2s Sep 10, 2025
0da9ac5
feat(chat): add chat search functionality with highlighting
mini2s Sep 10, 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
Prev Previous commit
Next Next commit
refactor: flatten image generation settings structure (#7536)
  • Loading branch information
daniel-lxs authored Aug 29, 2025
commit c3d84d295db48a8d348d27dca914471437a6c9b6
25 changes: 21 additions & 4 deletions packages/types/src/global-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export const globalSettingsSchema = z.object({
customInstructions: z.string().optional(),
taskHistory: z.array(historyItemSchema).optional(),

// Image generation settings (experimental) - flattened for simplicity
openRouterImageApiKey: z.string().optional(),
openRouterImageGenerationSelectedModel: z.string().optional(),

condensingApiConfigId: z.string().optional(),
customCondensingPrompt: z.string().optional(),

Expand Down Expand Up @@ -200,11 +204,24 @@ export const SECRET_STATE_KEYS = [
"featherlessApiKey",
"ioIntelligenceApiKey",
"vercelAiGatewayApiKey",
] as const satisfies readonly (keyof ProviderSettings)[]
export type SecretState = Pick<ProviderSettings, (typeof SECRET_STATE_KEYS)[number]>
] as const

// Global secrets that are part of GlobalSettings (not ProviderSettings)
export const GLOBAL_SECRET_KEYS = [
"openRouterImageApiKey", // For image generation
] as const

// Type for the actual secret storage keys
type ProviderSecretKey = (typeof SECRET_STATE_KEYS)[number]
type GlobalSecretKey = (typeof GLOBAL_SECRET_KEYS)[number]

// Type representing all secrets that can be stored
export type SecretState = Pick<ProviderSettings, Extract<ProviderSecretKey, keyof ProviderSettings>> & {
[K in GlobalSecretKey]?: string
}

export const isSecretStateKey = (key: string): key is Keys<SecretState> =>
SECRET_STATE_KEYS.includes(key as Keys<SecretState>)
SECRET_STATE_KEYS.includes(key as ProviderSecretKey) || GLOBAL_SECRET_KEYS.includes(key as GlobalSecretKey)

/**
* GlobalState
Expand All @@ -213,7 +230,7 @@ export const isSecretStateKey = (key: string): key is Keys<SecretState> =>
export type GlobalState = Omit<RooCodeSettings, Keys<SecretState>>

export const GLOBAL_STATE_KEYS = [...GLOBAL_SETTINGS_KEYS, ...PROVIDER_SETTINGS_KEYS].filter(
(key: Keys<RooCodeSettings>) => !SECRET_STATE_KEYS.includes(key as Keys<SecretState>),
(key: Keys<RooCodeSettings>) => !isSecretStateKey(key),
) as Keys<GlobalState>[]

export const isGlobalStateKey = (key: string): key is Keys<GlobalState> =>
Expand Down
7 changes: 0 additions & 7 deletions packages/types/src/provider-settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,6 @@ const openRouterSchema = baseProviderSettingsSchema.extend({
openRouterBaseUrl: z.string().optional(),
openRouterSpecificProvider: z.string().optional(),
openRouterUseMiddleOutTransform: z.boolean().optional(),
// Image generation settings (experimental)
openRouterImageGenerationSettings: z
.object({
openRouterApiKey: z.string().optional(),
selectedModel: z.string().optional(),
})
.optional(),
})

const bedrockSchema = apiModelIdProviderModelSchema.extend({
Expand Down
124 changes: 102 additions & 22 deletions src/core/config/ContextProxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
GLOBAL_SETTINGS_KEYS,
SECRET_STATE_KEYS,
GLOBAL_STATE_KEYS,
GLOBAL_SECRET_KEYS,
type ProviderSettings,
type GlobalSettings,
type SecretState,
Expand Down Expand Up @@ -61,19 +62,77 @@ export class ContextProxy {
}
}

const promises = SECRET_STATE_KEYS.map(async (key) => {
try {
this.secretCache[key] = await this.originalContext.secrets.get(key)
} catch (error) {
logger.error(`Error loading secret ${key}: ${error instanceof Error ? error.message : String(error)}`)
}
})
const promises = [
...SECRET_STATE_KEYS.map(async (key) => {
try {
this.secretCache[key] = await this.originalContext.secrets.get(key)
} catch (error) {
logger.error(
`Error loading secret ${key}: ${error instanceof Error ? error.message : String(error)}`,
)
}
}),
...GLOBAL_SECRET_KEYS.map(async (key) => {
try {
this.secretCache[key] = await this.originalContext.secrets.get(key)
} catch (error) {
logger.error(
`Error loading global secret ${key}: ${error instanceof Error ? error.message : String(error)}`,
)
}
}),
]

await Promise.all(promises)

// Migration: Check for old nested image generation settings and migrate them
await this.migrateImageGenerationSettings()

this._isInitialized = true
}

/**
* Migrates old nested openRouterImageGenerationSettings to the new flattened structure
*/
private async migrateImageGenerationSettings() {
try {
// Check if there's an old nested structure
const oldNestedSettings = this.originalContext.globalState.get<any>("openRouterImageGenerationSettings")

if (oldNestedSettings && typeof oldNestedSettings === "object") {
logger.info("Migrating old nested image generation settings to flattened structure")

// Migrate the API key if it exists and we don't already have one
if (oldNestedSettings.openRouterApiKey && !this.secretCache.openRouterImageApiKey) {
await this.originalContext.secrets.store(
"openRouterImageApiKey",
oldNestedSettings.openRouterApiKey,
)
this.secretCache.openRouterImageApiKey = oldNestedSettings.openRouterApiKey
logger.info("Migrated openRouterImageApiKey to secrets")
}

// Migrate the selected model if it exists and we don't already have one
if (oldNestedSettings.selectedModel && !this.stateCache.openRouterImageGenerationSelectedModel) {
await this.originalContext.globalState.update(
"openRouterImageGenerationSelectedModel",
oldNestedSettings.selectedModel,
)
this.stateCache.openRouterImageGenerationSelectedModel = oldNestedSettings.selectedModel
logger.info("Migrated openRouterImageGenerationSelectedModel to global state")
}

// Clean up the old nested structure
await this.originalContext.globalState.update("openRouterImageGenerationSettings", undefined)
logger.info("Removed old nested openRouterImageGenerationSettings")
}
} catch (error) {
logger.error(
`Error during image generation settings migration: ${error instanceof Error ? error.message : String(error)}`,
)
}
}

public get extensionUri() {
return this.originalContext.extensionUri
}
Expand Down Expand Up @@ -152,20 +211,34 @@ export class ContextProxy {
* This is useful when you need to ensure the cache has the latest values
*/
async refreshSecrets(): Promise<void> {
const promises = SECRET_STATE_KEYS.map(async (key) => {
try {
this.secretCache[key] = await this.originalContext.secrets.get(key)
} catch (error) {
logger.error(
`Error refreshing secret ${key}: ${error instanceof Error ? error.message : String(error)}`,
)
}
})
const promises = [
...SECRET_STATE_KEYS.map(async (key) => {
try {
this.secretCache[key] = await this.originalContext.secrets.get(key)
} catch (error) {
logger.error(
`Error refreshing secret ${key}: ${error instanceof Error ? error.message : String(error)}`,
)
}
}),
...GLOBAL_SECRET_KEYS.map(async (key) => {
try {
this.secretCache[key] = await this.originalContext.secrets.get(key)
} catch (error) {
logger.error(
`Error refreshing global secret ${key}: ${error instanceof Error ? error.message : String(error)}`,
)
}
}),
]
await Promise.all(promises)
}

private getAllSecretState(): SecretState {
return Object.fromEntries(SECRET_STATE_KEYS.map((key) => [key, this.getSecret(key)]))
return Object.fromEntries([
...SECRET_STATE_KEYS.map((key) => [key, this.getSecret(key as SecretStateKey)]),
...GLOBAL_SECRET_KEYS.map((key) => [key, this.getSecret(key as SecretStateKey)]),
])
}

/**
Expand Down Expand Up @@ -232,18 +305,24 @@ export class ContextProxy {
* RooCodeSettings
*/

public setValue<K extends RooCodeSettingsKey>(key: K, value: RooCodeSettings[K]) {
return isSecretStateKey(key) ? this.storeSecret(key, value as string) : this.updateGlobalState(key, value)
public async setValue<K extends RooCodeSettingsKey>(key: K, value: RooCodeSettings[K]) {
return isSecretStateKey(key)
? this.storeSecret(key as SecretStateKey, value as string)
: this.updateGlobalState(key as GlobalStateKey, value)
}

public getValue<K extends RooCodeSettingsKey>(key: K): RooCodeSettings[K] {
return isSecretStateKey(key)
? (this.getSecret(key) as RooCodeSettings[K])
: (this.getGlobalState(key) as RooCodeSettings[K])
? (this.getSecret(key as SecretStateKey) as RooCodeSettings[K])
: (this.getGlobalState(key as GlobalStateKey) as RooCodeSettings[K])
}

public getValues(): RooCodeSettings {
return { ...this.getAllGlobalState(), ...this.getAllSecretState() }
const globalState = this.getAllGlobalState()
const secretState = this.getAllSecretState()

// Simply merge all states - no nested secrets to handle
return { ...globalState, ...secretState }
}

public async setValues(values: RooCodeSettings) {
Expand Down Expand Up @@ -285,6 +364,7 @@ export class ContextProxy {
await Promise.all([
...GLOBAL_STATE_KEYS.map((key) => this.originalContext.globalState.update(key, undefined)),
...SECRET_STATE_KEYS.map((key) => this.originalContext.secrets.delete(key)),
...GLOBAL_SECRET_KEYS.map((key) => this.originalContext.secrets.delete(key)),
])

await this.initialize()
Expand Down
21 changes: 15 additions & 6 deletions src/core/config/__tests__/ContextProxy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import * as vscode from "vscode"

import { GLOBAL_STATE_KEYS, SECRET_STATE_KEYS } from "@roo-code/types"
import { GLOBAL_STATE_KEYS, SECRET_STATE_KEYS, GLOBAL_SECRET_KEYS } from "@roo-code/types"

import { ContextProxy } from "../ContextProxy"

Expand Down Expand Up @@ -70,17 +70,23 @@ describe("ContextProxy", () => {

describe("constructor", () => {
it("should initialize state cache with all global state keys", () => {
expect(mockGlobalState.get).toHaveBeenCalledTimes(GLOBAL_STATE_KEYS.length)
// +1 for the migration check of old nested settings
expect(mockGlobalState.get).toHaveBeenCalledTimes(GLOBAL_STATE_KEYS.length + 1)
for (const key of GLOBAL_STATE_KEYS) {
expect(mockGlobalState.get).toHaveBeenCalledWith(key)
}
// Also check for migration call
expect(mockGlobalState.get).toHaveBeenCalledWith("openRouterImageGenerationSettings")
})

it("should initialize secret cache with all secret keys", () => {
expect(mockSecrets.get).toHaveBeenCalledTimes(SECRET_STATE_KEYS.length)
expect(mockSecrets.get).toHaveBeenCalledTimes(SECRET_STATE_KEYS.length + GLOBAL_SECRET_KEYS.length)
for (const key of SECRET_STATE_KEYS) {
expect(mockSecrets.get).toHaveBeenCalledWith(key)
}
for (const key of GLOBAL_SECRET_KEYS) {
expect(mockSecrets.get).toHaveBeenCalledWith(key)
}
})
})

Expand All @@ -93,8 +99,8 @@ describe("ContextProxy", () => {
const result = proxy.getGlobalState("apiProvider")
expect(result).toBe("deepseek")

// Original context should be called once during updateGlobalState
expect(mockGlobalState.get).toHaveBeenCalledTimes(GLOBAL_STATE_KEYS.length) // Only from initialization
// Original context should be called once during updateGlobalState (+1 for migration check)
expect(mockGlobalState.get).toHaveBeenCalledTimes(GLOBAL_STATE_KEYS.length + 1) // From initialization + migration check
})

it("should handle default values correctly", async () => {
Expand Down Expand Up @@ -403,9 +409,12 @@ describe("ContextProxy", () => {
for (const key of SECRET_STATE_KEYS) {
expect(mockSecrets.delete).toHaveBeenCalledWith(key)
}
for (const key of GLOBAL_SECRET_KEYS) {
expect(mockSecrets.delete).toHaveBeenCalledWith(key)
}

// Total calls should equal the number of secret keys
expect(mockSecrets.delete).toHaveBeenCalledTimes(SECRET_STATE_KEYS.length)
expect(mockSecrets.delete).toHaveBeenCalledTimes(SECRET_STATE_KEYS.length + GLOBAL_SECRET_KEYS.length)
})

it("should reinitialize caches after reset", async () => {
Expand Down
8 changes: 2 additions & 6 deletions src/core/tools/__tests__/generateImageTool.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,8 @@ describe("generateImageTool", () => {
experiments: {
[EXPERIMENT_IDS.IMAGE_GENERATION]: true,
},
apiConfiguration: {
openRouterImageGenerationSettings: {
openRouterApiKey: "test-api-key",
selectedModel: "google/gemini-2.5-flash-image-preview",
},
},
openRouterImageApiKey: "test-api-key",
openRouterImageGenerationSelectedModel: "google/gemini-2.5-flash-image-preview",
}),
}),
},
Expand Down
8 changes: 3 additions & 5 deletions src/core/tools/generateImageTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,8 @@ export async function generateImageTool(
// Check if file is write-protected
const isWriteProtected = cline.rooProtectedController?.isWriteProtected(relPath) || false

// Get OpenRouter API key from experimental settings ONLY (no fallback to profile)
const apiConfiguration = state?.apiConfiguration
const imageGenerationSettings = apiConfiguration?.openRouterImageGenerationSettings
const openRouterApiKey = imageGenerationSettings?.openRouterApiKey
// Get OpenRouter API key from global settings (experimental image generation)
const openRouterApiKey = state?.openRouterImageApiKey

if (!openRouterApiKey) {
await cline.say(
Expand All @@ -148,7 +146,7 @@ export async function generateImageTool(
}

// Get selected model from settings or use default
const selectedModel = imageGenerationSettings?.selectedModel || IMAGE_GENERATION_MODELS[0]
const selectedModel = state?.openRouterImageGenerationSelectedModel || IMAGE_GENERATION_MODELS[0]

// Determine if the path is outside the workspace
const fullPath = path.resolve(cline.cwd, removeClosingTag("path", relPath))
Expand Down
7 changes: 7 additions & 0 deletions src/core/webview/ClineProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,8 @@ export class ClineProvider
maxDiagnosticMessages,
includeTaskHistoryInEnhance,
remoteControlEnabled,
openRouterImageApiKey,
openRouterImageGenerationSelectedModel,
} = await this.getState()

const telemetryKey = process.env.POSTHOG_API_KEY
Expand Down Expand Up @@ -1893,6 +1895,8 @@ export class ClineProvider
maxDiagnosticMessages: maxDiagnosticMessages ?? 50,
includeTaskHistoryInEnhance: includeTaskHistoryInEnhance ?? true,
remoteControlEnabled,
openRouterImageApiKey,
openRouterImageGenerationSelectedModel,
}
}

Expand Down Expand Up @@ -2092,6 +2096,9 @@ export class ClineProvider
return false
}
})(),
// Add image generation settings
openRouterImageApiKey: stateValues.openRouterImageApiKey,
openRouterImageGenerationSelectedModel: stateValues.openRouterImageGenerationSelectedModel,
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/core/webview/__tests__/ClineProvider.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,8 @@ describe("ClineProvider", () => {
profileThresholds: {},
hasOpenedModeSelector: false,
diagnosticsEnabled: true,
openRouterImageApiKey: undefined,
openRouterImageGenerationSelectedModel: undefined,
}

const message: ExtensionMessage = {
Expand Down
8 changes: 8 additions & 0 deletions src/core/webview/webviewMessageHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,14 @@ export const webviewMessageHandler = async (
await updateGlobalState("language", message.text as Language)
await provider.postStateToWebview()
break
case "openRouterImageApiKey":
await provider.contextProxy.setValue("openRouterImageApiKey", message.text)
await provider.postStateToWebview()
break
case "openRouterImageGenerationSelectedModel":
await provider.contextProxy.setValue("openRouterImageGenerationSelectedModel", message.text)
await provider.postStateToWebview()
break
case "showRooIgnoredFiles":
await updateGlobalState("showRooIgnoredFiles", message.bool ?? false)
await provider.postStateToWebview()
Expand Down
Loading