Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions webview-ui/playwright/roo-code-types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { DEFAULT_MODES } from "../../packages/types/src/mode"
export { DEFAULT_OPEN_AI_CODEX_USE_WEBSOCKET } from "../../packages/types/src/provider-settings/openai-codex"

export const DEFAULT_AUTO_CLOSE_ZOO_OPENED_FILES = false
export const DEFAULT_AUTO_CLOSE_ZOO_OPENED_FILES_AFTER_USER_EDITED = false
Expand Down
1 change: 1 addition & 0 deletions webview-ui/playwright/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const rooCodeTypesShimImporters = [
"/webview-ui/src/components/chat/CodeIndexPopover.tsx",
"/webview-ui/src/components/chat/ModeSelector.tsx",
"/webview-ui/src/components/settings/UISettings.tsx",
"/webview-ui/src/components/settings/providers/OpenAICodexWebSocketToggle.tsx",
]

export default defineConfig({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import React from "react"

import SettingsView from "../SettingsView"
import { vscode } from "@src/utils/vscode"
import { OpenAICodexWebSocketToggle } from "../providers/OpenAICodexWebSocketToggle"

const postMessage = vi.spyOn(vscode, "postMessage").mockImplementation(() => {})

Expand Down Expand Up @@ -684,6 +685,45 @@ describe("SettingsView - Unsaved Changes Detection", () => {
})
})

it.each([true, false, undefined])(
"buffers Codex WebSocket edits from %s until Save despite a live refresh",
async (enabled) => {
const configuration: ProviderSettings = {
apiProvider: providerIdentifiers.openaiCodex,
apiModelId: "gpt-5.6-sol",
openAiCodexUseWebSocket: enabled,
}
vi.mocked(useExtensionState, { partial: true }).mockReturnValue({
...defaultExtensionState,
apiConfiguration: configuration,
})
vi.mocked(ApiOptions).mockImplementation(({ apiConfiguration, setApiConfigurationField }) => (
<OpenAICodexWebSocketToggle
value={apiConfiguration.openAiCodexUseWebSocket}
onChange={(value) => setApiConfigurationField("openAiCodexUseWebSocket", value)}
/>
))
const view = renderWithExtensionState(<SettingsView onDone={vi.fn()} />, { queryClient })
fireEvent.click(await screen.findByRole("checkbox", { name: "settings:openAiCodexWebSocket.label" }))
vi.mocked(useExtensionState, { partial: true }).mockReturnValue({
...defaultExtensionState,
apiConfiguration: { ...configuration },
})
view.rerender(<SettingsView onDone={vi.fn()} />)
const checkbox = screen.getByRole("checkbox", { name: "settings:openAiCodexWebSocket.label" })
if (enabled) expect(checkbox).not.toBeChecked()
else expect(checkbox).toBeChecked()
expect(configuration.openAiCodexUseWebSocket).toBe(enabled)
expect(postMessage).not.toHaveBeenCalledWith(expect.objectContaining({ type: "upsertApiConfiguration" }))
fireEvent.click(screen.getByTestId("save-button"))
expect(postMessage).toHaveBeenCalledWith({
type: "upsertApiConfiguration",
text: "default",
apiConfiguration: { ...configuration, openAiCodexUseWebSocket: !enabled },
})
},
)

