AI agents edit files using // ... existing code ... markers instead of sending full files. Morph merges server-side at 10,500 tokens/s.
Why this matters: Traditional search-replace uses 40% more tokens and takes more turns. Fast Apply is instant.
Installation
npm install @morphllm/morphsdk
Quick Start
Anthropic
OpenAI
Vercel AI SDK
MorphClient
import Anthropic from '@anthropic-ai/sdk';
import { MorphClient } from '@morphllm/morphsdk';
const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
const anthropic = new Anthropic();
// Tool inherits API key from MorphClient
const tool = morph.anthropic.createEditFileTool();
const response = await anthropic.messages.create({
model: "claude-sonnet-4-5-20250929",
max_tokens: 12000,
tools: [tool],
messages: [{
role: "user",
content: "Add error handling to src/auth.ts"
}]
});
import OpenAI from 'openai';
import { MorphClient } from '@morphllm/morphsdk';
const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
const openai = new OpenAI();
// Tool inherits API key from MorphClient
const tool = morph.openai.createEditFileTool();
const response = await openai.chat.completions.create({
model: "gpt-5-high",
tools: [tool],
messages: [{
role: "user",
content: "Add error handling to src/auth.ts"
}]
});
OpenAI high thinking models often output in patch format—Morph handles this automatically. If you see patch-style outputs, tune your system prompt to prefer // ... existing code ... markers for better results.
import { generateText, stepCountIs } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { MorphClient } from '@morphllm/morphsdk';
const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
// Create the tool that is compatible with the Vercel AI SDK
const editFileTool = morph.vercel.createEditFileTool();
const result = await generateText({
model: anthropic('claude-sonnet-4-5-20250929'),
tools: { editFile: editFileTool },
prompt: "Add error handling to src/auth.ts",
stopWhen: stepCountIs(5)
});
import { MorphClient } from '@morphllm/morphsdk';
const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
// Direct execution
const result = await morph.fastApply.execute({
target_filepath: 'src/auth.ts',
instructions: 'I will add null check',
code_edit: '// ... existing code ...\nif (!user) throw new Error("Not found");\n// ... existing code ...'
});
console.log(result.success); // true
console.log(`+${result.changes.linesAdded} -${result.changes.linesRemoved}`);
The instructions parameter provides crucial context for ambiguous edits, helping the apply model make correct decisions and achieve near perfect accuracy. Have the parent model generate the instructions.
How It Works
Agent outputs lazy edit:
async function login(email: string, password: string) {
// ... existing code ...
if (!user) {
throw new Error('Invalid credentials');
}
// ... existing code ...
}
Morph merges into your actual file:
@@ -12,6 +12,10 @@
const user = await db.findUser(email);
+
+ if (!user) {
+ throw new Error('Invalid credentials');
+ }
return createSession(user);
Key: The // ... existing code ... markers tell Morph where to insert changes without sending the full file.
Direct Usage
Use without an agent:
const result = await morph.fastApply.execute({
target_filepath: 'src/auth.ts',
instructions: 'I will add null check',
code_edit: '// ... existing code ...\nif (!user) throw new Error("Not found");\n// ... existing code ...'
});
console.log(result.success); // true
console.log(`+${result.changes.linesAdded} -${result.changes.linesRemoved}`);
Code-in/Code-out (Sandbox Support)
Use applyEdit when you manage your own filesystem or work in sandboxes like E2B, Modal, or Daytona:
applyEdit Function
MorphClient Method
import { applyEdit } from '@morphllm/morphsdk';
// Read file yourself (from sandbox, memory, etc.)
const originalCode = await sandbox.readFile('src/auth.ts');
const result = await applyEdit({
originalCode,
codeEdit: '// ... existing code ...\nif (!user) throw new Error("Not found");\n// ... existing code ...',
instructions: 'Add null check',
filepath: 'src/auth.ts' // Optional, for udiff context
});
if (result.success) {
// Write file yourself
await sandbox.writeFile('src/auth.ts', result.mergedCode);
console.log(result.udiff); // View the diff
}
import { MorphClient } from '@morphllm/morphsdk';
const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
const result = await morph.fastApply.applyEdit({
originalCode: 'function hello() { return "world"; }',
codeEdit: 'function hello() { return "universe"; }',
instructions: 'Change return value'
});
console.log(result.mergedCode);
// function hello() { return "universe"; }
applyEdit returns mergedCode instead of writing to disk—perfect for sandbox environments where you control file I/O.
Configuration
import { MorphClient } from '@morphllm/morphsdk';
const morph = new MorphClient({ apiKey: process.env.MORPH_API_KEY });
const tool = morph.openai.createEditFileTool({
baseDir: './src', // Default: process.cwd()
autoWrite: true, // Auto-write files (default: true)
generateUdiff: true // Return diff (default: true)
});
API
execute (file-based)
applyEdit (code-based)
Input (EditFileInput):{
target_filepath: string, // Relative to baseDir
instructions: string, // What the model is changing
code_edit: string // Code with // ... existing code ...
}
Returns (EditFileResult):{
success: boolean,
filepath: string,
changes: { linesAdded, linesRemoved, linesModified },
udiff?: string,
error?: string
}
Input (ApplyEditInput):{
originalCode: string, // Current file contents
codeEdit: string, // Code with // ... existing code ...
instructions: string, // What the model is changing
filepath?: string // Optional, for udiff context
}
Returns (ApplyEditResult):{
success: boolean,
mergedCode?: string, // The merged result
changes: { linesAdded, linesRemoved, linesModified },
udiff?: string,
error?: string
}
All types are exported from the SDK root:import type {
EditFileInput,
EditFileResult,
ApplyEditInput,
ApplyEditResult,
EditChanges
} from '@morphllm/morphsdk';
Error Handling
if (!result.success) {
console.error(result.error);
// "File not found" | "Invalid filepath" | "API error"
}