Speculative new architecture for webview message handler

This commit is contained in:
slytechnical 2025-05-19 18:56:48 -05:00
parent 3053678903
commit bf4df46cc9
6 changed files with 98 additions and 42 deletions

View file

@ -0,0 +1,12 @@
import { ClineProvider } from "../ClineProvider"
import { WebviewMessage } from "../../../shared/WebviewMessage"
import { t } from "../../../i18n"
export async function handleClearTask(
provider: ClineProvider,
_message: WebviewMessage & { type: "clearTask" },
): Promise<void> {
// clear task resets the current session and allows for a new task to be started, if this session is a subtask - it allows the parent task to be resumed
await provider.finishSubTask(t("common:tasks.canceled"))
await provider.postStateToWebview()
}

View file

@ -0,0 +1,9 @@
import { ClineProvider } from "../ClineProvider"
import { WebviewMessage } from "../../../shared/WebviewMessage"
export async function handleCustomInstructions(
provider: ClineProvider,
message: WebviewMessage & { type: "customInstructions" },
): Promise<void> {
await provider.updateCustomInstructions(message.text)
}

View file

@ -0,0 +1,12 @@
import { ClineProvider } from "../ClineProvider"
import { WebviewMessage } from "../../../shared/WebviewMessage"
export async function handleNewTask(
provider: ClineProvider,
message: WebviewMessage & { type: "newTask" },
): Promise<void> {
// Initializing new instance of Cline will make sure that any
// agentically running promises in old instance don't affect our new
// task. This essentially creates a fresh slate for the new task.
await provider.initClineWithTask(message.text, message.images)
}

View file

@ -0,0 +1,11 @@
import { ClineProvider } from "../ClineProvider"
import { WebviewMessage } from "../../../shared/WebviewMessage"
import { selectImages } from "../../../integrations/misc/process-images"
export async function handleSelectImages(
provider: ClineProvider,
_message: WebviewMessage & { type: "selectImages" },
): Promise<void> {
const images = await selectImages()
await provider.postMessageToWebview({ type: "selectedImages", images })
}

View file

@ -0,0 +1,52 @@
import { ClineProvider } from "../ClineProvider"
import { WebviewMessage } from "../../../shared/WebviewMessage"
import { GetModelsOptions, ModelRecord, RouterName } from "../../../shared/api"
import { flushModels, getModels } from "../../../api/providers/fetchers/modelCache"
export async function handleRequestProviderModels(
provider: ClineProvider,
message: WebviewMessage & { type: "requestProviderModels" },
): Promise<void> {
const optionsFromPayload = message.payload as any // Check payload structure first
if (
typeof optionsFromPayload !== "object" ||
optionsFromPayload === null ||
typeof optionsFromPayload.provider !== "string" ||
!optionsFromPayload.provider
) {
const providerNameForError =
typeof optionsFromPayload?.provider === "string" && optionsFromPayload.provider
? (optionsFromPayload.provider as RouterName)
: ("unknown" as RouterName)
provider.postMessageToWebview({
type: "providerModelsResponse",
payload: {
provider: providerNameForError,
error: "Invalid payload for requestProviderModels: payload must be an object with a valid 'provider' string property.",
},
})
return
}
const options = optionsFromPayload as GetModelsOptions // Now cast to GetModelsOptions
let models: ModelRecord = {}
let error: string | undefined
try {
await flushModels(options.provider)
models = await getModels(options)
} catch (e: any) {
error =
e.message ||
`Failed to fetch models in webviewMessageHandler requestProviderModels for ${options.provider}. Check console for details.`
models = {}
}
provider.postMessageToWebview({
type: "providerModelsResponse",
payload: { provider: options.provider, models, error },
})
}

View file

@ -37,6 +37,7 @@ import { GlobalState } from "../../schemas"
import { flushModels, getModels } from "../../api/providers/fetchers/modelCache"
import { GetModelsOptions } from "../../shared/api"
import { generateSystemPrompt } from "./generateSystemPrompt"
import { handleRequestProviderModels } from "./messageHandlers/requestProviderModelsHandler"
const ALLOWED_VSCODE_SETTINGS = new Set(["terminal.integrated.inheritEnv"])
@ -278,48 +279,7 @@ export const webviewMessageHandler = async (provider: ClineProvider, message: We
await flushModels(routerNameFlush)
break
case "requestProviderModels": {
const optionsFromPayload = message.payload as any // Check payload structure first
if (
typeof optionsFromPayload !== "object" ||
optionsFromPayload === null ||
typeof optionsFromPayload.provider !== "string" ||
!optionsFromPayload.provider
) {
const providerNameForError =
typeof optionsFromPayload?.provider === "string" && optionsFromPayload.provider
? (optionsFromPayload.provider as RouterName)
: ("unknown" as RouterName)
provider.postMessageToWebview({
type: "providerModelsResponse",
payload: {
provider: providerNameForError,
error: "Invalid payload for requestProviderModels: payload must be an object with a valid 'provider' string property.",
},
})
break
}
const options = optionsFromPayload as GetModelsOptions // Now cast to GetModelsOptions
let models: ModelRecord = {}
let error: string | undefined
try {
await flushModels(options.provider)
models = await getModels(options)
} catch (e: any) {
error =
e.message ||
`Failed to fetch models in webviewMessageHandler requestProviderModels for ${options.provider}. Check console for details.`
models = {}
}
provider.postMessageToWebview({
type: "providerModelsResponse",
payload: { provider: options.provider, models, error },
})
await handleRequestProviderModels(provider, message as WebviewMessage & { type: "requestProviderModels" })
break
}
case "requestRouterModels":