it("keeps OpenAI-compatible reasoning edits cached until Save despite a live state refresh", async () => {
const configuration: ProviderSettings = {
apiProvider: providerIdentifiers.openai,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { vscode } from "@src/utils/vscode"
import { ModelPicker } from "../ModelPicker"
import { OpenAICodexRateLimitDashboard } from "./OpenAICodexRateLimitDashboard"
import { OpenAICodexSpeedSelector } from "./OpenAICodexSpeedSelector"
import { OpenAICodexWebSocketToggle } from "./OpenAICodexWebSocketToggle"

interface OpenAICodexProps {
apiConfiguration: ProviderSettings
Expand Down Expand Up @@ -77,6 +78,10 @@ export const OpenAICodex: React.FC<OpenAICodexProps> = ({
value={apiConfiguration[OPEN_AI_CODEX_SERVICE_TIER_KEY]}
onValueChange={(value) => setApiConfigurationField(OPEN_AI_CODEX_SERVICE_TIER_KEY, value)}
/>
<OpenAICodexWebSocketToggle
value={apiConfiguration.openAiCodexUseWebSocket}
onChange={(value) => setApiConfigurationField("openAiCodexUseWebSocket", value)}
/>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Checkbox } from "vscrui"
import { DEFAULT_OPEN_AI_CODEX_USE_WEBSOCKET } from "@roo-code/types"

import { useAppTranslation } from "@src/i18n/TranslationContext"

interface OpenAICodexWebSocketToggleProps {
value?: boolean
onChange: (enabled: boolean) => void
}

export function OpenAICodexWebSocketToggle({ value, onChange }: OpenAICodexWebSocketToggleProps) {
const { t } = useAppTranslation()
return (
<div className="flex flex-col gap-1" data-testid="openai-codex-websocket">
<Checkbox
checked={value ?? DEFAULT_OPEN_AI_CODEX_USE_WEBSOCKET}
onChange={(checked) => onChange(checked === true)}>
{t("settings:openAiCodexWebSocket.label")}
</Checkbox>
<p className="m-0 text-sm text-vscode-descriptionForeground">
{t("settings:openAiCodexWebSocket.description")}
</p>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ vi.mock("@src/i18n/TranslationContext", () => ({
t: (key: string) =>
({
"settings:openAiCodexSpeed.label": "Speed",
"settings:openAiCodexWebSocket.label": "Use WebSocket",
"settings:openAiCodexSpeed.tooltip":
"Fast uses Codex priority processing for about 1.5x speed and consumes more subscription quota.",
"settings:openAiCodexSpeed.standard": "Standard",
Expand Down Expand Up @@ -95,3 +96,26 @@ describe("OpenAICodex speed selector", () => {
expect(postMessage).not.toHaveBeenCalled()
})
})

describe("OpenAICodex WebSocket preference", () => {
it.each([undefined, false, true])(
"renders saved preference %s and edits through the cached settings callback",
(enabled) => {
const setApiConfigurationField = vi.fn()
const configuration: ProviderSettings = {
apiProvider: providerIdentifiers.openaiCodex,
openAiCodexUseWebSocket: enabled,
}
render(<OpenAICodex apiConfiguration={configuration} setApiConfigurationField={setApiConfigurationField} />)
const checkbox = screen.getByRole("checkbox", { name: "Use WebSocket" })
if (enabled) expect(checkbox).toBeChecked()
else expect(checkbox).not.toBeChecked()
fireEvent.click(checkbox)
expect(setApiConfigurationField).toHaveBeenLastCalledWith("openAiCodexUseWebSocket", !enabled)
expect(configuration.openAiCodexUseWebSocket).toBe(enabled)
expect(vscode.postMessage).not.toHaveBeenCalledWith(
expect.objectContaining({ type: "upsertApiConfiguration" }),
)
},
)
})
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,13 @@ import { OpenAiCodexServiceTier } from "@roo-code/types/model"
import { TranslationContext } from "@src/i18n/TranslationContext"
import { TooltipProvider } from "@src/components/ui/tooltip"
import { OpenAICodexSpeedSelector } from "../OpenAICodexSpeedSelector"
import { OpenAICodexWebSocketToggle } from "../OpenAICodexWebSocketToggle"

const translations: Record<string, string> = {
"settings:common.select": "Select",
"settings:openAiCodexWebSocket.label": "Use WebSocket",
"settings:openAiCodexWebSocket.description":
"Keeps the ChatGPT connection open between requests. Uses HTTP if a WebSocket connection cannot be established.",
"settings:openAiCodexSpeed.label": "Speed",
"settings:openAiCodexSpeed.tooltip":
"Fast uses Codex priority processing for about 1.5x speed and consumes more subscription quota.",
Expand All @@ -25,7 +29,9 @@ export const OpenAICodexFixture = () => (
<TooltipProvider>
<div className="flex w-[480px] flex-col gap-4 bg-vscode-editor-background p-4 text-vscode-foreground">
<OpenAICodexSpeedSelector value={OpenAiCodexServiceTier.Default} onValueChange={() => {}} />
<OpenAICodexWebSocketToggle value={false} onChange={() => {}} />
<OpenAICodexSpeedSelector value={OpenAiCodexServiceTier.Priority} onValueChange={() => {}} />
<OpenAICodexWebSocketToggle value={true} onChange={() => {}} />
</div>
</TooltipProvider>
</TranslationContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@
] as const

for (const theme of themes) {
test(`renders both OpenAI Codex speeds in the VS Code ${theme.name} theme`, async ({ mount }) => {
test(`renders OpenAI Codex speed and WebSocket preferences in the VS Code ${theme.name} theme`, async ({
mount,
}) => {
const component = mountedStory(await mount("openai-codex"))

Check failure on line 27 in webview-ui/src/components/settings/providers/__tests__/OpenAICodex.visual.tsx

View workflow job for this annotation

GitHub Actions / webview-visual

[chromium] › src/components/settings/providers/__tests__/OpenAICodex.visual.tsx:24:2 › renders OpenAI Codex speed and WebSocket preferences in the VS Code dark theme

10) [chromium] › src/components/settings/providers/__tests__/OpenAICodex.visual.tsx:24:2 › renders OpenAI Codex speed and WebSocket preferences in the VS Code dark theme Error: page.evaluate: SyntaxError: The requested module '/@fs/__w/Zoo-Code/Zoo-Code/packages/types/src/provider-settings/openai-codex.ts' does not provide an export named 'DEFAULT_OPEN_AI_CODEX_USE_WEBSOCKET' 25 | mount, 26 | }) => { > 27 | const component = mountedStory(await mount("openai-codex")) | ^ 28 | const selectors = component.getByTestId("openai-codex-service-tier") 29 | const comboboxes = component.getByRole("combobox", { name: "Speed" }) 30 | const selector = selectors.first() at /__w/Zoo-Code/Zoo-Code/webview-ui/src/components/settings/providers/__tests__/OpenAICodex.visual.tsx:27:34
const selectors = component.getByTestId("openai-codex-service-tier")
const comboboxes = component.getByRole("combobox", { name: "Speed" })
const selector = selectors.first()

await expect(selectors).toHaveCount(2)
await expect(comboboxes).toHaveCount(2)
const checkboxes = component.getByRole("checkbox", { name: "Use WebSocket" })
await expect(checkboxes).toHaveCount(2)
await expect(checkboxes.first()).not.toBeChecked()
await expect(checkboxes.last()).toBeChecked()
await selector.evaluate((element, { bodyClass, themeId }) => {
const { document } = element.ownerDocument.defaultView!

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/ca/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/de/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/en/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -1179,6 +1179,10 @@
"limitMaxTokensDescription": "Limit the maximum number of tokens in the response",
"maxOutputTokensLabel": "Max output tokens",
"maxTokensGenerateDescription": "Maximum tokens to generate in response",
"openAiCodexWebSocket": {
"label": "Use WebSocket",
"description": "Keeps the ChatGPT connection open between requests. Uses HTTP if a WebSocket connection cannot be established."
},
"openAiCodexSpeed": {
"label": "Speed",
"tooltip": "Fast uses Codex priority processing for about 1.5x speed and consumes more subscription quota.",
Expand Down
4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/es/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/fr/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/hi/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/id/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/it/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/ja/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/ko/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/nl/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/pl/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/pt-BR/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/ru/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/tr/settings.json

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

4 changes: 4 additions & 0 deletions webview-ui/src/i18n/locales/vi/settings.json

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

Loading
Loading