Skip to content

Commit cc6a3b8

Browse files
committed
feat(morph): add Morph Fast Apply settings and strategy selection
1 parent bbd3d98 commit cc6a3b8

File tree

5 files changed

+44
-7
lines changed

5 files changed

+44
-7
lines changed

packages/types/src/global-settings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export const SECRET_STATE_KEYS = [
205205
"fireworksApiKey",
206206
"featherlessApiKey",
207207
"ioIntelligenceApiKey",
208+
"morphApiKey",
208209
"vercelAiGatewayApiKey",
209210
] as const
210211

packages/types/src/provider-settings.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ const baseProviderSettingsSchema = z.object({
101101
diffEnabled: z.boolean().optional(),
102102
todoListEnabled: z.boolean().optional(),
103103
fuzzyMatchThreshold: z.number().optional(),
104+
// Morph Fast Apply - optional provider-scoped controls
105+
morphFastApplyEnabled: z.boolean().optional(),
106+
morphApiKey: z.string().optional(),
107+
104108
modelTemperature: z.number().nullish(),
105109
rateLimitSeconds: z.number().optional(),
106110
consecutiveMistakeLimit: z.number().min(0).optional(),

src/core/task/Task.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -394,17 +394,18 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
394394

395395
// Only set up diff strategy if diff is enabled.
396396
if (this.diffEnabled) {
397-
// Default to old strategy, will be updated if experiment is enabled.
397+
// Default to legacy single-file strategy
398398
this.diffStrategy = new MultiSearchReplaceDiffStrategy(this.fuzzyMatchThreshold)
399399

400-
// Check experiment asynchronously and update strategy if needed.
400+
// Prefer MultiFile when Morph Fast Apply is enabled, otherwise respect experiment flag.
401401
provider.getState().then((state) => {
402402
const isMultiFileApplyDiffEnabled = experiments.isEnabled(
403403
state.experiments ?? {},
404404
EXPERIMENT_IDS.MULTI_FILE_APPLY_DIFF,
405405
)
406+
const isMorphFastApplyEnabled = state.apiConfiguration?.morphFastApplyEnabled === true
406407

407-
if (isMultiFileApplyDiffEnabled) {
408+
if (isMorphFastApplyEnabled || isMultiFileApplyDiffEnabled) {
408409
this.diffStrategy = new MultiFileSearchReplaceDiffStrategy(this.fuzzyMatchThreshold)
409410
}
410411
})

src/core/webview/generateSystemPrompt.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,20 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
2727
maxConcurrentFileReads,
2828
} = await provider.getState()
2929

30-
// Check experiment to determine which diff strategy to use
30+
// Determine which diff strategy to use:
31+
// - If Morph Fast Apply is enabled, force MultiFile strategy for best tolerance and batching
32+
// - Otherwise, fall back to experiment flag to choose between MultiFile and single-file strategies
3133
const isMultiFileApplyDiffEnabled = experimentsModule.isEnabled(
3234
experiments ?? {},
3335
EXPERIMENT_IDS.MULTI_FILE_APPLY_DIFF,
3436
)
37+
const isMorphFastApplyEnabled = apiConfiguration?.morphFastApplyEnabled === true
3538

36-
const diffStrategy = isMultiFileApplyDiffEnabled
39+
const diffStrategy = isMorphFastApplyEnabled
3740
? new MultiFileSearchReplaceDiffStrategy(fuzzyMatchThreshold)
38-
: new MultiSearchReplaceDiffStrategy(fuzzyMatchThreshold)
41+
: isMultiFileApplyDiffEnabled
42+
? new MultiFileSearchReplaceDiffStrategy(fuzzyMatchThreshold)
43+
: new MultiSearchReplaceDiffStrategy(fuzzyMatchThreshold)
3944

4045
const cwd = provider.cwd
4146

webview-ui/src/components/settings/ApiOptions.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { memo, useCallback, useEffect, useMemo, useState } from "react"
22
import { convertHeadersToObject } from "./utils/headers"
33
import { useDebounce } from "react-use"
4-
import { VSCodeLink, VSCodeButton } from "@vscode/webview-ui-toolkit/react"
4+
import { VSCodeLink, VSCodeButton, VSCodeCheckbox, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
55
import { ExternalLinkIcon } from "@radix-ui/react-icons"
66

77
import {
@@ -765,6 +765,32 @@ const ApiOptions = ({
765765
fuzzyMatchThreshold={apiConfiguration.fuzzyMatchThreshold}
766766
onChange={(field, value) => setApiConfigurationField(field, value)}
767767
/>
768+
769+
{/* Morph Fast Apply - provider-scoped controls */}
770+
<div className="pl-3 border-l-2 border-vscode-button-background space-y-2">
771+
<label className="block font-medium">Morph Fast Apply</label>
772+
<div className="flex flex-col gap-1">
773+
<VSCodeCheckbox
774+
checked={Boolean(apiConfiguration.morphFastApplyEnabled)}
775+
onChange={(e: any) =>
776+
setApiConfigurationField("morphFastApplyEnabled", e.target.checked)
777+
}>
778+
Enable Morph Fast Apply (fuzzy multi-file)
779+
</VSCodeCheckbox>
780+
781+
<VSCodeTextField
782+
value={apiConfiguration?.morphApiKey || ""}
783+
type="password"
784+
onInput={(e: any) => setApiConfigurationField("morphApiKey", e.target.value)}
785+
placeholder="Optional API key">
786+
Morph API key (optional)
787+
</VSCodeTextField>
788+
<div className="text-sm text-vscode-descriptionForeground">
789+
When enabled, apply_diff uses faster tolerant matching across multiple files. An API
790+
key is only required if using a hosted Morph service.
791+
</div>
792+
</div>
793+
</div>
768794
{selectedModelInfo?.supportsTemperature !== false && (
769795
<TemperatureControl
770796
value={apiConfiguration.modelTemperature}

0 commit comments

Comments
 (0)