@morphllm/morphsdk 0.2.112 → 0.2.114
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-EQHP36A2.js → chunk-3U7AWFBN.js} +5 -5
- package/dist/{chunk-2MAUPERG.js → chunk-FXBT4UDY.js} +19 -34
- package/dist/chunk-FXBT4UDY.js.map +1 -0
- package/dist/{chunk-HDRLLCAD.js → chunk-HMAX2FEE.js} +2 -2
- package/dist/{chunk-TLC3QKE6.js → chunk-M5DR2WOZ.js} +4 -3
- package/dist/{chunk-TLC3QKE6.js.map → chunk-M5DR2WOZ.js.map} +1 -1
- package/dist/{chunk-I3IN742Q.js → chunk-UNHHRMU7.js} +2 -2
- package/dist/{chunk-KQP6ZPYB.js → chunk-Y5BB7JFH.js} +2 -2
- package/dist/client.cjs +99 -123
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +6 -6
- package/dist/edge.cjs +102 -104
- package/dist/edge.cjs.map +1 -1
- package/dist/edge.js +1 -1
- package/dist/index.cjs +99 -123
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +6 -6
- package/dist/tools/fastapply/anthropic.cjs +22 -112
- package/dist/tools/fastapply/anthropic.cjs.map +1 -1
- package/dist/tools/fastapply/anthropic.js +3 -4
- package/dist/tools/fastapply/apply.cjs +28 -104
- package/dist/tools/fastapply/apply.cjs.map +1 -1
- package/dist/tools/fastapply/apply.d.ts +7 -3
- package/dist/tools/fastapply/apply.js +1 -2
- package/dist/tools/fastapply/core.cjs +22 -112
- package/dist/tools/fastapply/core.cjs.map +1 -1
- package/dist/tools/fastapply/core.js +2 -3
- package/dist/tools/fastapply/index.cjs +22 -112
- package/dist/tools/fastapply/index.cjs.map +1 -1
- package/dist/tools/fastapply/index.js +5 -6
- package/dist/tools/fastapply/openai.cjs +22 -112
- package/dist/tools/fastapply/openai.cjs.map +1 -1
- package/dist/tools/fastapply/openai.js +3 -4
- package/dist/tools/fastapply/types.cjs.map +1 -1
- package/dist/tools/fastapply/types.d.ts +5 -0
- package/dist/tools/fastapply/vercel.cjs +22 -112
- package/dist/tools/fastapply/vercel.cjs.map +1 -1
- package/dist/tools/fastapply/vercel.js +3 -4
- package/dist/tools/index.cjs +22 -112
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +5 -6
- package/package.json +1 -1
- package/dist/chunk-2MAUPERG.js.map +0 -1
- /package/dist/{chunk-EQHP36A2.js.map → chunk-3U7AWFBN.js.map} +0 -0
- /package/dist/{chunk-HDRLLCAD.js.map → chunk-HMAX2FEE.js.map} +0 -0
- /package/dist/{chunk-I3IN742Q.js.map → chunk-UNHHRMU7.js.map} +0 -0
- /package/dist/{chunk-KQP6ZPYB.js.map → chunk-Y5BB7JFH.js.map} +0 -0
|
@@ -30,86 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
-
// tools/utils/resilience.ts
|
|
34
|
-
async function fetchWithRetry(url, options, retryConfig = {}) {
|
|
35
|
-
const {
|
|
36
|
-
maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
|
|
37
|
-
initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
|
|
38
|
-
maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
|
|
39
|
-
backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
|
|
40
|
-
retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,
|
|
41
|
-
onRetry
|
|
42
|
-
} = retryConfig;
|
|
43
|
-
let lastError = null;
|
|
44
|
-
let delay = initialDelay;
|
|
45
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
46
|
-
try {
|
|
47
|
-
const response = await fetch(url, options);
|
|
48
|
-
if (response.status === 429 || response.status === 503) {
|
|
49
|
-
if (attempt < maxRetries) {
|
|
50
|
-
const retryAfter = response.headers.get("Retry-After");
|
|
51
|
-
const waitTime = retryAfter ? parseInt(retryAfter) * 1e3 : Math.min(delay, maxDelay);
|
|
52
|
-
const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);
|
|
53
|
-
if (onRetry) {
|
|
54
|
-
onRetry(attempt + 1, error);
|
|
55
|
-
}
|
|
56
|
-
await sleep(waitTime);
|
|
57
|
-
delay *= backoffMultiplier;
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return response;
|
|
62
|
-
} catch (error) {
|
|
63
|
-
lastError = error;
|
|
64
|
-
const isRetryable = retryableErrors.some(
|
|
65
|
-
(errType) => lastError?.message?.includes(errType)
|
|
66
|
-
);
|
|
67
|
-
if (!isRetryable || attempt === maxRetries) {
|
|
68
|
-
throw lastError;
|
|
69
|
-
}
|
|
70
|
-
const waitTime = Math.min(delay, maxDelay);
|
|
71
|
-
if (onRetry) {
|
|
72
|
-
onRetry(attempt + 1, lastError);
|
|
73
|
-
}
|
|
74
|
-
await sleep(waitTime);
|
|
75
|
-
delay *= backoffMultiplier;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
throw lastError || new Error("Max retries exceeded");
|
|
79
|
-
}
|
|
80
|
-
async function withTimeout(promise, timeoutMs, errorMessage) {
|
|
81
|
-
let timeoutId;
|
|
82
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
83
|
-
timeoutId = setTimeout(() => {
|
|
84
|
-
reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));
|
|
85
|
-
}, timeoutMs);
|
|
86
|
-
});
|
|
87
|
-
try {
|
|
88
|
-
const result = await Promise.race([promise, timeoutPromise]);
|
|
89
|
-
clearTimeout(timeoutId);
|
|
90
|
-
return result;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
clearTimeout(timeoutId);
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function sleep(ms) {
|
|
97
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
98
|
-
}
|
|
99
|
-
var DEFAULT_RETRY_CONFIG;
|
|
100
|
-
var init_resilience = __esm({
|
|
101
|
-
"tools/utils/resilience.ts"() {
|
|
102
|
-
"use strict";
|
|
103
|
-
DEFAULT_RETRY_CONFIG = {
|
|
104
|
-
maxRetries: 3,
|
|
105
|
-
initialDelay: 1e3,
|
|
106
|
-
maxDelay: 3e4,
|
|
107
|
-
backoffMultiplier: 2,
|
|
108
|
-
retryableErrors: ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND"]
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
33
|
// tools/fastapply/apply.ts
|
|
114
34
|
var apply_exports = {};
|
|
115
35
|
__export(apply_exports, {
|
|
@@ -166,37 +86,25 @@ async function callMorphAPI(originalCode, codeEdit, instructions, filepath, conf
|
|
|
166
86
|
console.log(`[FastApply] Original: ${originalCode.length} chars, Edit: ${codeEdit.length} chars`);
|
|
167
87
|
}
|
|
168
88
|
const startTime = Date.now();
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
{
|
|
172
|
-
method: "POST",
|
|
173
|
-
headers: {
|
|
174
|
-
"Content-Type": "application/json",
|
|
175
|
-
"Authorization": `Bearer ${apiKey}`
|
|
176
|
-
},
|
|
177
|
-
body: JSON.stringify({
|
|
178
|
-
model: "morph-v3-fast",
|
|
179
|
-
messages: [{ role: "user", content: message }]
|
|
180
|
-
})
|
|
181
|
-
},
|
|
182
|
-
config.retryConfig
|
|
183
|
-
);
|
|
184
|
-
const response = await withTimeout(
|
|
185
|
-
fetchPromise,
|
|
89
|
+
const client = new import_openai.default({
|
|
90
|
+
apiKey,
|
|
91
|
+
baseURL: `${apiUrl}/v1`,
|
|
186
92
|
timeout,
|
|
187
|
-
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
93
|
+
maxRetries: config.retryConfig?.maxRetries ?? 3
|
|
94
|
+
});
|
|
95
|
+
const completion = await client.chat.completions.create({
|
|
96
|
+
model: "morph-v3-fast",
|
|
97
|
+
messages: [{ role: "user", content: message }]
|
|
98
|
+
});
|
|
99
|
+
const content = completion.choices[0]?.message?.content;
|
|
100
|
+
if (!content) {
|
|
101
|
+
throw new Error("Morph API returned empty response");
|
|
193
102
|
}
|
|
194
|
-
const data = await response.json();
|
|
195
103
|
const elapsed = Date.now() - startTime;
|
|
196
104
|
if (debug) {
|
|
197
|
-
console.log(`[FastApply]
|
|
105
|
+
console.log(`[FastApply] Success in ${elapsed}ms, merged: ${content.length} chars`);
|
|
198
106
|
}
|
|
199
|
-
return
|
|
107
|
+
return { content, completionId: completion.id };
|
|
200
108
|
}
|
|
201
109
|
async function applyEdit(input, config = {}) {
|
|
202
110
|
const debug = config.debug || false;
|
|
@@ -205,7 +113,7 @@ async function applyEdit(input, config = {}) {
|
|
|
205
113
|
if (debug) {
|
|
206
114
|
console.log(`[FastApply] Applying edit to code (${input.originalCode.length} chars)`);
|
|
207
115
|
}
|
|
208
|
-
const mergedCode = await callMorphAPI(
|
|
116
|
+
const { content: mergedCode, completionId } = await callMorphAPI(
|
|
209
117
|
input.originalCode,
|
|
210
118
|
input.codeEdit,
|
|
211
119
|
input.instructions,
|
|
@@ -218,7 +126,8 @@ async function applyEdit(input, config = {}) {
|
|
|
218
126
|
success: true,
|
|
219
127
|
mergedCode,
|
|
220
128
|
udiff,
|
|
221
|
-
changes
|
|
129
|
+
changes,
|
|
130
|
+
completionId
|
|
222
131
|
};
|
|
223
132
|
} catch (error) {
|
|
224
133
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -230,12 +139,12 @@ async function applyEdit(input, config = {}) {
|
|
|
230
139
|
};
|
|
231
140
|
}
|
|
232
141
|
}
|
|
233
|
-
var import_diff, DEFAULT_API_URL, DEFAULT_TIMEOUT;
|
|
142
|
+
var import_diff, import_openai, DEFAULT_API_URL, DEFAULT_TIMEOUT;
|
|
234
143
|
var init_apply = __esm({
|
|
235
144
|
"tools/fastapply/apply.ts"() {
|
|
236
145
|
"use strict";
|
|
237
146
|
import_diff = require("diff");
|
|
238
|
-
|
|
147
|
+
import_openai = __toESM(require("openai"), 1);
|
|
239
148
|
DEFAULT_API_URL = "https://api.morphllm.com";
|
|
240
149
|
DEFAULT_TIMEOUT = 3e4;
|
|
241
150
|
}
|
|
@@ -336,7 +245,7 @@ async function executeEditFile(input, config = {}) {
|
|
|
336
245
|
}
|
|
337
246
|
if (debug) console.log(`[FastApply] File doesn't exist, will create new file`);
|
|
338
247
|
}
|
|
339
|
-
const mergedCode = await callMorphAPI2(originalCode, input.code_edit, input.instructions, input.target_filepath, config);
|
|
248
|
+
const { content: mergedCode, completionId } = await callMorphAPI2(originalCode, input.code_edit, input.instructions, input.target_filepath, config);
|
|
340
249
|
const udiff = config.generateUdiff !== false ? generateUdiff2(originalCode, mergedCode, input.target_filepath) : void 0;
|
|
341
250
|
if (config.autoWrite !== false) {
|
|
342
251
|
await writeFile(fullPath, mergedCode, "utf-8");
|
|
@@ -347,7 +256,8 @@ async function executeEditFile(input, config = {}) {
|
|
|
347
256
|
success: true,
|
|
348
257
|
filepath: input.target_filepath,
|
|
349
258
|
udiff,
|
|
350
|
-
changes
|
|
259
|
+
changes,
|
|
260
|
+
completionId
|
|
351
261
|
};
|
|
352
262
|
} catch (error) {
|
|
353
263
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../tools/utils/resilience.ts","../../../tools/fastapply/apply.ts","../../../tools/fastapply/core.ts"],"sourcesContent":["/**\n * Resilience utilities for retry logic and timeout handling\n */\n\nexport interface RetryConfig {\n maxRetries?: number; // Default: 3\n initialDelay?: number; // Default: 1000ms\n maxDelay?: number; // Default: 30000ms\n backoffMultiplier?: number; // Default: 2\n retryableErrors?: string[]; // Default: ['ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND']\n onRetry?: (attempt: number, error: Error) => void;\n}\n\nconst DEFAULT_RETRY_CONFIG: Required<Omit<RetryConfig, 'onRetry'>> = {\n maxRetries: 3,\n initialDelay: 1000,\n maxDelay: 30000,\n backoffMultiplier: 2,\n retryableErrors: ['ECONNREFUSED', 'ETIMEDOUT', 'ENOTFOUND'],\n};\n\n/**\n * Retry a fetch request with exponential backoff\n * \n * @param url - Request URL\n * @param options - Fetch options\n * @param retryConfig - Retry configuration\n * @returns Response from fetch\n * \n * @example\n * ```typescript\n * const response = await fetchWithRetry(\n * 'https://api.example.com/data',\n * { method: 'POST', body: JSON.stringify(data) },\n * { maxRetries: 5, initialDelay: 500 }\n * );\n * ```\n */\nexport async function fetchWithRetry(\n url: string,\n options: RequestInit,\n retryConfig: RetryConfig = {}\n): Promise<Response> {\n const {\n maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,\n initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,\n maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,\n backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,\n retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,\n onRetry,\n } = retryConfig;\n\n let lastError: Error | null = null;\n let delay = initialDelay;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n const response = await fetch(url, options);\n \n // Retry on 429 (rate limit) or 503 (service unavailable)\n if (response.status === 429 || response.status === 503) {\n if (attempt < maxRetries) {\n // Check for Retry-After header\n const retryAfter = response.headers.get('Retry-After');\n const waitTime = retryAfter \n ? parseInt(retryAfter) * 1000 \n : Math.min(delay, maxDelay);\n \n const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);\n if (onRetry) {\n onRetry(attempt + 1, error);\n }\n \n await sleep(waitTime);\n delay *= backoffMultiplier;\n continue;\n }\n }\n\n return response;\n } catch (error) {\n lastError = error as Error;\n \n // Check if error is retryable\n const isRetryable = retryableErrors.some(errType => \n lastError?.message?.includes(errType)\n );\n\n if (!isRetryable || attempt === maxRetries) {\n throw lastError;\n }\n\n // Exponential backoff\n const waitTime = Math.min(delay, maxDelay);\n if (onRetry) {\n onRetry(attempt + 1, lastError);\n }\n \n await sleep(waitTime);\n delay *= backoffMultiplier;\n }\n }\n\n throw lastError || new Error('Max retries exceeded');\n}\n\n/**\n * Add timeout to any promise\n * \n * @param promise - Promise to wrap with timeout\n * @param timeoutMs - Timeout in milliseconds\n * @param errorMessage - Optional custom error message\n * @returns Promise that rejects if timeout is reached\n * \n * @example\n * ```typescript\n * const result = await withTimeout(\n * fetchData(),\n * 5000,\n * 'Data fetch timed out'\n * );\n * ```\n */\nexport async function withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n errorMessage?: string\n): Promise<T> {\n let timeoutId: NodeJS.Timeout | number;\n \n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n\n try {\n const result = await Promise.race([promise, timeoutPromise]);\n clearTimeout(timeoutId!);\n return result;\n } catch (error) {\n clearTimeout(timeoutId!);\n throw error;\n }\n}\n\n/**\n * Sleep for specified milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n}\n\n/**\n * Unified error type for all tools\n */\nexport class MorphError extends Error {\n constructor(\n message: string,\n public code: string,\n public statusCode?: number,\n public retryable: boolean = false\n ) {\n super(message);\n this.name = 'MorphError';\n }\n}\n\n\n","/**\n * Edge-compatible code application API\n *\n * This module has zero Node.js dependencies and works on:\n * - Cloudflare Workers\n * - Vercel Edge Functions\n * - Deno Deploy\n * - Browser environments\n *\n * For file-based operations, use executeEditFile from core.ts\n */\n\nimport { createTwoFilesPatch } from 'diff';\nimport { fetchWithRetry, withTimeout } from '../utils/resilience.js';\nimport type {\n EditChanges,\n MorphApplyResponse,\n ApplyEditInput,\n ApplyEditResult,\n ApplyEditConfig,\n} from './types.js';\n\nconst DEFAULT_API_URL = 'https://api.morphllm.com';\nconst DEFAULT_TIMEOUT = 30000;\n\n/**\n * Generate a unified diff between two strings\n */\nexport function generateUdiff(\n original: string,\n modified: string,\n filepath: string\n): string {\n return createTwoFilesPatch(\n filepath,\n filepath,\n original,\n modified,\n 'Original',\n 'Modified'\n );\n}\n\n/**\n * Count changes from a unified diff\n */\nexport function countChanges(original: string, modified: string): EditChanges {\n const diff = generateUdiff(original, modified, 'file');\n const lines = diff.split('\\n');\n\n let linesAdded = 0;\n let linesRemoved = 0;\n\n for (const line of lines) {\n if (line.startsWith('+') && !line.startsWith('+++')) {\n linesAdded++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n linesRemoved++;\n }\n }\n\n const linesModified = Math.min(linesAdded, linesRemoved);\n\n return {\n linesAdded: linesAdded - linesModified,\n linesRemoved: linesRemoved - linesModified,\n linesModified,\n };\n}\n\n/**\n * Call Morph Apply API to merge code edits\n * Uses OpenAI-compatible chat completions endpoint with XML-formatted message\n */\nexport async function callMorphAPI(\n originalCode: string,\n codeEdit: string,\n instructions: string,\n filepath: string,\n config: ApplyEditConfig\n): Promise<string> {\n const apiKey = config.morphApiKey || (typeof process !== 'undefined' ? process.env?.MORPH_API_KEY : undefined);\n const apiUrl = config.morphApiUrl || DEFAULT_API_URL;\n const timeout = config.timeout || DEFAULT_TIMEOUT;\n const debug = config.debug || false;\n\n if (!apiKey) {\n throw new Error(\n 'Morph API key not found. Set MORPH_API_KEY environment variable or pass morphApiKey in config.'\n );\n }\n\n // Format message with XML tags as per Morph Fast Apply spec\n const message = `<instruction>${instructions}</instruction>\\n<code>${originalCode}</code>\\n<update>${codeEdit}</update>`;\n\n if (debug) {\n console.log(`[FastApply] Calling ${apiUrl}/v1/chat/completions`);\n console.log(`[FastApply] File: ${filepath}, Instructions: ${instructions.slice(0, 60)}...`);\n console.log(`[FastApply] Original: ${originalCode.length} chars, Edit: ${codeEdit.length} chars`);\n }\n\n const startTime = Date.now();\n\n // Fetch with retry and timeout\n const fetchPromise = fetchWithRetry(\n `${apiUrl}/v1/chat/completions`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: 'morph-v3-fast',\n messages: [{ role: 'user', content: message }],\n }),\n },\n config.retryConfig\n );\n\n const response = await withTimeout(\n fetchPromise,\n timeout,\n `Morph API request timed out after ${timeout}ms`\n );\n\n if (!response.ok) {\n const error = await response.text();\n if (debug) console.error(`[FastApply] API error: ${response.status} - ${error}`);\n throw new Error(`Morph API error (${response.status}): ${error}`);\n }\n\n const data: MorphApplyResponse = await response.json();\n const elapsed = Date.now() - startTime;\n\n if (debug) {\n console.log(`[FastApply] ✅ Success in ${elapsed}ms, merged: ${data.choices[0].message.content.length} chars`);\n }\n\n return data.choices[0].message.content;\n}\n\n/**\n * Apply an edit to code directly without file I/O\n *\n * This is the edge-compatible code-in/code-out API that accepts code content directly\n * and returns the merged result without reading or writing any files.\n *\n * Works on Cloudflare Workers, Vercel Edge Functions, Deno, and browsers.\n *\n * @param input - Code and edit parameters\n * @param config - Optional configuration\n * @returns Result with merged code\n *\n * @example\n * ```typescript\n * import { applyEdit } from '@morphllm/morphsdk';\n *\n * const result = await applyEdit({\n * originalCode: fs.readFileSync('file.ts', 'utf-8'),\n * codeEdit: '// ... existing code ...\\nconst newVar = 42;\\n// ... existing code ...',\n * instructions: 'Add a new variable',\n * filepath: 'file.ts' // optional, for udiff context\n * });\n *\n * if (result.success) {\n * fs.writeFileSync('file.ts', result.mergedCode);\n * }\n * ```\n */\nexport async function applyEdit(\n input: ApplyEditInput,\n config: ApplyEditConfig = {}\n): Promise<ApplyEditResult> {\n const debug = config.debug || false;\n const filepath = input.filepath || 'file';\n\n try {\n if (debug) {\n console.log(`[FastApply] Applying edit to code (${input.originalCode.length} chars)`);\n }\n\n const mergedCode = await callMorphAPI(\n input.originalCode,\n input.codeEdit,\n input.instructions,\n filepath,\n config\n );\n\n const udiff = config.generateUdiff !== false\n ? generateUdiff(input.originalCode, mergedCode, filepath)\n : undefined;\n\n const changes = countChanges(input.originalCode, mergedCode);\n\n return {\n success: true,\n mergedCode,\n udiff,\n changes,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';\n if (debug) console.error(`[FastApply] Error: ${errorMessage}`);\n\n return {\n success: false,\n changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },\n error: errorMessage,\n };\n }\n}\n","/**\n * Core implementation of Morph Fast Apply\n *\n * This module provides file-based operations that require Node.js.\n * For edge-compatible code-in/code-out operations, use applyEdit from ./apply.ts\n */\n\nimport { join, resolve, relative } from 'path';\nimport type {\n EditFileInput,\n EditFileResult,\n EditFileConfig,\n} from './types.js';\n\n// Re-export edge-compatible functions\nexport { applyEdit, generateUdiff, countChanges, callMorphAPI } from './apply.js';\n\nconst DEFAULT_CONFIG: Required<Omit<EditFileConfig, 'morphApiKey' | 'systemPrompt' | 'retryConfig' | 'description'>> = {\n morphApiUrl: 'https://api.morphllm.com',\n baseDir: process.cwd(),\n generateUdiff: true,\n autoWrite: true,\n timeout: 30000,\n debug: false,\n};\n\n/**\n * FastApply client for programmatic file editing\n * Note: This client requires Node.js for file operations\n */\nexport class FastApplyClient {\n private config: EditFileConfig;\n\n constructor(config: { apiKey?: string; debug?: boolean; timeout?: number; retryConfig?: any } = {}) {\n this.config = {\n morphApiKey: config.apiKey,\n morphApiUrl: DEFAULT_CONFIG.morphApiUrl,\n debug: config.debug,\n timeout: config.timeout || DEFAULT_CONFIG.timeout,\n retryConfig: config.retryConfig,\n generateUdiff: DEFAULT_CONFIG.generateUdiff,\n autoWrite: DEFAULT_CONFIG.autoWrite,\n };\n }\n\n /**\n * Execute a file edit operation\n *\n * @param input - Edit parameters including filepath, instructions, and code_edit\n * @param overrides - Optional config overrides for this operation\n * @returns Edit result with success status and changes\n */\n async execute(input: EditFileInput, overrides?: Partial<EditFileConfig>): Promise<EditFileResult> {\n return executeEditFile(input, { ...this.config, ...overrides });\n }\n\n /**\n * Apply an edit to code directly without file I/O\n *\n * Useful for sandbox environments or when you manage your own file system.\n * Compatible with the earlier OpenAI client API contract.\n *\n * @param input - Code and edit parameters\n * @param overrides - Optional config overrides for this operation\n * @returns Result with merged code\n *\n * @example\n * ```typescript\n * const result = await client.applyEdit({\n * originalCode: 'function hello() { return \"world\"; }',\n * codeEdit: 'function hello() { return \"universe\"; }',\n * instructions: 'Change return value'\n * });\n * console.log(result.mergedCode);\n * ```\n */\n async applyEdit(input: import('./types.js').ApplyEditInput, overrides?: Partial<import('./types.js').ApplyEditConfig>): Promise<import('./types.js').ApplyEditResult> {\n const { applyEdit } = await import('./apply.js');\n return applyEdit(input, { ...this.config, ...overrides });\n }\n}\n\n/**\n * Execute a file edit using Morph Fast Apply\n * Note: This function requires Node.js for file I/O\n */\nexport async function executeEditFile(\n input: EditFileInput,\n config: EditFileConfig = {}\n): Promise<EditFileResult> {\n const baseDir = config.baseDir || DEFAULT_CONFIG.baseDir;\n const fullPath = resolve(join(baseDir, input.target_filepath));\n const debug = config.debug || false;\n\n // Security: ensure file is within baseDir\n const relativePath = relative(baseDir, fullPath);\n if (relativePath.startsWith('..') || fullPath === baseDir) {\n return {\n success: false,\n filepath: input.target_filepath,\n changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },\n error: `Invalid filepath: '${input.target_filepath}' is outside baseDir`,\n };\n }\n\n try {\n if (debug) console.log(`[FastApply] Reading file: ${input.target_filepath}`);\n\n // Dynamic import to avoid loading Node.js fs module at module evaluation time\n const { readFile, writeFile } = await import('fs/promises');\n const { callMorphAPI, generateUdiff, countChanges } = await import('./apply.js');\n\n // Handle both existing and non-existent files\n let originalCode = '';\n try {\n originalCode = await readFile(fullPath, 'utf-8');\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n throw error; // Re-throw if it's not a \"file not found\" error\n }\n // File doesn't exist, proceed with empty content (will create new file)\n if (debug) console.log(`[FastApply] File doesn't exist, will create new file`);\n }\n\n const mergedCode = await callMorphAPI(originalCode, input.code_edit, input.instructions, input.target_filepath, config);\n\n const udiff = config.generateUdiff !== false ? generateUdiff(originalCode, mergedCode, input.target_filepath) : undefined;\n\n if (config.autoWrite !== false) {\n await writeFile(fullPath, mergedCode, 'utf-8');\n if (debug) console.log(`[FastApply] Wrote ${mergedCode.length} chars to ${input.target_filepath}`);\n }\n\n const changes = countChanges(originalCode, mergedCode);\n\n return {\n success: true,\n filepath: input.target_filepath,\n udiff,\n changes,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';\n if (debug) console.error(`[FastApply] Error: ${errorMessage}`);\n\n return {\n success: false,\n filepath: input.target_filepath,\n changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },\n error: errorMessage,\n };\n }\n}\n"],"mappings":"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","names":["resolve","applyEdit","callMorphAPI","generateUdiff","countChanges"]}
|
|
1
|
+
{"version":3,"sources":["../../../tools/fastapply/apply.ts","../../../tools/fastapply/core.ts"],"sourcesContent":["/**\n * Edge-compatible code application API\n *\n * This module works on:\n * - Node.js\n * - Cloudflare Workers\n * - Vercel Edge Functions\n * - Deno Deploy\n * - Browser environments\n *\n * For file-based operations, use executeEditFile from core.ts\n */\n\nimport { createTwoFilesPatch } from 'diff';\nimport OpenAI from 'openai';\nimport type {\n EditChanges,\n ApplyEditInput,\n ApplyEditResult,\n ApplyEditConfig,\n} from './types.js';\n\nconst DEFAULT_API_URL = 'https://api.morphllm.com';\nconst DEFAULT_TIMEOUT = 30000;\n\n/**\n * Generate a unified diff between two strings\n */\nexport function generateUdiff(\n original: string,\n modified: string,\n filepath: string\n): string {\n return createTwoFilesPatch(\n filepath,\n filepath,\n original,\n modified,\n 'Original',\n 'Modified'\n );\n}\n\n/**\n * Count changes from a unified diff\n */\nexport function countChanges(original: string, modified: string): EditChanges {\n const diff = generateUdiff(original, modified, 'file');\n const lines = diff.split('\\n');\n\n let linesAdded = 0;\n let linesRemoved = 0;\n\n for (const line of lines) {\n if (line.startsWith('+') && !line.startsWith('+++')) {\n linesAdded++;\n } else if (line.startsWith('-') && !line.startsWith('---')) {\n linesRemoved++;\n }\n }\n\n const linesModified = Math.min(linesAdded, linesRemoved);\n\n return {\n linesAdded: linesAdded - linesModified,\n linesRemoved: linesRemoved - linesModified,\n linesModified,\n };\n}\n\n/**\n * Call Morph Apply API to merge code edits\n * Uses OpenAI SDK for reliable connection handling, retries, and timeouts\n */\nexport async function callMorphAPI(\n originalCode: string,\n codeEdit: string,\n instructions: string,\n filepath: string,\n config: ApplyEditConfig\n): Promise<{ content: string; completionId?: string }> {\n const apiKey = config.morphApiKey || (typeof process !== 'undefined' ? process.env?.MORPH_API_KEY : undefined);\n const apiUrl = config.morphApiUrl || DEFAULT_API_URL;\n const timeout = config.timeout || DEFAULT_TIMEOUT;\n const debug = config.debug || false;\n\n if (!apiKey) {\n throw new Error(\n 'Morph API key not found. Set MORPH_API_KEY environment variable or pass morphApiKey in config.'\n );\n }\n\n // Format message with XML tags as per Morph Fast Apply spec\n const message = `<instruction>${instructions}</instruction>\\n<code>${originalCode}</code>\\n<update>${codeEdit}</update>`;\n\n if (debug) {\n console.log(`[FastApply] Calling ${apiUrl}/v1/chat/completions`);\n console.log(`[FastApply] File: ${filepath}, Instructions: ${instructions.slice(0, 60)}...`);\n console.log(`[FastApply] Original: ${originalCode.length} chars, Edit: ${codeEdit.length} chars`);\n }\n\n const startTime = Date.now();\n\n const client = new OpenAI({\n apiKey,\n baseURL: `${apiUrl}/v1`,\n timeout,\n maxRetries: config.retryConfig?.maxRetries ?? 3,\n });\n\n const completion = await client.chat.completions.create({\n model: 'morph-v3-fast',\n messages: [{ role: 'user', content: message }],\n });\n\n const content = completion.choices[0]?.message?.content;\n if (!content) {\n throw new Error('Morph API returned empty response');\n }\n\n const elapsed = Date.now() - startTime;\n\n if (debug) {\n console.log(`[FastApply] Success in ${elapsed}ms, merged: ${content.length} chars`);\n }\n\n return { content, completionId: completion.id };\n}\n\n/**\n * Apply an edit to code directly without file I/O\n *\n * This is the edge-compatible code-in/code-out API that accepts code content directly\n * and returns the merged result without reading or writing any files.\n *\n * Works on Cloudflare Workers, Vercel Edge Functions, Deno, and browsers.\n *\n * @param input - Code and edit parameters\n * @param config - Optional configuration\n * @returns Result with merged code\n *\n * @example\n * ```typescript\n * import { applyEdit } from '@morphllm/morphsdk';\n *\n * const result = await applyEdit({\n * originalCode: fs.readFileSync('file.ts', 'utf-8'),\n * codeEdit: '// ... existing code ...\\nconst newVar = 42;\\n// ... existing code ...',\n * instructions: 'Add a new variable',\n * filepath: 'file.ts' // optional, for udiff context\n * });\n *\n * if (result.success) {\n * fs.writeFileSync('file.ts', result.mergedCode);\n * }\n * ```\n */\nexport async function applyEdit(\n input: ApplyEditInput,\n config: ApplyEditConfig = {}\n): Promise<ApplyEditResult> {\n const debug = config.debug || false;\n const filepath = input.filepath || 'file';\n\n try {\n if (debug) {\n console.log(`[FastApply] Applying edit to code (${input.originalCode.length} chars)`);\n }\n\n const { content: mergedCode, completionId } = await callMorphAPI(\n input.originalCode,\n input.codeEdit,\n input.instructions,\n filepath,\n config\n );\n\n const udiff = config.generateUdiff !== false\n ? generateUdiff(input.originalCode, mergedCode, filepath)\n : undefined;\n\n const changes = countChanges(input.originalCode, mergedCode);\n\n return {\n success: true,\n mergedCode,\n udiff,\n changes,\n completionId,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';\n if (debug) console.error(`[FastApply] Error: ${errorMessage}`);\n\n return {\n success: false,\n changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },\n error: errorMessage,\n };\n }\n}\n","/**\n * Core implementation of Morph Fast Apply\n *\n * This module provides file-based operations that require Node.js.\n * For edge-compatible code-in/code-out operations, use applyEdit from ./apply.ts\n */\n\nimport { join, resolve, relative } from 'path';\nimport type {\n EditFileInput,\n EditFileResult,\n EditFileConfig,\n} from './types.js';\n\n// Re-export edge-compatible functions\nexport { applyEdit, generateUdiff, countChanges, callMorphAPI } from './apply.js';\n\nconst DEFAULT_CONFIG: Required<Omit<EditFileConfig, 'morphApiKey' | 'systemPrompt' | 'retryConfig' | 'description'>> = {\n morphApiUrl: 'https://api.morphllm.com',\n baseDir: process.cwd(),\n generateUdiff: true,\n autoWrite: true,\n timeout: 30000,\n debug: false,\n};\n\n/**\n * FastApply client for programmatic file editing\n * Note: This client requires Node.js for file operations\n */\nexport class FastApplyClient {\n private config: EditFileConfig;\n\n constructor(config: { apiKey?: string; debug?: boolean; timeout?: number; retryConfig?: any } = {}) {\n this.config = {\n morphApiKey: config.apiKey,\n morphApiUrl: DEFAULT_CONFIG.morphApiUrl,\n debug: config.debug,\n timeout: config.timeout || DEFAULT_CONFIG.timeout,\n retryConfig: config.retryConfig,\n generateUdiff: DEFAULT_CONFIG.generateUdiff,\n autoWrite: DEFAULT_CONFIG.autoWrite,\n };\n }\n\n /**\n * Execute a file edit operation\n *\n * @param input - Edit parameters including filepath, instructions, and code_edit\n * @param overrides - Optional config overrides for this operation\n * @returns Edit result with success status and changes\n */\n async execute(input: EditFileInput, overrides?: Partial<EditFileConfig>): Promise<EditFileResult> {\n return executeEditFile(input, { ...this.config, ...overrides });\n }\n\n /**\n * Apply an edit to code directly without file I/O\n *\n * Useful for sandbox environments or when you manage your own file system.\n * Compatible with the earlier OpenAI client API contract.\n *\n * @param input - Code and edit parameters\n * @param overrides - Optional config overrides for this operation\n * @returns Result with merged code\n *\n * @example\n * ```typescript\n * const result = await client.applyEdit({\n * originalCode: 'function hello() { return \"world\"; }',\n * codeEdit: 'function hello() { return \"universe\"; }',\n * instructions: 'Change return value'\n * });\n * console.log(result.mergedCode);\n * ```\n */\n async applyEdit(input: import('./types.js').ApplyEditInput, overrides?: Partial<import('./types.js').ApplyEditConfig>): Promise<import('./types.js').ApplyEditResult> {\n const { applyEdit } = await import('./apply.js');\n return applyEdit(input, { ...this.config, ...overrides });\n }\n}\n\n/**\n * Execute a file edit using Morph Fast Apply\n * Note: This function requires Node.js for file I/O\n */\nexport async function executeEditFile(\n input: EditFileInput,\n config: EditFileConfig = {}\n): Promise<EditFileResult> {\n const baseDir = config.baseDir || DEFAULT_CONFIG.baseDir;\n const fullPath = resolve(join(baseDir, input.target_filepath));\n const debug = config.debug || false;\n\n // Security: ensure file is within baseDir\n const relativePath = relative(baseDir, fullPath);\n if (relativePath.startsWith('..') || fullPath === baseDir) {\n return {\n success: false,\n filepath: input.target_filepath,\n changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },\n error: `Invalid filepath: '${input.target_filepath}' is outside baseDir`,\n };\n }\n\n try {\n if (debug) console.log(`[FastApply] Reading file: ${input.target_filepath}`);\n\n // Dynamic import to avoid loading Node.js fs module at module evaluation time\n const { readFile, writeFile } = await import('fs/promises');\n const { callMorphAPI, generateUdiff, countChanges } = await import('./apply.js');\n\n // Handle both existing and non-existent files\n let originalCode = '';\n try {\n originalCode = await readFile(fullPath, 'utf-8');\n } catch (error: any) {\n if (error.code !== 'ENOENT') {\n throw error; // Re-throw if it's not a \"file not found\" error\n }\n // File doesn't exist, proceed with empty content (will create new file)\n if (debug) console.log(`[FastApply] File doesn't exist, will create new file`);\n }\n\n const { content: mergedCode, completionId } = await callMorphAPI(originalCode, input.code_edit, input.instructions, input.target_filepath, config);\n\n const udiff = config.generateUdiff !== false ? generateUdiff(originalCode, mergedCode, input.target_filepath) : undefined;\n\n if (config.autoWrite !== false) {\n await writeFile(fullPath, mergedCode, 'utf-8');\n if (debug) console.log(`[FastApply] Wrote ${mergedCode.length} chars to ${input.target_filepath}`);\n }\n\n const changes = countChanges(originalCode, mergedCode);\n\n return {\n success: true,\n filepath: input.target_filepath,\n udiff,\n changes,\n completionId,\n };\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';\n if (debug) console.error(`[FastApply] Error: ${errorMessage}`);\n\n return {\n success: false,\n filepath: input.target_filepath,\n changes: { linesAdded: 0, linesRemoved: 0, linesModified: 0 },\n error: errorMessage,\n };\n }\n}\n"],"mappings":"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","names":["OpenAI","applyEdit","callMorphAPI","generateUdiff","countChanges"]}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
FastApplyClient,
|
|
3
3
|
executeEditFile
|
|
4
|
-
} from "../../chunk-
|
|
4
|
+
} from "../../chunk-M5DR2WOZ.js";
|
|
5
5
|
import {
|
|
6
6
|
applyEdit,
|
|
7
7
|
callMorphAPI,
|
|
8
8
|
countChanges,
|
|
9
9
|
generateUdiff
|
|
10
|
-
} from "../../chunk-
|
|
11
|
-
import "../../chunk-4VWJFZVS.js";
|
|
10
|
+
} from "../../chunk-FXBT4UDY.js";
|
|
12
11
|
import "../../chunk-PZ5AY32C.js";
|
|
13
12
|
export {
|
|
14
13
|
FastApplyClient,
|
|
@@ -30,86 +30,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
-
// tools/utils/resilience.ts
|
|
34
|
-
async function fetchWithRetry(url, options, retryConfig = {}) {
|
|
35
|
-
const {
|
|
36
|
-
maxRetries = DEFAULT_RETRY_CONFIG.maxRetries,
|
|
37
|
-
initialDelay = DEFAULT_RETRY_CONFIG.initialDelay,
|
|
38
|
-
maxDelay = DEFAULT_RETRY_CONFIG.maxDelay,
|
|
39
|
-
backoffMultiplier = DEFAULT_RETRY_CONFIG.backoffMultiplier,
|
|
40
|
-
retryableErrors = DEFAULT_RETRY_CONFIG.retryableErrors,
|
|
41
|
-
onRetry
|
|
42
|
-
} = retryConfig;
|
|
43
|
-
let lastError = null;
|
|
44
|
-
let delay = initialDelay;
|
|
45
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
46
|
-
try {
|
|
47
|
-
const response = await fetch(url, options);
|
|
48
|
-
if (response.status === 429 || response.status === 503) {
|
|
49
|
-
if (attempt < maxRetries) {
|
|
50
|
-
const retryAfter = response.headers.get("Retry-After");
|
|
51
|
-
const waitTime = retryAfter ? parseInt(retryAfter) * 1e3 : Math.min(delay, maxDelay);
|
|
52
|
-
const error = new Error(`HTTP ${response.status}: Retrying after ${waitTime}ms`);
|
|
53
|
-
if (onRetry) {
|
|
54
|
-
onRetry(attempt + 1, error);
|
|
55
|
-
}
|
|
56
|
-
await sleep(waitTime);
|
|
57
|
-
delay *= backoffMultiplier;
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return response;
|
|
62
|
-
} catch (error) {
|
|
63
|
-
lastError = error;
|
|
64
|
-
const isRetryable = retryableErrors.some(
|
|
65
|
-
(errType) => lastError?.message?.includes(errType)
|
|
66
|
-
);
|
|
67
|
-
if (!isRetryable || attempt === maxRetries) {
|
|
68
|
-
throw lastError;
|
|
69
|
-
}
|
|
70
|
-
const waitTime = Math.min(delay, maxDelay);
|
|
71
|
-
if (onRetry) {
|
|
72
|
-
onRetry(attempt + 1, lastError);
|
|
73
|
-
}
|
|
74
|
-
await sleep(waitTime);
|
|
75
|
-
delay *= backoffMultiplier;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
throw lastError || new Error("Max retries exceeded");
|
|
79
|
-
}
|
|
80
|
-
async function withTimeout(promise, timeoutMs, errorMessage) {
|
|
81
|
-
let timeoutId;
|
|
82
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
83
|
-
timeoutId = setTimeout(() => {
|
|
84
|
-
reject(new Error(errorMessage || `Operation timed out after ${timeoutMs}ms`));
|
|
85
|
-
}, timeoutMs);
|
|
86
|
-
});
|
|
87
|
-
try {
|
|
88
|
-
const result = await Promise.race([promise, timeoutPromise]);
|
|
89
|
-
clearTimeout(timeoutId);
|
|
90
|
-
return result;
|
|
91
|
-
} catch (error) {
|
|
92
|
-
clearTimeout(timeoutId);
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
function sleep(ms) {
|
|
97
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
98
|
-
}
|
|
99
|
-
var DEFAULT_RETRY_CONFIG;
|
|
100
|
-
var init_resilience = __esm({
|
|
101
|
-
"tools/utils/resilience.ts"() {
|
|
102
|
-
"use strict";
|
|
103
|
-
DEFAULT_RETRY_CONFIG = {
|
|
104
|
-
maxRetries: 3,
|
|
105
|
-
initialDelay: 1e3,
|
|
106
|
-
maxDelay: 3e4,
|
|
107
|
-
backoffMultiplier: 2,
|
|
108
|
-
retryableErrors: ["ECONNREFUSED", "ETIMEDOUT", "ENOTFOUND"]
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
|
|
113
33
|
// tools/fastapply/apply.ts
|
|
114
34
|
var apply_exports = {};
|
|
115
35
|
__export(apply_exports, {
|
|
@@ -166,37 +86,25 @@ async function callMorphAPI(originalCode, codeEdit, instructions, filepath, conf
|
|
|
166
86
|
console.log(`[FastApply] Original: ${originalCode.length} chars, Edit: ${codeEdit.length} chars`);
|
|
167
87
|
}
|
|
168
88
|
const startTime = Date.now();
|
|
169
|
-
const
|
|
170
|
-
|
|
171
|
-
{
|
|
172
|
-
method: "POST",
|
|
173
|
-
headers: {
|
|
174
|
-
"Content-Type": "application/json",
|
|
175
|
-
"Authorization": `Bearer ${apiKey}`
|
|
176
|
-
},
|
|
177
|
-
body: JSON.stringify({
|
|
178
|
-
model: "morph-v3-fast",
|
|
179
|
-
messages: [{ role: "user", content: message }]
|
|
180
|
-
})
|
|
181
|
-
},
|
|
182
|
-
config.retryConfig
|
|
183
|
-
);
|
|
184
|
-
const response = await withTimeout(
|
|
185
|
-
fetchPromise,
|
|
89
|
+
const client = new import_openai.default({
|
|
90
|
+
apiKey,
|
|
91
|
+
baseURL: `${apiUrl}/v1`,
|
|
186
92
|
timeout,
|
|
187
|
-
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
93
|
+
maxRetries: config.retryConfig?.maxRetries ?? 3
|
|
94
|
+
});
|
|
95
|
+
const completion = await client.chat.completions.create({
|
|
96
|
+
model: "morph-v3-fast",
|
|
97
|
+
messages: [{ role: "user", content: message }]
|
|
98
|
+
});
|
|
99
|
+
const content = completion.choices[0]?.message?.content;
|
|
100
|
+
if (!content) {
|
|
101
|
+
throw new Error("Morph API returned empty response");
|
|
193
102
|
}
|
|
194
|
-
const data = await response.json();
|
|
195
103
|
const elapsed = Date.now() - startTime;
|
|
196
104
|
if (debug) {
|
|
197
|
-
console.log(`[FastApply]
|
|
105
|
+
console.log(`[FastApply] Success in ${elapsed}ms, merged: ${content.length} chars`);
|
|
198
106
|
}
|
|
199
|
-
return
|
|
107
|
+
return { content, completionId: completion.id };
|
|
200
108
|
}
|
|
201
109
|
async function applyEdit(input, config = {}) {
|
|
202
110
|
const debug = config.debug || false;
|
|
@@ -205,7 +113,7 @@ async function applyEdit(input, config = {}) {
|
|
|
205
113
|
if (debug) {
|
|
206
114
|
console.log(`[FastApply] Applying edit to code (${input.originalCode.length} chars)`);
|
|
207
115
|
}
|
|
208
|
-
const mergedCode = await callMorphAPI(
|
|
116
|
+
const { content: mergedCode, completionId } = await callMorphAPI(
|
|
209
117
|
input.originalCode,
|
|
210
118
|
input.codeEdit,
|
|
211
119
|
input.instructions,
|
|
@@ -218,7 +126,8 @@ async function applyEdit(input, config = {}) {
|
|
|
218
126
|
success: true,
|
|
219
127
|
mergedCode,
|
|
220
128
|
udiff,
|
|
221
|
-
changes
|
|
129
|
+
changes,
|
|
130
|
+
completionId
|
|
222
131
|
};
|
|
223
132
|
} catch (error) {
|
|
224
133
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
@@ -230,12 +139,12 @@ async function applyEdit(input, config = {}) {
|
|
|
230
139
|
};
|
|
231
140
|
}
|
|
232
141
|
}
|
|
233
|
-
var import_diff, DEFAULT_API_URL, DEFAULT_TIMEOUT;
|
|
142
|
+
var import_diff, import_openai, DEFAULT_API_URL, DEFAULT_TIMEOUT;
|
|
234
143
|
var init_apply = __esm({
|
|
235
144
|
"tools/fastapply/apply.ts"() {
|
|
236
145
|
"use strict";
|
|
237
146
|
import_diff = require("diff");
|
|
238
|
-
|
|
147
|
+
import_openai = __toESM(require("openai"), 1);
|
|
239
148
|
DEFAULT_API_URL = "https://api.morphllm.com";
|
|
240
149
|
DEFAULT_TIMEOUT = 3e4;
|
|
241
150
|
}
|
|
@@ -293,7 +202,7 @@ async function executeEditFile(input, config = {}) {
|
|
|
293
202
|
}
|
|
294
203
|
if (debug) console.log(`[FastApply] File doesn't exist, will create new file`);
|
|
295
204
|
}
|
|
296
|
-
const mergedCode = await callMorphAPI2(originalCode, input.code_edit, input.instructions, input.target_filepath, config);
|
|
205
|
+
const { content: mergedCode, completionId } = await callMorphAPI2(originalCode, input.code_edit, input.instructions, input.target_filepath, config);
|
|
297
206
|
const udiff = config.generateUdiff !== false ? generateUdiff2(originalCode, mergedCode, input.target_filepath) : void 0;
|
|
298
207
|
if (config.autoWrite !== false) {
|
|
299
208
|
await writeFile(fullPath, mergedCode, "utf-8");
|
|
@@ -304,7 +213,8 @@ async function executeEditFile(input, config = {}) {
|
|
|
304
213
|
success: true,
|
|
305
214
|
filepath: input.target_filepath,
|
|
306
215
|
udiff,
|
|
307
|
-
changes
|
|
216
|
+
changes,
|
|
217
|
+
completionId
|
|
308
218
|
};
|
|
309
219
|
} catch (error) {
|
|
310
220
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|