Skip to content
Merged
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
28 changes: 2 additions & 26 deletions src/core/webview/__tests__/ClineProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { ExtensionMessage, ExtensionState } from "../../../shared/ExtensionMessa
import { setSoundEnabled } from "../../../utils/sound"
import { defaultModeSlug } from "../../../shared/modes"
import { experimentDefault } from "../../../shared/experiments"
import { defaultExtensionState } from "../../../shared/ExtensionMessage"

// Mock setup must come before imports
jest.mock("../../prompts/sections/custom-instructions")
Expand Down Expand Up @@ -352,35 +353,10 @@ describe("ClineProvider", () => {
await provider.resolveWebviewView(mockWebviewView)

const mockState: ExtensionState = {
version: "1.0.0",
preferredLanguage: "English",
clineMessages: [],
taskHistory: [],
shouldShowAnnouncement: false,
...defaultExtensionState,
apiConfiguration: {
apiProvider: "openrouter",
},
customInstructions: undefined,
alwaysAllowReadOnly: false,
alwaysAllowWrite: false,
alwaysAllowExecute: false,
alwaysAllowBrowser: false,
alwaysAllowMcp: false,
uriScheme: "vscode",
soundEnabled: false,
diffEnabled: false,
checkpointsEnabled: false,
writeDelayMs: 1000,
browserViewportSize: "900x600",
fuzzyMatchThreshold: 1.0,
mcpEnabled: true,
enableMcpServerCreation: false,
requestDelaySeconds: 5,
rateLimitSeconds: 0,
mode: defaultModeSlug,
customModes: [],
experiments: experimentDefault,
maxOpenTabsContext: 20,
}

const message: ExtensionMessage = {
Expand Down
46 changes: 45 additions & 1 deletion src/shared/ExtensionMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { McpServer } from "./mcp"
import { GitCommit } from "../utils/git"
import { Mode, CustomModePrompts, ModeConfig } from "./modes"
import { CustomSupportPrompts } from "./support-prompt"
import { ExperimentId } from "./experiments"
import { ExperimentId, experimentDefault } from "./experiments"

export interface LanguageModelChatSelector {
vendor?: string
Expand Down Expand Up @@ -86,6 +86,11 @@ export interface ApiConfigMeta {
}

export interface ExtensionState {
glamaModels?: Record<string, ModelInfo>
requestyModels?: Record<string, ModelInfo>
openRouterModels?: Record<string, ModelInfo>
unboundModels?: Record<string, ModelInfo>
openAiModels?: string[]
version: string
clineMessages: ClineMessage[]
taskHistory: HistoryItem[]
Expand Down Expand Up @@ -240,3 +245,42 @@ export interface ClineApiReqInfo {
}

export type ClineApiReqCancelReason = "streaming_failed" | "user_cancelled"

export const defaultExtensionState: ExtensionState = {
version: "1.0.0",
clineMessages: [],
taskHistory: [],
shouldShowAnnouncement: false,
allowedCommands: [],
soundEnabled: false,
soundVolume: 0.5,
diffEnabled: false,
checkpointsEnabled: false,
fuzzyMatchThreshold: 1.0,
preferredLanguage: "English",
writeDelayMs: 1000,
browserViewportSize: "900x600",
screenshotQuality: 75,
terminalOutputLineLimit: 500,
mcpEnabled: true,
enableMcpServerCreation: true,
alwaysApproveResubmit: false,
requestDelaySeconds: 5,
rateLimitSeconds: 0,
currentApiConfigName: "default",
listApiConfigMeta: [],
mode: "code",
customModePrompts: {},
customSupportPrompts: {},
experiments: experimentDefault,
enhancementApiConfigId: "",
autoApprovalEnabled: false,
customModes: [],
maxOpenTabsContext: 20,
cwd: "",
glamaModels: {},
requestyModels: {},
openRouterModels: {},
unboundModels: {},
openAiModels: [],
}
74 changes: 6 additions & 68 deletions webview-ui/.storybook/preview-context.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ExtensionStateContextType, ExtensionStateContext } from "../src/context/ExtensionStateContext"
import { defaultExtensionState } from "../../src/shared/ExtensionMessage"
import { McpServer } from "../../src/shared/mcp"
import { ApiConfiguration, ModelInfo } from "../../src/shared/api"
import { HistoryItem } from "../../src/shared/HistoryItem" // Import HistoryItem
Expand Down Expand Up @@ -51,79 +52,17 @@ const mockOpenedTabs: Array<{ label: string; isActive: boolean; path?: string }>
]

const defaultContext: ExtensionStateContextType = {
// Version and state
version: "1.0.0",
...defaultExtensionState,
// Override specific properties for testing
theme: {},
didHydrateState: true,
showWelcome: false,

// Messages and history
clineMessages: [],
taskHistory: [mockTaskHistoryItem],
shouldShowAnnouncement: false,

// API and models
apiConfiguration: mockApiConfig,
glamaModels: {},
requestyModels: {},
openRouterModels: {},
unboundModels: {},
openAiModels: [],

// MCP
mcpServers: [mockMcpServer],
mcpEnabled: true,
enableMcpServerCreation: true,

// Files and tabs
taskHistory: [mockTaskHistoryItem],
filePaths: mockFilePaths,
openedTabs: mockOpenedTabs,
currentCheckpoint: undefined,

// Settings
mode: "code",
preferredLanguage: "English",
requestDelaySeconds: 0,
rateLimitSeconds: 0,
writeDelayMs: 0,
browserViewportSize: "1200x800",
screenshotQuality: 75,
terminalOutputLineLimit: 500,
fuzzyMatchThreshold: 1.0,
maxOpenTabsContext: 20,

// Features
diffEnabled: false,
checkpointsEnabled: false,
soundEnabled: false,
soundVolume: 0.5,
autoApprovalEnabled: true,

// Permissions
alwaysAllowBrowser: true,
alwaysAllowExecute: true,
alwaysAllowMcp: true,
alwaysAllowModeSwitch: true,
alwaysAllowReadOnly: true,
alwaysApproveResubmit: true,
alwaysAllowWrite: true,
allowedCommands: [],

// Other state
customModePrompts: {},
customSupportPrompts: {},
experiments: {
experimentalDiffStrategy: false,
search_and_replace: false,
insert_content: false,
powerSteering: false,
},
customModes: [],
enhancementApiConfigId: undefined,
currentApiConfigName: "default",
listApiConfigMeta: [],
theme: {},

// Setters
// Add setter functions
setApiConfiguration: () => {},
setCustomInstructions: () => {},
setAlwaysAllowReadOnly: () => {},
Expand Down Expand Up @@ -151,7 +90,6 @@ const defaultContext: ExtensionStateContextType = {
setRateLimitSeconds: () => {},
setCurrentApiConfigName: () => {},
setListApiConfigMeta: () => {},
onUpdateApiConfig: () => {},
setMode: () => {},
setCustomModePrompts: () => {},
setCustomSupportPrompts: () => {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react"
import { render, waitFor } from "@testing-library/react"
import ChatView from "../ChatView"
import { ExtensionStateContextProvider } from "../../../context/ExtensionStateContext"
import { defaultExtensionState } from "../../../../../src/shared/ExtensionMessage"
import { vscode } from "../../../utils/vscode"

// Mock vscode API
Expand Down Expand Up @@ -71,13 +72,7 @@ const mockPostMessage = (state: any) => {
{
type: "state",
state: {
version: "1.0.0",
clineMessages: [],
taskHistory: [],
shouldShowAnnouncement: false,
allowedCommands: [],
alwaysAllowExecute: false,
autoApprovalEnabled: true,
...defaultExtensionState,
...state,
},
},
Expand Down
8 changes: 2 additions & 6 deletions webview-ui/src/components/chat/__tests__/ChatView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from "react"
import { render, waitFor } from "@testing-library/react"
import ChatView from "../ChatView"
import { ExtensionStateContextProvider } from "../../../context/ExtensionStateContext"
import { defaultExtensionState } from "../../../../../src/shared/ExtensionMessage"
import { vscode } from "../../../utils/vscode"

// Define minimal types needed for testing
Expand Down Expand Up @@ -130,12 +131,7 @@ const mockPostMessage = (state: Partial<ExtensionState>) => {
{
type: "state",
state: {
version: "1.0.0",
clineMessages: [],
taskHistory: [],
shouldShowAnnouncement: false,
allowedCommands: [],
alwaysAllowExecute: false,
...defaultExtensionState,
...state,
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { render, screen, fireEvent } from "@testing-library/react"
import SettingsView from "../SettingsView"
import { ExtensionStateContextProvider } from "../../../context/ExtensionStateContext"
import { defaultExtensionState } from "../../../../../src/shared/ExtensionMessage"
import { vscode } from "../../../utils/vscode"

// Mock vscode API
Expand Down Expand Up @@ -82,14 +83,7 @@ const mockPostMessage = (state: any) => {
{
type: "state",
state: {
version: "1.0.0",
clineMessages: [],
taskHistory: [],
shouldShowAnnouncement: false,
allowedCommands: [],
alwaysAllowExecute: false,
soundEnabled: false,
soundVolume: 0.5,
...defaultExtensionState,
...state,
},
},
Expand Down
52 changes: 15 additions & 37 deletions webview-ui/src/context/ExtensionStateContext.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import React, { createContext, useCallback, useContext, useEffect, useState } from "react"
import { useEvent } from "react-use"
import { ApiConfigMeta, ExtensionMessage, ExtensionState } from "../../../src/shared/ExtensionMessage"
import { ApiConfiguration } from "../../../src/shared/api"
import {
ApiConfigMeta,
ExtensionMessage,
ExtensionState,
defaultExtensionState,
} from "../../../src/shared/ExtensionMessage"
import { ApiConfiguration, ModelInfo } from "../../../src/shared/api"
import { vscode } from "../utils/vscode"
import { convertTextMateToHljs } from "../utils/textMateToHljs"
import { findLastIndex } from "../../../src/shared/array"
import { McpServer } from "../../../src/shared/mcp"
import { checkExistKey } from "../../../src/shared/checkExistApiConfig"
import { Mode, CustomModePrompts, defaultModeSlug, defaultPrompts, ModeConfig } from "../../../src/shared/modes"
import { Mode, CustomModePrompts, ModeConfig } from "../../../src/shared/modes"
import { CustomSupportPrompts } from "../../../src/shared/support-prompt"
import { experimentDefault, ExperimentId } from "../../../src/shared/experiments"
import { ExperimentId } from "../../../src/shared/experiments"

export interface ExtensionStateContextType extends ExtensionState {
didHydrateState: boolean
Expand Down Expand Up @@ -58,6 +63,11 @@ export interface ExtensionStateContextType extends ExtensionState {
setMode: (value: Mode) => void
setCustomModePrompts: (value: CustomModePrompts) => void
setCustomSupportPrompts: (value: CustomSupportPrompts) => void
glamaModels?: Record<string, ModelInfo>
requestyModels?: Record<string, ModelInfo>
openRouterModels?: Record<string, ModelInfo>
unboundModels?: Record<string, ModelInfo>
openAiModels?: string[]
enhancementApiConfigId?: string
setEnhancementApiConfigId: (value: string) => void
setExperimentEnabled: (id: ExperimentId, enabled: boolean) => void
Expand All @@ -70,39 +80,7 @@ export interface ExtensionStateContextType extends ExtensionState {
export const ExtensionStateContext = createContext<ExtensionStateContextType | undefined>(undefined)

export const ExtensionStateContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [state, setState] = useState<ExtensionState>({
version: "",
clineMessages: [],
taskHistory: [],
shouldShowAnnouncement: false,
allowedCommands: [],
soundEnabled: false,
soundVolume: 0.5,
diffEnabled: false,
checkpointsEnabled: false,
fuzzyMatchThreshold: 1.0,
preferredLanguage: "English",
writeDelayMs: 1000,
browserViewportSize: "900x600",
screenshotQuality: 75,
terminalOutputLineLimit: 500,
mcpEnabled: true,
enableMcpServerCreation: true,
alwaysApproveResubmit: false,
requestDelaySeconds: 5,
rateLimitSeconds: 0, // Minimum time between successive requests (0 = disabled)
currentApiConfigName: "default",
listApiConfigMeta: [],
mode: defaultModeSlug,
customModePrompts: defaultPrompts,
customSupportPrompts: {},
experiments: experimentDefault,
enhancementApiConfigId: "",
autoApprovalEnabled: false,
customModes: [],
maxOpenTabsContext: 20,
cwd: "",
})
const [state, setState] = useState<ExtensionState>(defaultExtensionState)

const [didHydrateState, setDidHydrateState] = useState(false)
const [showWelcome, setShowWelcome] = useState(false)
Expand Down
Loading