# Apply API Source: https://docs.morphllm.com/api-reference/endpoint/apply POST /v1/chat/completions Apply code edits at 10,500 tok/s with 98% accuracy via OpenAI-compatible API ## Overview The Apply API enables lightning-fast code editing at **10,500+ tokens/second** with **98% accuracy**. This OpenAI-compatible endpoint intelligently merges code changes while preserving structure and formatting. ## Models Choose the model that best fits your use case: Model Speed Accuracy Best For morph-v3-fast 10,500+ tok/sec 96% Real-time applications, quick edits morph-v3-large 5000+ tok/sec 98% Complex changes, highest accuracy auto 5000-10,500tok/sec \~98% Recommended - automatically selects optimal model
## Message Format The Apply API uses a structured XML format within the message content: ``` Brief description of what you're changing Original code content Code snippet showing only the changes with // ... existing code ... markers ``` ### Format Guidelines * **``**: Optional but recommended. Use first-person, clear descriptions * **``**: The complete original code that needs modification * **``**: Show only what changes, using `// ... existing code ...` for unchanged sections ## Usage Examples ```typescript TypeScript highlight={13} theme={null} import OpenAI from "openai"; const openai = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.morphllm.com/v1", }); const instruction = "I will add error handling to prevent division by zero"; const originalCode = "function divide(a, b) {\n return a / b;\n}"; const codeEdit = "function divide(a, b) {\n if (b === 0) {\n throw new Error('Cannot divide by zero');\n }\n return a / b;\n}"; const response = await openai.chat.completions.create({ model: "morph-v3-fast", messages: [ { role: "user", content: `${instruction}\n${originalCode}\n${codeEdit}`, }, ], }); const mergedCode = response.choices[0].message.content; ``` ```python Python highlight={14} theme={null} import os from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.morphllm.com/v1" ) instruction = "I will add error handling to prevent division by zero" original_code = "function divide(a, b) {\n return a / b;\n}" code_edit = "function divide(a, b) {\n if (b === 0) {\n throw new Error('Cannot divide by zero');\n }\n return a / b;\n}" response = client.chat.completions.create( model="morph-v3-fast", messages=[ { "role": "user", "content": f"{instruction}\n{original_code}\n{code_edit}" } ] ) merged_code = response.choices[0].message.content ``` ```bash cURL highlight={9} theme={null} curl -X POST "https://api.morphllm.com/v1/chat/completions" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "morph-v3-fast", "messages": [ { "role": "user", "content": "I will add error handling to prevent division by zero\nfunction divide(a, b) {\n return a / b;\n}\nfunction divide(a, b) {\n if (b === 0) {\n throw new Error(\"Cannot divide by zero\");\n }\n return a / b;\n}" } ] }' ``` ## Error Codes HTTP Status Description 200 Success - chat completion response 400 Bad request - malformed request or parameters 401 Authentication error - invalid API key
Build AI agent tools with Morph Apply See more implementation patterns # Cancel Batch Source: https://docs.morphllm.com/api-reference/endpoint/batches-cancel POST /v1/batches/{batch_id}/cancel Stop a running batch at /v1/batches/{batch_id}/cancel ## Overview Moves a `validating` or `in_progress` batch to `cancelling`, then `cancelled` once in-flight requests drain. Requests that already completed stay in the output file and are billed; the rest are written to the error file as `batch_cancelled`. Cancelling a terminal batch returns 400. # Create Batch Source: https://docs.morphllm.com/api-reference/endpoint/batches-create POST /v1/batches Start processing an uploaded input file at /v1/batches ## Overview Creates a batch over a file uploaded with `purpose: batch` and returns it in `validating`. Poll [`GET /v1/batches/{batch_id}`](/api-reference/endpoint/batches-retrieve) until `status` is terminal. Every line must target `/v1/chat/completions` and name the same model, `custom_id` must be unique within the file, and `stream: true` is rejected. Completed requests are billed at half the model's synchronous rate; see the [Batch guide](/sdk/components/batch) for the full contract. # List Batches Source: https://docs.morphllm.com/api-reference/endpoint/batches-list GET /v1/batches Page through your batches at /v1/batches ## Overview Lists the key's batches, newest first. `after` is an integer offset, not an object id: add `limit` to it for each next page. # Retrieve Batch Source: https://docs.morphllm.com/api-reference/endpoint/batches-retrieve GET /v1/batches/{batch_id} Poll a batch at /v1/batches/{batch_id} ## Overview Returns the batch with live `request_counts`. Once `status` is `completed`, `failed`, `expired`, or `cancelled`, download `output_file_id` and `error_file_id` from [the content endpoint](/api-reference/endpoint/files-content). Poll every 30 to 60 seconds; there is no webhook. # Compact API Source: https://docs.morphllm.com/api-reference/endpoint/compact POST /v1/compact Compress chat history and code context at 33,000 tok/s with byte-identical output ## Overview Compact compresses chat history and code context at **33,000 tok/s** by removing irrelevant lines. Every surviving line is byte-for-byte identical to the original input. 100K tokens compresses in under 2 seconds. Pass `query` to tell the model what matters for the next LLM call. Without it, the model auto-detects from the last user message. ## Usage Examples ```typescript TypeScript theme={null} import { MorphClient } from '@morphllm/morphsdk'; const morph = new MorphClient({ apiKey: "YOUR_API_KEY" }); const result = await morph.compact({ input: chatHistory, query: "How do I validate JWT tokens?", compressionRatio: 0.5, preserveRecent: 3, }); // result.output is the compressed text β€” pass it to your LLM ``` ```python Python (OpenAI SDK) theme={null} from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.morphllm.com/v1", ) response = client.chat.completions.create( model="morph-compactor", messages=[{"role": "user", "content": chat_history}], ) compressed = response.choices[0].message.content ``` ```python Python (requests) theme={null} import requests response = requests.post( "https://api.morphllm.com/v1/compact", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={ "input": source_code, "query": "authentication", "compression_ratio": 0.5, "preserve_recent": 0, }, ) data = response.json() print(data["output"]) for r in data["messages"][0]["compacted_line_ranges"]: print(f" lines {r['start']}-{r['end']} removed") ``` ```bash cURL theme={null} curl -X POST "https://api.morphllm.com/v1/compact" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": "def hello():\n return 1\n\ndef unused():\n pass\n\ndef world():\n return 2", "query": "hello function", "compression_ratio": 0.5, "preserve_recent": 0 }' ``` ## keepContext Tags Wrap sections you never want compressed in `` / `` tags. Tagged content survives compression verbatim regardless of the compression ratio. ``` // CRITICAL: Auth middleware β€” do not compress function authenticate(req, res, next) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'No token' }); req.user = jwt.verify(token, process.env.JWT_SECRET); next(); } ``` The response includes `kept_line_ranges` showing which lines were force-preserved. ## Compatible Endpoints Compact also works through OpenAI-compatible endpoints with `model: "morph-compactor"`: | Endpoint | Format | Use with | | --------------------------- | ----------------------- | -------------------------------------------- | | `POST /v1/compact` | Native Morph format | Direct HTTP, Morph SDK | | `POST /v1/responses` | OpenAI Responses API | Any OpenAI SDK (`client.responses.create()`) | | `POST /v1/chat/completions` | OpenAI Chat Completions | Any OpenAI-compatible client | See the full [Compact documentation](/sdk/components/compact) for SDK reference, best practices, and advanced usage. # Delete Model Source: https://docs.morphllm.com/api-reference/endpoint/delete-model DELETE /v1/models/{model} Remove a fine-tuned model at /v1/models/{model} ## Overview Deletes a fine-tuned model you own. Built-in models cannot be deleted. This is permanent β€” predictions against the id fail immediately after. # Code Apply API Source: https://docs.morphllm.com/api-reference/endpoint/direct POST /v1/code/apply Direct code apply endpoint with structured parameters for automated workflows ## Overview The Code Apply API provides a direct interface for applying code edits using the Morph model. This endpoint intelligently merges code changes at **10,500+ tokens/second** with **99.2% accuracy**, designed specifically for AI agents and development tools. Unlike the chat-based API, this endpoint accepts structured parameters directly, making it easier to integrate into automated workflows and development environments. ## Quickstart Add the `edit_file` tool to your agent. Use one of the formats below. ````xml Tool Description theme={null} Use this tool to make an edit to an existing file. This will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write. When writing the edit, you should specify each edit in sequence, with the special comment // ... existing code ... to represent unchanged code in between edited lines. For example: // ... existing code ... FIRST_EDIT // ... existing code ... SECOND_EDIT // ... existing code ... THIRD_EDIT // ... existing code ... You should still bias towards repeating as few lines of the original file as possible to convey the change. But, each edit should contain minimally sufficient context of unchanged lines around the code you're editing to resolve ambiguity. DO NOT omit spans of pre-existing code (or comments) without using the // ... existing code ... comment to indicate its absence. If you omit the existing code comment, the model may inadvertently delete these lines. If you plan on deleting a section, you must provide context before and after to delete it. If the initial code is ```code \n Block 1 \n Block 2 \n Block 3 \n code```, and you want to remove Block 2, you would output ```// ... existing code ... \n Block 1 \n Block 3 \n // ... existing code ...```. Make sure it is clear what the edit should be, and where it should be applied. Make edits to a file in a single edit_file call instead of multiple edit_file calls to the same file. The apply model can handle many distinct edits at once. ```` **Parameters:** * `target_file` (string, required): The target file to modify * `instructions` (string, required): A single sentence written in the first person describing what you're changing. Used to help disambiguate uncertainty in the edit. * `code_edit` (string, required): Specify ONLY the precise lines of code that you wish to edit. Use `// ... existing code ...` for unchanged sections. ````json Tool Definition theme={null} { "name": "edit_file", "description": "Use this tool to make an edit to an existing file.\n\nThis will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write.\nWhen writing the edit, you should specify each edit in sequence, with the special comment // ... existing code ... to represent unchanged code in between edited lines.\n\nFor example:\n\n// ... existing code ...\nFIRST_EDIT\n// ... existing code ...\nSECOND_EDIT\n// ... existing code ...\nTHIRD_EDIT\n// ... existing code ...\n\nYou should still bias towards repeating as few lines of the original file as possible to convey the change.\nBut, each edit should contain minimally sufficient context of unchanged lines around the code you're editing to resolve ambiguity.\nDO NOT omit spans of pre-existing code (or comments) without using the // ... existing code ... comment to indicate its absence. If you omit the existing code comment, the model may inadvertently delete these lines.\nIf you plan on deleting a section, you must provide context before and after to delete it. If the initial code is ```code \\n Block 1 \\n Block 2 \\n Block 3 \\n code```, and you want to remove Block 2, you would output ```// ... existing code ... \\n Block 1 \\n Block 3 \\n // ... existing code ...```.\nMake sure it is clear what the edit should be, and where it should be applied.\nMake edits to a file in a single edit_file call instead of multiple edit_file calls to the same file. The apply model can handle many distinct edits at once.", "input_schema": { "type": "object", "properties": { "target_file": { "type": "string", "description": "Name or path of target file to modify." }, "instructions": { "type": "string", "description": "A single sentence instruction describing what you are going to do for the sketched edit. This is used to assist the less intelligent model in applying the edit. Use the first person to describe what you are going to do. Use it to disambiguate uncertainty in the edit." }, "code_edit": { "type": "string", "description": "Specify ONLY the precise lines of code that you wish to edit. NEVER specify or write out unchanged code. Instead, represent all unchanged code using the comment of the language you're editing in - example: // ... existing code ..." } }, "required": ["target_file", "instructions", "code_edit"] } } ```` Instead of using tool calls, you can have the agent output code edits in markdown format that you can parse: ````markdown Agent Instruction theme={null} Use this approach to make edits to existing files by outputting code edits in a specific markdown format. This will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write. When writing the edit, you should specify each edit in sequence, with the special comment // ... existing code ... to represent unchanged code in between edited lines. For example: // ... existing code ... FIRST_EDIT // ... existing code ... SECOND_EDIT // ... existing code ... THIRD_EDIT // ... existing code ... You should still bias towards repeating as few lines of the original file as possible to convey the change. But, each edit should contain minimally sufficient context of unchanged lines around the code you're editing to resolve ambiguity. DO NOT omit spans of pre-existing code (or comments) without using the // ... existing code ... comment to indicate its absence. If you omit the existing code comment, the model may inadvertently delete these lines. If you plan on deleting a section, you must provide context before and after to delete it. If the initial code is ```code \n Block 1 \n Block 2 \n Block 3 \n code```, and you want to remove Block 2, you would output ```// ... existing code ... \n Block 1 \n Block 3 \n // ... existing code ...```. Make sure it is clear what the edit should be, and where it should be applied. Make edits to a file in a single response instead of multiple responses to the same file. The apply model can handle many distinct edits at once. When you want to edit a file, output your code edits using this markdown format: ```filepath=path/to/file.js instruction=A single sentence describing what you're changing // ... existing code ... YOUR_CODE_EDIT_HERE // ... existing code ... ``` The instruction should be written in the first person describing what you're changing. Used to help disambiguate uncertainty in the edit. ```` **IMPORTANT:** The `instructions` param should be generated by the model, not hardcoded. Example: "I am adding error handling to the user auth and removing the old auth functions" Send the original code and edit snippet to the Code Apply endpoint: ```python theme={null} import requests url = "https://api.morphllm.com/v1/code/apply" api_key = "[YOUR_API_KEY]" headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } data = { "initial_code": initial_code, "edit_snippet": edit_snippet, } response = requests.post(url, headers=headers, json=data) return response.json() ``` Extract the final merged code from the response: ```python theme={null} merged_code = response.json()["merged_code"] ``` **Response format:** ```json theme={null} { "merged_code": "string", "usage": { "prompt_tokens": "number", "completion_tokens": "number", "total_tokens": "number" } } ``` ## Models Choose the model that best fits your use case: Model Speed Accuracy Best For morph-v3-fast 10,500+ tok/sec 97% Real-time applications, best for most coding agents and files morph-v3-large 5000+ tok/sec 98.8% Complex changes, highest accuracy, best for complex edits auto 5000-10,500tok/sec \~98.8% Recommended - automatically selects optimal model
## Request Format ```json theme={null} { "initial_code": "string", "edit_snippet": "string", "instructions": "string (optional)", "model": "string (optional)", "stream": "boolean (optional)" } ``` ### Parameters * **`initial_code`** (required): The complete original code that needs modification * **`edit_snippet`** (required): Code snippet showing the changes with `// ... existing code ...` markers for unchanged sections * **`instructions`** (optional): Brief description of what you're changing to help disambiguate the edit * **`model`** (optional): Model to use (`morph-v3-fast`, `morph-v3-large`, or `auto` - defaults to `auto`) * **`stream`** (optional): Whether to stream the response (defaults to `false`) ## Response Format ### Non-Streaming Response ```json theme={null} { "mergedCode": "string", "usage": { "prompt_tokens": "number", "completion_tokens": "number", "total_tokens": "number" } } ``` ### Streaming Response For streaming requests (`stream: true`), the response follows the Server-Sent Events (SSE) format with incremental code updates. ## Example Request ```bash theme={null} curl -X POST "https://api.morphllm.com/v1/code/apply" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "initial_code": "function divide(a, b) {\n return a / b;\n}", "edit_snippet": "function divide(a, b) {\n if (b === 0) {\n throw new Error('\''Cannot divide by zero'\'');\n }\n return a / b;\n}", "instructions": "Add error handling to prevent division by zero" }' ``` ## Example Response ```json theme={null} { "merged_code": "function divide(a, b) {\n if (b === 0) {\n throw new Error('Cannot divide by zero');\n }\n return a / b;\n}", "usage": { "prompt_tokens": 45, "completion_tokens": 28, "total_tokens": 73 } } ``` ## Error Codes HTTP Status Error Code Description 200 - Success - code successfully applied 400 bad\_request Bad request - missing required parameters or malformed request 401 unauthorized Authentication required - invalid or missing API key 500 code\_apply\_error Internal error during code application 503 service\_unavailable Model not available - service temporarily unavailable
## Key Features * **High Performance**: Up to 10,500+ tokens/second with morph-v3-fast * **High Accuracy**: 99.2% accuracy with intelligent code merging * **Preserves Structure**: Maintains code formatting, indentation, and comments * **Streaming Support**: Real-time streaming for large code changes * **Multiple Models**: Choose between speed and accuracy based on your needs * **Direct Integration**: Simple JSON API designed for automated workflows Learn how to integrate the Code Apply API into your workflow Use the OpenAI-compatible chat interface instead # Tab Next Action Prediction API Source: https://docs.morphllm.com/api-reference/endpoint/donotshare Tab Next Action Prediction API endpoints ## Base URL ``` http://192.222.50.238:8080 ``` faster proxy endpoint: (in progress) ``` http://192.222.50.238:9000 ``` *** ## Health Check Check server status and cache performance. ```http theme={null} GET /health ``` ```bash cURL theme={null} curl http://192.222.50.238:8080/health ``` ```python Python theme={null} import requests response = requests.get("http://192.222.50.238:8080/health") print(response.json()) ``` ```javascript JavaScript theme={null} const response = await fetch('http://192.222.50.238:8080/health'); const data = await response.json(); ``` ### Response ```json theme={null} { "status": "healthy", "server_role": "standalone", "model": "morph-test", "gpu_available": true, "cache_enabled": true, "cache_stats": { "enabled": true, "hit_rate": 0.92, "num_cached_tokens": 15420 }, "uptime_seconds": 3847.2 } ``` Service status: `healthy` or `degraded` Server role: `standalone`, `prefiller`, or `decoder` Model name being served Whether GPU is available and initialized Whether prefix caching is enabled Cache performance statistics (if caching enabled) Cache status Cache hit rate (0.0 - 1.0) Number of tokens currently cached Server uptime in seconds *** ## Generate Prediction Generate next action prediction from a prompt. ```http theme={null} POST /v1/predict ``` ```bash cURL theme={null} curl -X POST http://192.222.50.238:8080/v1/predict \ -H "Content-Type: application/json" \ -d '{ "prompt": "{\"type\":3,\"data\":{\"source\":2,\"type\":6,\"id\":42,\"x\":385,\"y\":127}}\n{\"type\":3,\"data\":{\"source\":2,\"type\":2,\"id\":42,\"x\":385,\"y\":127,\"pointerType\":0}}\n{\"type\":3,\"data\":{\"source\":2,\"type\":1,\"id\":56}}\n{\"type\":3,\"data\":{\"source\":5,\"text\":\"user@example.com\",\"isChecked\":false,\"id\":56}}", "max_tokens": 50, "temperature": 0.3 }' ``` ```python Python theme={null} import requests # rrweb events as prompt rrweb_events = """{"type":3,"data":{"source":2,"type":6,"id":42,"x":385,"y":127}} {"type":3,"data":{"source":2,"type":2,"id":42,"x":385,"y":127,"pointerType":0}} {"type":3,"data":{"source":2,"type":1,"id":56}} {"type":3,"data":{"source":5,"text":"user@example.com","isChecked":false,"id":56}}""" response = requests.post( "http://192.222.50.238:8080/v1/predict", json={ "prompt": rrweb_events, "max_tokens": 50, "temperature": 0.3 } ) print(response.json()) ``` ```javascript JavaScript theme={null} // rrweb events as prompt const rrwebEvents = `{"type":3,"data":{"source":2,"type":6,"id":42,"x":385,"y":127}} {"type":3,"data":{"source":2,"type":2,"id":42,"x":385,"y":127,"pointerType":0}} {"type":3,"data":{"source":2,"type":1,"id":56}} {"type":3,"data":{"source":5,"text":"user@example.com","isChecked":false,"id":56}}`; const response = await fetch('http://192.222.50.238:8080/v1/predict', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: rrwebEvents, max_tokens: 50, temperature: 0.3 }) }); const data = await response.json(); ``` ```python Python (batch events) theme={null} import requests # Send batch of rrweb events rrweb_batch = [ {"type": 3, "data": {"source": 2, "type": 6, "id": 42, "x": 385, "y": 127}}, {"type": 3, "data": {"source": 2, "type": 2, "id": 42, "x": 385, "y": 127, "pointerType": 0}}, {"type": 3, "data": {"source": 2, "type": 1, "id": 56}}, {"type": 3, "data": {"source": 5, "text": "user@example.com", "isChecked": False, "id": 56}} ] # Convert to newline-delimited JSON string prompt = "\n".join([str(event) for event in rrweb_batch]) response = requests.post( "http://192.222.50.238:8080/v1/predict", json={ "prompt": prompt, "max_tokens": 50, "temperature": 0.3 } ) ``` ### Request Body rrweb event data as newline-delimited JSON. Each line should be a valid rrweb event object Maximum number of tokens to generate (range: 1-512) Sampling temperature (range: 0.0-2.0). Lower values produce more deterministic outputs Enable streaming response (currently not implemented) ### Response ```json theme={null} { "text": "{\"type\":3,\"data\":{\"source\":2,\"type\":1,\"id\":67}}\n{\"type\":3,\"data\":{\"source\":5,\"text\":\"password123\",\"isChecked\":false,\"id\":67}}", "latency_ms": 287, "tokens_generated": 42 } ``` Generated rrweb event predictions as newline-delimited JSON Request processing latency in milliseconds Number of tokens generated in the response *** ## Error Responses All errors return JSON with a standard format: ```json theme={null} { "detail": "Error message describing what went wrong" } ``` ### Status Codes Request completed successfully Invalid request parameters (e.g., temperature out of range) Model not ready or server not initialized Unexpected server error during prediction *** ## Performance Tips **Optimize Cache Hits**: Send rrweb events in consistent session sequences to maximize prefix cache reuse. Events from the same session with consistent ordering will achieve higher cache hit rates and lower latency. **Typical Latency**: * Single-node: \~800ms (P50), \~1.5s (P99) * Disaggregated: \~250ms (P50), \~450ms (P99) (in progress) * Cache hit rate of 90%+ dramatically reduces latency for similar event sequences ## rrweb Event Format The API expects rrweb events as newline-delimited JSON strings. Common event types: * **Type 2 (Meta)**: Page metadata and viewport info * **Type 3 (Incremental)**: User interactions (clicks, input, scroll, etc.) * `source: 2` = MouseInteraction * `source: 5` = Input * `source: 3` = MouseMove * **Type 4 (IncrementalSnapshot)**: DOM mutations Example event structure: ```json theme={null} { "type": 3, "data": { "source": 2, "type": 2, "id": 42, "x": 385, "y": 127, "pointerType": 0 } } ``` # Enterprise Apply Source: https://docs.morphllm.com/api-reference/endpoint/enterprise POST /v1/chat/completions Enterprise Apply API with custom model configurations **πŸ”’ CONFIDENTIAL - INTERNAL USE ONLY** This page contains proprietary enterprise API documentation and is linked to your account. Do not share any information mentioned here with anyone external to your company. This documentation is for internal development and integration purposes only. # Quickstart Switch to instruction-guided editing with 98% accuracy in 3 steps. ## Prerequisites * Enterprise API key from your Morph account * Access to `https://api.morphllm.com/v1/` | Model | Speed | Accuracy | Input Limit | Output Limit | | -------------- | ------------------ | -------- | -------------- | -------------- | | morph-v3-fast | 10,500+ tok/sec | **96%** | **16k tokens** | **16k tokens** | | morph-v3-large | 5000+ tok/sec | **98%** | **16k tokens** | **16k tokens** | | auto | 5000-10,500tok/sec | **98%** | **16k tokens** | **16k tokens** | ## 1. Configure Your Edit Tool Set up your AI agent to generate the proper instructions guided format for the highest accuracy editing. **Edit File Tool Description:** ````xml theme={null} Use this tool to make an edit to an existing file. This will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write. When writing the edit, you should specify each edit in sequence, with the special comment // ... existing code ... to represent unchanged code in between edited lines. For example: // ... existing code ... FIRST_EDIT // ... existing code ... SECOND_EDIT // ... existing code ... THIRD_EDIT // ... existing code ... You should still bias towards repeating as few lines of the original file as possible to convey the change. But, each edit should contain minimally sufficient context of unchanged lines around the code you're editing to resolve ambiguity. DO NOT omit spans of pre-existing code (or comments) without using the // ... existing code ... comment to indicate its absence. If you omit the existing code comment, the model may inadvertently delete these lines. If you plan on deleting a section, you must provide context before and after to delete it. If the initial code is ```code \n Block 1 \n Block 2 \n Block 3 \n code```, and you want to remove Block 2, you would output ```// ... existing code ... \n Block 1 \n Block 3 \n // ... existing code ...```. Make sure it is clear what the edit should be, and where it should be applied. ALWAYS make all edits to a file in a single edit_file instead of multiple edit_file calls to the same file. The apply model can handle many distinct edits at once. ```` **Parameters:** * `target_filepath` (string, required): The path of the target file to modify * `instructions` (string, required): A single sentence written in the first person describing what you're changing. Used to help disambiguate uncertainty in the edit. * `code_edit` (string, required): Specify ONLY the precise lines of code that you wish to edit. Use `// ... existing code ...` for unchanged sections. **Tool Definition:** ````json theme={null} { "name": "edit_file", "description": "Use this tool to make an edit to an existing file.\n\nThis will be read by a less intelligent model, which will quickly apply the edit. You should make it clear what the edit is, while also minimizing the unchanged code you write.\nWhen writing the edit, you should specify each edit in sequence, with the special comment // ... existing code ... to represent unchanged code in between edited lines.\n\nFor example:\n\n// ... existing code ...\nFIRST_EDIT\n// ... existing code ...\nSECOND_EDIT\n// ... existing code ...\nTHIRD_EDIT\n// ... existing code ...\n\nYou should still bias towards repeating as few lines of the original file as possible to convey the change.\nBut, each edit should contain minimally sufficient context of unchanged lines around the code you're editing to resolve ambiguity.\nDO NOT omit spans of pre-existing code (or comments) without using the // ... existing code ... comment to indicate its absence. If you omit the existing code comment, the model may inadvertently delete these lines.\nIf you plan on deleting a section, you must provide context before and after to delete it. If the initial code is ```code \\n Block 1 \\n Block 2 \\n Block 3 \\n code```, and you want to remove Block 2, you would output ```// ... existing code ... \\n Block 1 \\n Block 3 \\n // ... existing code ...```.\nMake sure it is clear what the edit should be, and where it should be applied.\nALWAYS make all edits to a file in a single edit_file instead of multiple edit_file calls to the same file. The apply model can handle many distinct edits at once.", "parameters": { "properties": { "target_filepath": { "type": "string", "description": "Path of the target file to modify." }, "instructions": { "type": "string", "description": "A single sentence instruction describing what you are going to do for the sketched edit. This is used to assist the less intelligent model in applying the edit. Use the first person to describe what you are going to do. Use it to disambiguate uncertainty in the edit." }, "code_edit": { "type": "string", "description": "Specify ONLY the precise lines of code that you wish to edit. NEVER specify or write out unchanged code. Instead, represent all unchanged code using the comment of the language you're editing in - example: // ... existing code ..." } }, "required": ["target_filepath", "instructions", "code_edit"] } } ```` The `instructions` field should be generated by your AI model, not user input. Follow the tool description above nearly verbatim - terminology like "use it to disambiguate uncertainty in the edit" should be used. Example: "I am adding error handling to the user authentication function" ## 2. Send to Morph Enterprise API ```typescript enterprise_apply.ts theme={null} import { OpenAI } from 'openai'; const client = new OpenAI({ apiKey: 'your-enterprise-api-key', baseURL: 'https://api.morphllm.com/v1' }); const testOriginalCode = ` const a = 1 const b = 2 function add(a, b) { return a + b } function subtract(a, b) { return a - b } const authenticateUser () => { return "Authenticated" } `; // Test data - your agent should generate these const testInstruction = "I will add the real user authentication function and remove the old authentication method"; const testUpdateSnippet = ` // ... existing code ... const authenticateUser = (email, password) => { const result = await verifyUser(email, password) if (result) { return "Authenticated" } else { return "Unauthenticated" } } `; async function applyEnterpriseEdit( instruction: string, originalCode: string, updateSnippet: string ): Promise { const response = await client.chat.completions.create({ model: "morph-v3-fast", messages: [ { role: "user", content: `${instruction}\n${originalCode}\n${updateSnippet}` } ] }); return response.choices[0].message.content || ''; } // Example usage async function main() { try { const finalCode = await applyEnterpriseEdit( testInstruction, testOriginalCode, testUpdateSnippet ); console.log("Final merged code:"); console.log(finalCode); } catch (error) { console.error("Error applying edit:", error); } } // Run the example main(); ``` ```python enterprise_apply.py theme={null} import openai import asyncio client = openai.OpenAI( api_key="your-enterprise-api-key", base_url="https://api.morphllm.com/v1" ) test_original_code = """ const a = 1 const b = 2 def add(a, b): return a + b } def subtract(a, b): return a - b } def authenticateUser (): return "Authenticated" } """ # Test data - your agent should generate these test_instruction = "I will add the real user authentication function and remove the old authentication method" # This is the instruction that your agent should generate test_update_snippet = """ def authenticateUser (email, password) => { # ... existing code ... result = await verifyUser(email, password) if (result) { return "Authenticated" } else { return "Unauthenticated" } } """ def apply_enterprise_edit(instruction: str, original_code: str, update_snippet: str): """Apply an enterprise edit using Morph's instruction-guided editing.""" response = client.chat.completions.create( model="morph-v3-fast", messages=[ { "role": "user", "content": f"{instruction}\n{original_code}\n{update_snippet}" } ] ) return response.choices[0].message.content # Example usage if __name__ == "__main__": final_code = apply_enterprise_edit( test_instruction, test_original_code, test_update_snippet ) print("Final merged code:") print(final_code) ``` ## 3. Handle the Response Extract the merged code from the enterprise API response. **Response Format:** ```json theme={null} final_code = response.choices[0].message.content ``` **Extract the Final Code:** ```typescript extract_code.ts theme={null} const finalCode = response.choices[0].message.content; // Write to file or return to your application await fs.writeFile(targetFile, finalCode); ``` ```python extract_code.py theme={null} final_code = response.choices[0].message.content # Write to file or return to your application with open(target_file, 'w') as f: f.write(final_code) ``` *** ## Enterprise Features Instruction-guided editing achieves 98% accuracy on complex code changes Handle entire large files, complete modules, and complex codebases Generate complete implementations, full refactors, and comprehensive updates **Migration from Standard API:** Enterprise API requires an `` field but maintains backward compatibility with existing `` patterns. # Download File Content Source: https://docs.morphllm.com/api-reference/endpoint/files-content GET /v1/files/{file_id}/content Stream a file's bytes at /v1/files/{file_id}/content ## Overview Streams the file as `application/octet-stream`, one JSON object per line. For a batch's `output_file_id` every line is a [`BatchOutputLine`](/sdk/components/batch#output-file-format); for its `error_file_id` every line is a [`BatchErrorLine`](/sdk/components/batch#error-file-format). Lines are not in input order, so join them to your requests on `custom_id`. # Delete File Source: https://docs.morphllm.com/api-reference/endpoint/files-delete DELETE /v1/files/{file_id} Remove a file and its content at /v1/files/{file_id} ## Overview Deletes a file immediately. A batch that has already read an input file keeps running; deleting an output file makes its results unrecoverable. Files you leave alone are deleted on their own at `expires_at`. # List Files Source: https://docs.morphllm.com/api-reference/endpoint/files-list GET /v1/files Page through uploaded and generated files at /v1/files ## Overview Lists your files, newest first by default. Filter with `purpose=batch` for uploads or `purpose=batch_output` for the output and error files batches produce. `after` is an integer offset, not an object id: add `limit` to it for each next page. # Retrieve File Source: https://docs.morphllm.com/api-reference/endpoint/files-retrieve GET /v1/files/{file_id} Read a file's metadata at /v1/files/{file_id} ## Overview Returns a file's size, purpose, and `expires_at`. Use [the content endpoint](/api-reference/endpoint/files-content) to download the bytes. # Upload File Source: https://docs.morphllm.com/api-reference/endpoint/files-upload POST /v1/files Upload a JSONL batch input file at /v1/files ## Overview Uploads a JSONL file of chat-completion requests with `purpose: batch` and returns its `file_` id. Pass that id as `input_file_id` to [create a batch](/api-reference/endpoint/batches-create). Each line is a [`BatchInputLine`](/sdk/components/batch#input-file-format); files are capped at 100 MB and 50,000 lines. # Cancel Fine-tuning Job Source: https://docs.morphllm.com/api-reference/endpoint/fine-tuning-cancel POST /v1/fine_tuning/jobs/{job_id}/cancel Stop a running job at /v1/fine_tuning/jobs/{job_id}/cancel ## Overview Cancels a queued or running job. Jobs already in a terminal state are unaffected. # Create Fine-tuning Job Source: https://docs.morphllm.com/api-reference/endpoint/fine-tuning-create POST /v1/fine_tuning/jobs Train a custom Reflex at /v1/fine_tuning/jobs ## Overview Creates a fine-tuning job that trains a custom Reflex from labeled examples. The resulting `fine_tuned_model` id is usable in [`POST /v1/reflex/predict`](/api-reference/endpoint/reflex) when the job succeeds. Track progress with [job events](/api-reference/endpoint/fine-tuning-events). # Delete Fine-tuning Job Source: https://docs.morphllm.com/api-reference/endpoint/fine-tuning-delete DELETE /v1/fine_tuning/jobs/{job_id} Remove a job and its artifacts at /v1/fine_tuning/jobs/{job_id} ## Overview Deletes a fine-tuning job. Delete the trained model itself with [`DELETE /v1/models/{model}`](/api-reference/endpoint/delete-model). # List Job Events Source: https://docs.morphllm.com/api-reference/endpoint/fine-tuning-events GET /v1/fine_tuning/jobs/{job_id}/events Stream training progress at /v1/fine_tuning/jobs/{job_id}/events ## Overview Returns the training event log for a job β€” queued, running, metrics, and terminal transitions β€” with cursor pagination. # Get Fine-tuning Job Source: https://docs.morphllm.com/api-reference/endpoint/fine-tuning-get GET /v1/fine_tuning/jobs/{job_id} Fetch one job's state at /v1/fine_tuning/jobs/{job_id} ## Overview Returns a single job, including status and β€” once the job succeeds β€” the `fine_tuned_model` id to use for prediction. # List Fine-tuning Jobs Source: https://docs.morphllm.com/api-reference/endpoint/fine-tuning-list GET /v1/fine_tuning/jobs Page through your fine-tuning jobs at /v1/fine_tuning/jobs ## Overview Lists your fine-tuning jobs, newest first, with cursor pagination. # Messages API Source: https://docs.morphllm.com/api-reference/endpoint/messages POST /v1/messages Anthropic-compatible /v1/messages endpoint β€” point an Anthropic SDK at Morph by changing the base URL ## Overview `POST /v1/messages` mirrors Anthropic's Messages API. Clients built on an Anthropic SDK switch to Morph by changing the base URL and API key β€” no request or response rewriting. ```python theme={null} import anthropic client = anthropic.Anthropic( base_url="https://api.morphllm.com", api_key="YOUR_MORPH_API_KEY", ) message = client.messages.create( model="morph-glm53-744b", max_tokens=1024, messages=[{"role": "user", "content": "Refactor this function to be async."}], ) print(message.content[0].text) ``` Model ids, prices, and context windows are served live at [morphllm.com/api/models/json](https://www.morphllm.com/api/models/json) β€” fetch that rather than hardcoding. For OpenAI-style clients, use [`POST /v1/chat/completions`](/api-reference/endpoint/apply) instead; both routes serve the same models. # List Models Source: https://docs.morphllm.com/api-reference/endpoint/models GET /v1/models OpenAI-compatible model listing at /v1/models ## Overview `GET /v1/models` returns the model ids your key can use, in the OpenAI list shape β€” SDK helpers like `client.models.list()` work unchanged. ```bash theme={null} curl https://api.morphllm.com/v1/models \ -H "Authorization: Bearer $MORPH_API_KEY" ``` This endpoint returns ids only. Prices and context windows live at [morphllm.com/api/models/json](https://www.morphllm.com/api/models/json), which is regenerated from the same source as billing β€” use it for anything cost-sensitive. # Reflex API Source: https://docs.morphllm.com/api-reference/endpoint/reflex POST /v1/reflex/predict Per-turn text classifiers β€” predict in ~90ms, batch, and train custom Reflexes over an OpenAI-compatible API ## Overview A Reflex is a small, fast text classifier that puts a label on a turn in \~90ms. Pass a default Reflex name (`jailbreak`, `guardrail`, `leaked-thinking`, `stuck-in-a-loop`, `incomplete-thought`, `user-frustrated`, `ambiguity`, `difficulty`, `domain`) or a model you trained in the `model` field. The playground above is `POST /v1/reflex/predict` β€” pass `models` (an array) instead of `model` to run several classifiers over one shared prefill. ## Full endpoint surface Every endpoint below is in the [OpenAPI spec](https://docs.morphllm.com/api-reference/openapi.json). Try `predict` in the playground above; the rest carry copy-paste examples in the guides linked under each table. ### Classify | Method | Endpoint | Does | | ------ | ---------------------------------------------------- | ------------------------------------------------------- | | `POST` | `/v1/reflex/predict` | Classify text, single or multi-model. | | `POST` | `/v1/reflex/synchronous_predict_batch` | Up to 300 rows inline, one response. | | `POST` | `/v1/reflex/asynchronous_batches/upload` | Queue up to 10,000 rows offline at the discounted rate. | | `GET` | `/v1/reflex/asynchronous_batches/{batch_id}` | Poll an async batch. | | `GET` | `/v1/reflex/asynchronous_batches/{batch_id}/results` | Fetch async batch results. | Guides: [Predict](/sdk/components/reflexes), [Batch classification](/sdk/components/reflexes/batch). ### Train | Method | Endpoint | Does | | -------- | -------------------------------------- | -------------------------------------------------------------------------- | | `POST` | `/v1/fine_tuning/jobs` | Train a custom Reflex from labeled data, a description, or unlabeled text. | | `GET` | `/v1/fine_tuning/jobs` | List your jobs. | | `GET` | `/v1/fine_tuning/jobs/{job_id}` | Retrieve a job and poll its status. | | `POST` | `/v1/fine_tuning/jobs/{job_id}/cancel` | Cancel a queued or running job. | | `GET` | `/v1/fine_tuning/jobs/{job_id}/events` | Training events and the loss curve (SSE with `?stream=true`). | | `DELETE` | `/v1/fine_tuning/jobs/{job_id}` | Delete a job and its model. | | `DELETE` | `/v1/models/{model}` | Delete a trained model by name. | Guide: [Train a Custom Reflex](/sdk/components/reflexes/custom). What a Reflex is, the default classifiers, and realtime `/predict`. Bring labeled examples or synthesize a dataset; get a classifier in \~30s. # Get Batch Results Source: https://docs.morphllm.com/api-reference/endpoint/reflex-batch-results GET /v1/reflex/asynchronous_batches/{batch_id}/results Fetch scored rows from a completed batch at /v1/reflex/asynchronous_batches/{batch_id}/results ## Overview Returns the per-row predictions for a completed asynchronous batch. Rows for batches still in progress return once the batch reaches a terminal state β€” check [status](/api-reference/endpoint/reflex-batch-status) first. # Get Batch Status Source: https://docs.morphllm.com/api-reference/endpoint/reflex-batch-status GET /v1/reflex/asynchronous_batches/{batch_id} Poll an async classification batch at /v1/reflex/asynchronous_batches/{batch_id} ## Overview Returns the state and row counts of an asynchronous batch. Poll until `status` is terminal, then fetch [results](/api-reference/endpoint/reflex-batch-results). # Synchronous Batch Predict Source: https://docs.morphllm.com/api-reference/endpoint/reflex-batch-sync POST /v1/reflex/synchronous_predict_batch Classify up to 1,000 rows in one blocking request at /v1/reflex/synchronous_predict_batch ## Overview Classifies a batch of rows in one request and blocks until every row is scored. For workloads too large to wait on, use the [asynchronous batch flow](/api-reference/endpoint/reflex-batch-upload) instead. Single-row realtime prediction is [`POST /v1/reflex/predict`](/api-reference/endpoint/reflex). # Async Batch Upload Source: https://docs.morphllm.com/api-reference/endpoint/reflex-batch-upload POST /v1/reflex/asynchronous_batches/upload Queue a large classification batch at /v1/reflex/asynchronous_batches/upload ## Overview Queues a batch for asynchronous classification and returns a batch id immediately. Poll [`GET /v1/reflex/asynchronous_batches/{batch_id}`](/api-reference/endpoint/reflex-batch-status) for progress and fetch rows from [the results endpoint](/api-reference/endpoint/reflex-batch-results) when it completes. Async pricing is half the realtime rate. # Report API Source: https://docs.morphllm.com/api-reference/endpoint/report POST /api/report Report failed or problematic completions to improve Morph model quality ## Overview Report failed or problematic completions to help improve Morph's quality. This endpoint allows you to flag completions that produced incorrect, malformed, or problematic code so our team can investigate and improve the models. **When to use this endpoint:** * Generated code has syntax errors * Applied changes broke existing functionality * Model output doesn't match the intended instruction * Generated code produces runtime errors or exceptions * Code quality issues (security vulnerabilities, bad practices) The completion ID can be found in the response headers (`x-completion-id`) or server logs from your original apply request. ## Request Body The completion ID from the original request (found in response headers or logs) Description of what went wrong (Error message, traceback, etc.) The original user instruction that led to the problematic completion. This helps provide context for debugging and improving the model. Maximum 2000 characters. ## Response Whether the report was successfully recorded Confirmation message Internal ID of the reported request ISO timestamp when the report was recorded ## Error Codes | Status | Description | | ------ | ---------------------------- | | `200` | Report successfully recorded | | `400` | Invalid request parameters | | `401` | Invalid or missing API key | | `404` | Completion ID not found | | `409` | Request already reported | ## Examples ### cURL ```bash theme={null} curl -X POST "https://morphllm.com/api/report" \ -H "Authorization: Bearer your-api-key" \ -H "Content-Type: application/json" \ -d '{ "completion_id": "chatcmpl-9d9e2fc21c094f4eacbcee0009f2f12d", "failure_reason": "Generated code had syntax errors: SyntaxError: Unexpected token in JSON", "user_query": "Add error handling to the user login function" }' ``` ### JavaScript (fetch) ```javascript theme={null} const reportFailure = async (completionId, failureReason, userQuery = null) => { const payload = { completion_id: completionId, failure_reason: failureReason, }; // Include user_query only if provided if (userQuery) { payload.user_query = userQuery; } const response = await fetch('https://morphllm.com/api/report', { method: 'POST', headers: { 'Authorization': 'Bearer your-api-key', 'Content-Type': 'application/json', }, body: JSON.stringify(payload), }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); }; // Usage with user query try { const result = await reportFailure( 'chatcmpl-9d9e2fc21c094f4eacbcee0009f2f12d', 'Generated code produces runtime error: TypeError: Cannot read property', 'Add validation to user input fields' ); console.log('Report submitted:', result); } catch (error) { console.error('Failed to submit report:', error); } // Usage without user query try { const result = await reportFailure( 'chatcmpl-9d9e2fc21c094f4eacbcee0009f2f12d', 'Generated code produces runtime error: TypeError: Cannot read property' ); console.log('Report submitted:', result); } catch (error) { console.error('Failed to submit report:', error); } ``` ### Python (requests) ```python theme={null} import requests import json def report_failure(completion_id, failure_reason, api_key, user_query=None): url = "https://morphllm.com/api/report" headers = { "Authorization": f"Bearer {api_key}", "Content-Type": "application/json" } payload = { "completion_id": completion_id, "failure_reason": failure_reason } # Include user_query only if provided if user_query: payload["user_query"] = user_query try: response = requests.post(url, headers=headers, json=payload) response.raise_for_status() # Raises an HTTPError for bad responses return response.json() except requests.exceptions.RequestException as e: print(f"Error submitting report: {e}") return None # Usage with user query api_key = "your-api-key" completion_id = "chatcmpl-9d9e2fc21c094f4eacbcee0009f2f12d" failure_reason = """ Traceback (most recent call last): File "generated_code.py", line 10, in result = process_data(invalid_input) File "generated_code.py", line 5, in process_data return data.split('.') AttributeError: 'NoneType' object has no attribute 'split' """ user_query = "Refactor the data processing function to handle null values" result = report_failure(completion_id, failure_reason, api_key, user_query) if result: print(f"Report submitted successfully: {result}") # Usage without user query result = report_failure(completion_id, failure_reason, api_key) if result: print(f"Report submitted successfully: {result}") ``` ### Node.js (axios) ```javascript theme={null} const axios = require('axios'); async function reportFailure(completionId, failureReason, apiKey, userQuery = null) { try { const payload = { completion_id: completionId, failure_reason: failureReason, }; // Include user_query only if provided if (userQuery) { payload.user_query = userQuery; } const response = await axios.post('https://morphllm.com/api/report', payload, { headers: { 'Authorization': `Bearer ${apiKey}`, 'Content-Type': 'application/json', }, }); return response.data; } catch (error) { if (error.response) { // Server responded with error status console.error('Server error:', error.response.data); throw new Error(`Server error: ${error.response.status} - ${error.response.data.error?.message}`); } else if (error.request) { // Request was made but no response received console.error('Network error:', error.request); throw new Error('Network error: No response received'); } else { // Something else happened console.error('Request error:', error.message); throw new Error(`Request error: ${error.message}`); } } } // Usage with user query (async () => { try { const result = await reportFailure( 'chatcmpl-9d9e2fc21c094f4eacbcee0009f2f12d', 'Generated code fails unit tests: Expected 5 but got undefined', 'your-api-key', 'Add unit tests for the calculate function' ); console.log('Success:', result.message); console.log('Report ID:', result.data?.request_log_id); console.log('Reported at:', result.data?.reported_at); } catch (error) { console.error('Failed to report:', error.message); } })(); // Usage without user query (async () => { try { const result = await reportFailure( 'chatcmpl-9d9e2fc21c094f4eacbcee0009f2f12d', 'Generated code fails unit tests: Expected 5 but got undefined', 'your-api-key' ); console.log('Success:', result.message); console.log('Report ID:', result.data?.request_log_id); console.log('Reported at:', result.data?.reported_at); } catch (error) { console.error('Failed to report:', error.message); } })(); ``` ### Response Example Successful response (200 OK): ```json theme={null} { "success": true, "message": "Report successfully recorded", "data": { "request_log_id": "req_123456789", "reported_at": "2024-01-15T10:30:00Z" } } ``` Error response (400 Bad Request): ```json theme={null} { "error": { "message": "Missing required parameter: completion_id", "type": "invalid_request_error", "code": "missing_parameter" } } ``` # Retrieve Model Source: https://docs.morphllm.com/api-reference/endpoint/retrieve-model GET /v1/models/{model} Fetch a single model by id at /v1/models/{model} ## Overview `GET /v1/models/{model}` returns one model object by id β€” the OpenAI `client.models.retrieve()` shape. A 404 means the id doesn't exist or your key can't use it. ```bash theme={null} curl https://api.morphllm.com/v1/models/morph-v3-fast \ -H "Authorization: Bearer $MORPH_API_KEY" ``` # WarpGrep API Source: https://docs.morphllm.com/api-reference/endpoint/warpgrep POST /v1/chat/completions Agentic code search subagent that explores repositories in ~6 seconds ## Overview WarpGrep is a code search agent that uses a multi-turn conversation to explore repositories. The model has its tools (`grep_search`, `read`, `list_directory`, `glob`, `finish`) **built in** β€” you do not need to pass a `tools` array in your requests. ## Model Use `morph-warp-grep-v2.1` as the model identifier. ## Message Format WarpGrep uses a structured format in the initial user message with **flat absolute paths**: ```xml theme={null} /home/user/myproject /home/user/myproject/README.md /home/user/myproject/package.json /home/user/myproject/src /home/user/myproject/src/auth /home/user/myproject/src/auth/login.py /home/user/myproject/src/db /home/user/myproject/src/utils /home/user/myproject/tests /home/user/myproject/config.py /home/user/myproject/main.py Find where user authentication is implemented ``` ### Format Components * **``**: Flat list of absolute paths β€” repo root first, then all files/directories to depth 2. No indentation, no tree characters, no trailing `/` on directories. * **``**: Natural language description of what code to find ## Example Request ```typescript TypeScript theme={null} import OpenAI from "openai"; const openai = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.morphllm.com/v1", }); const repoRoot = "/home/user/myapp"; const repoStructure = `${repoRoot} ${repoRoot}/src ${repoRoot}/src/auth ${repoRoot}/src/api ${repoRoot}/src/models ${repoRoot}/tests ${repoRoot}/package.json`; const searchQuery = "Find where JWT tokens are validated"; const response = await openai.chat.completions.create({ model: "morph-warp-grep-v2.1", messages: [ { role: "user", content: `\n${repoStructure}\n\n\n\n${searchQuery}\n` } ], temperature: 0.0, max_tokens: 2048 }); // Response has tool_calls β€” execute locally and continue the loop const toolCalls = response.choices[0].message.tool_calls; ``` ```python Python theme={null} from openai import OpenAI client = OpenAI( api_key="YOUR_API_KEY", base_url="https://api.morphllm.com/v1" ) repo_root = "/home/user/myapp" repo_structure = f"""{repo_root} {repo_root}/src {repo_root}/src/auth {repo_root}/src/api {repo_root}/src/models {repo_root}/tests {repo_root}/package.json""" search_query = "Find where JWT tokens are validated" response = client.chat.completions.create( model="morph-warp-grep-v2.1", messages=[ { "role": "user", "content": f"\n{repo_structure}\n\n\n\n{search_query}\n" } ], temperature=0.0, max_tokens=2048, ) # Response has tool_calls β€” execute locally and continue the loop tool_calls = response.choices[0].message.tool_calls ``` ```bash cURL theme={null} curl -X POST "https://api.morphllm.com/v1/chat/completions" \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "morph-warp-grep-v2.1", "messages": [ { "role": "user", "content": "\n/home/user/myapp\n/home/user/myapp/src\n/home/user/myapp/src/auth\n\n\n\nFind where JWT tokens are validated\n" } ], "temperature": 0.0, "max_tokens": 2048 }' ``` See [Direct API Access](/sdk/components/warp-grep/direct) for the full protocol details including tool execution and multi-turn flow. ## Multi-Turn Conversation WarpGrep uses built-in tool calling (up to 6 turns). The agent will: 1. **Turn 1**: Analyze your search query and call tools (`grep_search`, `list_directory`, `glob`) to explore 2. **Turns 2-5**: Refine search based on results, read specific files 3. **Final turn**: Call `finish` with code locations You execute tool calls locally and return results as `{role: "tool", tool_call_id: "...", content: "..."}` messages. ## Request Parameters | Parameter | Type | Required | Description | | ------------- | ------ | -------- | -------------------------------------------- | | `model` | string | Yes | Must be `morph-warp-grep-v2.1` | | `messages` | array | Yes | Array of conversation messages | | `temperature` | number | No | Recommended: `0.0` for deterministic results | | `max_tokens` | number | No | Recommended: `2048` | Tools are built into the model β€” you do **not** need to pass a `tools` parameter. The model will return `tool_calls` automatically. ## Response Format The agent responds with structured `tool_calls`: ```json theme={null} { "id": "chatcmpl-abc123", "object": "chat.completion", "created": 1234567890, "model": "morph-warp-grep-v2.1", "choices": [{ "index": 0, "message": { "role": "assistant", "content": null, "tool_calls": [ {"id": "chatcmpl-tool-abc123", "type": "function", "function": {"name": "grep_search", "arguments": "{\"pattern\": \"jwt|JWT\"}"}}, {"id": "chatcmpl-tool-def456", "type": "function", "function": {"name": "list_directory", "arguments": "{\"command\": \"ls src/auth\"}"}} ] }, "finish_reason": "tool_calls" }], "usage": { "prompt_tokens": 1180, "total_tokens": 1245, "completion_tokens": 65 } } ``` After you execute tools and return results, the agent continues until it calls `finish`. On tool-call turns the assistant `content` is `null`. Read only the `tool_calls` array. ## Available Tools WarpGrep uses five tools: * **`grep_search`**: Search for regex patterns across files. Case-insensitive by default. * **`read`**: Read file contents with optional line ranges * **`list_directory`**: Explore directory structure * **`glob`**: Find files by name/extension pattern (sorted by mtime) * **`finish`**: Submit final answer with code locations. Paths are **absolute**, matching the paths from the repo structure. See the [Direct API Guide](/sdk/components/warp-grep/direct) for complete tool specifications. Implement your tools to tolerate loose argument types. The model may send `limit` or `case_sensitive` as strings (`"50"`, `"false"`), and `grep_search` may emit undocumented arguments such as `output_lines` (an alias for `limit`) or `output_context_lines`. Coerce known keys and ignore unrecognized ones rather than erroring. See the [Direct API Guide](/sdk/components/warp-grep/direct#tool-definitions) for the full schema and robustness rules. ## SDK Integration For easier integration, use the WarpGrep SDK components: * **[TypeScript Tool](/sdk/components/warp-grep/tool)**: Drop-in tool for AI SDKs * **[Python Guide](/guides/warp-grep-python)**: Complete Python implementation ## Error Codes HTTP Status Description 200 Success - chat completion response with tool\_calls 400 Bad request - malformed request or parameters 401 Authentication error - invalid API key
Build your own WarpGrep harness Complete Python guide with examples # Self-Hosting Source: https://docs.morphllm.com/api-reference/self-hosting Run Morph models in your own environment with self-hosting options ## Overview For organizations with strict security requirements, Morph offers self-hosting options that allow you to run our code transformation models in your own environment. ## Benefits of Self-Hosting * **Zero data retention**: Your code never leaves your environment * **No usage metering**: Predictable costs with no per-request billing * **Full control**: Deploy behind your firewall with your own security controls * **Same performance**: The exact same speed and accuracy as our cloud offering ## Deployment Options Morph can be deployed in containers using Docker and Kubernetes, or directly in your private cloud infrastructure (AWS, GCP, Azure). ## Complete Suite for Coding Agents Self-hosted Morph includes: * **Fast Apply Model**: Transform code with unmatched speed and precision * **WarpGrep**: Agentic code search that explores the repo in a separate context window ## Get Started with Self-Hosting For information about self-hosting options and enterprise licensing, please contact us at [info@morphllm.com](mailto:info@morphllm.com). # Authentication Source: https://docs.morphllm.com/auth Learn how to authenticate with Morph API using Bearer tokens **Prerequisite**: You'll need an account on [Morph](https://morphllm.com/dashboard) to obtain an API key. ## Authentication All Morph API endpoints require authentication using Bearer tokens: ```bash theme={null} Authorization: Bearer your-morph-api-key ``` To get your API key: 1. Visit the [Morph dashboard](https://morphllm.com/api-keys) 2. Create an account or sign in 3. Navigate to your API keys section 4. Generate a new API key Keep your API key secure and never expose it in client-side code or public repositories. ## Base URL All Morph API endpoints use the following base URL: ```bash theme={null} https://api.morphllm.com/v1 ``` ## Test Your API Key Verify your setup with a simple test request: ```python Python theme={null} from openai import OpenAI client = OpenAI( api_key="your-morph-api-key", base_url="https://api.morphllm.com/v1" ) # Test the connection response = client.chat.completions.create( model="morph-v3-fast", messages=[{ "role": "user", "content": "def hello():\n print('Hello World')\ndef hello():\n print('Hello Morph!')" }] ) print(response.choices[0].message.content) ``` ```javascript JavaScript theme={null} import { OpenAI } from "openai"; const client = new OpenAI({ apiKey: "your-morph-api-key", baseURL: "https://api.morphllm.com/v1", }); // Test the connection const response = await client.chat.completions.create({ model: "morph-v3-fast", messages: [ { role: "user", content: "def hello():\n print('Hello World')\ndef hello():\n print('Hello Morph!')", }, ], }); console.log(response.choices[0].message.content); ``` ```bash cURL theme={null} curl --request POST \ --url https://api.morphllm.com/v1/chat/completions \ --header 'Authorization: Bearer your-morph-api-key' \ --header 'Content-Type: application/json' \ --data '{ "model": "morph-v3-fast", "messages": [{ "role": "user", "content": "def hello():\n print(\"Hello World\")\ndef hello():\n print(\"Hello Morph!\")" }] }' ``` If the test succeeds, you should see the updated code with "Hello Morph!" instead of "Hello World". ## Alternative Access Methods You can also access Morph through these platforms: Access Morph models through OpenRouter's unified API platform Access Morph models through Opper's EU-hosted AI gateway Use Morph with Model Context Protocol servers and Claude Desktop ## Next Steps Now that you've tested your API key, explore Morph's specialized models: Apply code changes with precision at 10,500 tokens per second and 98% accuracy Find relevant code with a search subagent that explores the repo in \~6 seconds For access to our latest models, self-hosting, or business inquiries, please contact us at [info@morphllm.com](mailto:info@morphllm.com). # Dedicated checkout operations Source: https://docs.morphllm.com/dedicated-checkout-operations # Dedicated Checkout operations A dedicated purchase takes one of two paths, both ending at the same order state machine. ## Saved payment method (accounts with billing on file) `POST /api/dedicated/checkout` looks up the account's Stripe customer before creating anything hosted. When a saved payment method is found it creates the subscription directly with `off_session: true` and activates the order in the same request, so the buyer never leaves the dashboard and never sees a Stripe-hosted page. The response is `{ url: , checkout: 'saved_payment_method' }`. A bank account wins over a card whenever the customer has both β€” ACH carries no percentage fee on a five-figure invoice. Within a type, the customer's default payment method wins. Two conditions send an account with billing on file to hosted Checkout anyway: * **An upfront commitment charge on a bank account.** Only metered plans (`reserved_gpu_hour`) owe nothing at subscription creation. A plan with a licensed commitment price settles synchronously on a card, but an ACH debit reports `processing` for days, and GPU capacity must not be held against money that has not moved. * **The subscription came back short of `active`.** A declined card leaves an `incomplete` subscription; it is canceled before falling back so one order can never carry two subscriptions. Automatic tax is enabled only when Stripe already recognizes the customer's location (`customer.tax.automatic_tax === 'supported'`). Off-session there is no address-collection step to make an unrecognized location calculable. Stripe's hosted promotion-code field does not exist on this path. A discounted purchase for an existing account is applied as a customer or subscription discount in Stripe, not typed at checkout. ## Hosted Checkout (accounts with nothing on file) Cold accounts use Stripe-hosted Checkout in subscription mode, restricted to `us_bank_account`; cards are not an allowed fallback there. Stripe's hosted promotion-code field is enabled, so promotion eligibility, redemption limits, and expiration remain authoritative in Stripe. The response is `{ url: , checkout: 'hosted' }`. ## Production webhook Configure the Stripe account webhook destination as: ```text theme={null} https://www.morphllm.com/api/webhooks/stripe ``` Subscribe it to at least these events: * `checkout.session.completed` * `invoice.paid` * `invoice.payment_failed` Set the destination's signing secret as `STRIPE_WEBHOOK_SECRET` in the Vercel Production environment. The shared handler detects `metadata.type=dedicated_endpoint` and routes those events to the dedicated commerce ledger before ordinary account billing. Event IDs are claimed in the same database transaction as their effects, so duplicate delivery is safe. A dedicated `checkout.session.completed` activates an order only when `payment_status` is `paid` or `no_payment_required`. The latter is expected for hourly metered subscriptions with no initial usage, including a fully discounted Checkout. Before holding capacity, the handler verifies the Checkout session ID, plan version, and requested model against the stored order. Both purchase paths then call the same `activateDedicatedOrder` (`src/lib/dedicated-commerce-db.ts`): it sets the subscription ID and two-hour activation deadline, transitions `checkout_pending β†’ paid`, and holds capacity or drops the order to `refunding`. It no-ops once the order has left `checkout_pending`, so duplicate webhooks and retried requests are safe. `invoice.paid` grants the commitment from the subscription's `dedicatedOrderId` metadata on both paths, and the reconciler keys refunds off `stripe_subscription_id`, so neither depends on a Checkout session existing. ## Scale from zero Purchasing never procures infrastructure. After payment is committed, the activation transaction holds GPU-equivalents against the configured pool limit. The hold may be `pending_capacity` with no node or slots when the first compatible node does not yet exist. The GitOps pull request records that demand but cannot merge until inventory is registered and the hold is atomically assigned a node and contiguous slots. For the 4Γ— B200 DeepSeek offer, the immutable values are: ```text theme={null} planVersionId: b200-hourly-4-v1 requestedModelId: deepseek-v4-flash modelTemplate: DeepSeek V4 Flash capacityPool: b200-dsv4flash gpuEquivalents: 4 nodeGpuCount: 8 ``` ## Annual display Production currently has monthly hourly Stripe prices only. Selecting Yearly displays the annual reference rate but changes the CTA to contact sales. It must not silently start a monthly Checkout at the displayed annual rate. Add a versioned annual plan and Stripe price before enabling direct annual Checkout. ## Initial 4Γ— B200 production enablement Run migrations `0040_add_dedicated_discount_catalog.sql` and `0041_add_dedicated_order_model.sql` first. Create the Stripe product and metered hourly Price, then substitute its real `price_...` ID below. This opens exactly one 4-GPU-equivalent logical sale while leaving physical inventory empty: ```sql theme={null} BEGIN; UPDATE dedicated_capacity_pools SET total_gpu_equivalents = 4, accepting_purchases = true, updated_at = now() WHERE id = 'b200-dsv4flash'; UPDATE dedicated_plan_versions SET stripe_price_id = 'price_REPLACE_WITH_LIVE_B200_HOURLY_PRICE', checkout_enabled = true, provisional_pricing = false, margin_approved_at = now(), launch_approved_at = now(), available_from = now(), retired_at = NULL WHERE id = 'b200-hourly-4-v1' AND billing_model = 'reserved_gpu_hour' AND gpu_hour_rate_microusd = 9827100; UPDATE dedicated_plan_versions SET checkout_enabled = false, retired_at = COALESCE(retired_at, now()) WHERE id IN ('b200-priority-2-v1', 'b200-priority-4-v1', 'b200-priority-8-v1'); COMMIT; ``` Before committing, verify that each `UPDATE` matched the intended row and that no physical node was inserted into `dedicated_capacity_nodes`. The first paid purchase creates a four-GPU logical hold and an unmergeable `pending_capacity` GitOps PR. Register the procured node in both control-plane inventory and `dedicated_capacity_nodes`; the reconciler will atomically assign slots and update the same PR to `allocated`. # Dedicated endpoints Source: https://docs.morphllm.com/dedicated-endpoints Reserve model capacity, send requests, monitor usage, and cancel service Reserve model capacity by choosing a model and plan. Morph provisions and operates it; once ready, connect an OpenAI client using the endpoint's URL and served model name. Idle capacity remains allocated and billable. Endpoints do not automatically shrink with traffic or scale to zero. ## Create an endpoint Install the Morph CLI: ```bash theme={null} curl -fsSL https://morphllm.com/install.sh | bash export PATH="$HOME/.local/bin:$PATH" ``` Create a [dashboard API key](https://www.morphllm.com/dashboard/api-keys) for the endpoint's account or organization, then set it in your terminal: ```bash theme={null} export MORPH_API_KEY="YOUR_MORPH_API_KEY" morph dedicated models morph dedicated create deepseek-v4-flash ``` `models` lists valid IDs; substitute one for `deepseek-v4-flash` if needed. Without a plan flag, `create` opens the browser plan picker. Select the owning account or organization there; the CLI key does not select browser billing. Choose capacity, review the agreement, and confirm. Alternatively, choose `--price`, `--balanced`, or `--fast` in the terminal: ```bash theme={null} morph dedicated create deepseek-v4-flash --balanced ``` The CLI shows the plan, requests confirmation, then uses saved payment details or opens hosted checkout. Use one purchase flow per endpoint. From [Dedicated](https://www.morphllm.com/dashboard/dedicated), [create an endpoint](https://www.morphllm.com/dashboard/dedicated/create). Choose a model and capacity. Review price, billing account, and agreement before purchasing. Organization purchases require an admin. ## Wait for readiness Watch provisioning on the endpoint's dashboard detail page, or list and inspect orders: ```bash theme={null} morph dedicated list morph dedicated status ENDPOINT_ID ``` Use the ID from your purchase or endpoint list. Wait for `ready` and connection details before sending requests; provisioning status is not a serving URL. Get connection details and lifecycle events as JSON: ```bash theme={null} morph dedicated status ENDPOINT_ID --json ``` After activation, `endpoint.endpointUrl` and `endpoint.servedModelName` identify your endpoint. Use this served name for requests, not the catalog ID. ## Send a request Copy connection details from the dashboard or status response; set them alongside your key: ```bash theme={null} export MORPH_API_KEY="YOUR_MORPH_API_KEY" export MORPH_ENDPOINT_URL="YOUR_ENDPOINT_URL" export MORPH_ENDPOINT_MODEL="YOUR_SERVED_MODEL_NAME" ``` Supply the URL without `/v1`; these examples append it. Run `pip install openai`, then: ```python theme={null} import os from openai import OpenAI client = OpenAI( api_key=os.environ["MORPH_API_KEY"], base_url=os.environ["MORPH_ENDPOINT_URL"].rstrip("/") + "/v1", ) response = client.chat.completions.create( model=os.environ["MORPH_ENDPOINT_MODEL"], messages=[{"role": "user", "content": "Hello!"}], ) print(response.choices[0].message.content) ``` Run `npm install openai`. Save as `request.mjs`; run `node request.mjs`: ```javascript theme={null} import OpenAI from "openai"; const endpointUrl = process.env.MORPH_ENDPOINT_URL; const model = process.env.MORPH_ENDPOINT_MODEL; if (!endpointUrl || !model) { throw new Error("Set MORPH_ENDPOINT_URL and MORPH_ENDPOINT_MODEL from the endpoint status."); } const client = new OpenAI({ apiKey: process.env.MORPH_API_KEY, baseURL: endpointUrl.replace(/\/$/, "") + "/v1", }); const response = await client.chat.completions.create({ model, messages: [{ role: "user", content: "Hello!" }], }); console.log(response.choices[0].message.content); ``` Keys must belong to the endpoint's account or organization. `morph token new` saves a CLI key; SDKs still need `MORPH_API_KEY` exported. ## Monitor your endpoint Open its dashboard: ```bash theme={null} morph dedicated dashboard ENDPOINT_ID ``` View provisioning, request counts, token usage, latency, and success metrics where available. Logs contain operational metadata, excluding prompts and responses. ```bash theme={null} morph dedicated logs ENDPOINT_ID morph dedicated logs ENDPOINT_ID --errors morph dedicated logs ENDPOINT_ID --follow morph dedicated history ENDPOINT_ID ``` `logs --follow` polls until Ctrl+C; `history` shows lifecycle events, including provisioning. Logs are empty before activation because requests are not yet served. ## Capacity and scaling Lower traffic does not reduce reserved capacity or charges. The CLI and dashboard expose no autoscaling limits, scaling to zero, region selection, custom weights, or engine configuration. Morph manages serving and placement; contact us for other capacity arrangements. Endpoint access is scoped to your account, but hardware is not exclusive: idle hardware may serve other traffic. Use [shared inference](/shared-inference) without reserving capacity. ## Billing and cancellation Hourly plans bill reserved GPU time from readiness, including idle time. Displayed token counts measure usage, not charges. Check your checkout agreement for rates and service terms. In [Dedicated](https://www.morphllm.com/dashboard/dedicated), select **Cancel dedicated** on the order or detail page and confirm. Organization cancellations require an admin. Alternatively: ```bash theme={null} morph dedicated stop ENDPOINT_ID ``` Canceling a purchased order before activation stops billing immediately and starts refunds for collected payments. Active endpoints follow their agreement: service and charges continue until the cancellation response's effective date, also shown in `status`. Verify with `morph dedicated status ENDPOINT_ID`. Cancel accidental purchases before creating another endpoint. ## Troubleshoot a request | Symptom | What to check | | :------------------------------------------- | :--------------------------------------------------------------------- | | Still provisioning | Check `status` and `history`; wait for `ready` and connection details. | | Unauthorized | Use a valid key from the owning account or organization. | | Model not found | Use the served model name, not the catalog ID. | | Request fails | Check `logs --errors` and readiness. | | Organization purchase or cancellation denied | Ask an organization admin. | For provisioning failures, send [support](https://www.morphllm.com/contact) the endpoint ID and history. Do not duplicate pending orders. # Endpoints Source: https://docs.morphllm.com/endpoints Choose shared inference or reserve capacity for a dedicated model endpoint Call shared models immediately or reserve dedicated capacity. Morph manages both. ## Choose how to serve | | Shared inference | Dedicated endpoints | | :-------------- | :----------------------------- | :---------------------------------------------- | | Start | Send requests with a Morph key | Choose model and plan; wait for provisioning | | Capacity | Shared model pools | Reserved endpoint capacity | | Billing | Model token usage | Hourly plans: reserved GPU time, including idle | | Model name | Public catalog ID | Served name returned at readiness | | OpenAI base URL | `https://api.morphllm.com/v1` | Endpoint URL plus `/v1` | Send your first shared API request. Create, monitor, and cancel reserved capacity. Dedicated capacity neither shrinks with traffic nor scales to zero. Review [scaling](/dedicated-endpoints#capacity-and-scaling) before purchasing. ## API formats Shared API: `https://api.morphllm.com`. One key, two formats: | Endpoint | Format | Serves | | :-------------------------- | :---------------------- | :----------------------------------------------------- | | `/v1/chat/completions` | OpenAI Chat Completions | All models | | `/v1/messages` | Anthropic Messages | [Open-source chat models](/sdk/components/fast-models) | | `/v1/messages/count_tokens` | Anthropic | Same | SDK examples use tabs. Anthropic Messages supports the same open source chat models, token billing, and rate limits. [Fast Apply](/sdk/components/fast-apply), [WarpGrep](/sdk/components/warp-grep/index), [Compact](/sdk/components/compact), and [Reflex](/sdk/components/reflexes/index) use OpenAI format only. Authenticate with `Authorization: Bearer YOUR_API_KEY` or `x-api-key: YOUR_API_KEY`. ```python theme={null} import anthropic client = anthropic.Anthropic( api_key="YOUR_API_KEY", base_url="https://api.morphllm.com", ) message = client.messages.create( model="morph-glm53-744b", max_tokens=1024, messages=[{"role": "user", "content": "Write a tiny rate limiter in TS."}], ) print(message.content[-1].text) # last block: models may emit a thinking block first ``` ```typescript theme={null} import Anthropic from "@anthropic-ai/sdk"; const client = new Anthropic({ apiKey: "YOUR_API_KEY", baseURL: "https://api.morphllm.com", }); const message = await client.messages.create({ model: "morph-glm53-744b", max_tokens: 1024, messages: [{ role: "user", content: "Write a tiny rate limiter in TS." }], }); ``` ```bash theme={null} curl -X POST "https://api.morphllm.com/v1/messages" \ -H "x-api-key: YOUR_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "morph-glm53-744b", "max_tokens": 1024, "messages": [{"role": "user", "content": "Write a tiny rate limiter in TS."}] }' ``` Anthropic streaming, tools (`tool_use` / `tool_result`), system prompts, and conversation history work unchanged. Reasoning returns `thinking` blocks; requested thinking budgets map to [effort tiers](/sdk/components/fast-models): under 8k β†’ `low`, under 24k β†’ `medium`, above β†’ `high`. ## Claude Code ```bash theme={null} export ANTHROPIC_BASE_URL=https://api.morphllm.com export ANTHROPIC_AUTH_TOKEN=YOUR_API_KEY export ANTHROPIC_MODEL=morph-kimik3 # or morph-glm53-744b claude ``` [Claude Code setup](/guides/coding-agents) supports tools, streaming, system prompts, and conversation history. Verified with v2.1. Anthropic folds system messages into its system prompt. In Morph, `messages` entries with `{"role": "system"}` return `400`, `invalid message role: 'system'`. Use the separate `system` parameter, as Claude Code already does. Proxies injecting system messages must rewrite those entries to `user` until support ships. # Enterprise Solutions Source: https://docs.morphllm.com/enterprise Deploy Morph with enterprise-grade security, compliance, and support ## Enterprise Features Deploy on your infrastructure with full data control Dedicated instance with SOC2 compliance and SLAs Air-gapped deployment for maximum security 24/7 dedicated support with guaranteed response times ## Key Benefits * **Enhanced Models**: 44k input / 36k output context windows (coming soon) * **Security & Compliance**: SOC2 Type II certified, HIPAA compliant options * **Enterprise Support**: 24/7 dedicated support with SLA guarantees * **Flexible Deployment**: Multi-region, auto-scaling, custom endpoints ## Pricing Enterprise pricing is customized based on deployment type, usage volume, support level, and additional features. Get custom deployment options and enterprise features # Agent Tools (edit_file) Source: https://docs.morphllm.com/guides/agent-tools Build precise AI agents that edit code fast without full file rewrites using Morph's edit_file tool ## Essential Supporting Tools Always read files before editing to understand the structure: ```json theme={null} { "name": "read_file", "description": "Read the contents of a file to understand its structure before making edits", "parameters": { "properties": { "target_file": { "type": "string", "description": "The path of the file to read" }, "start_line_one_indexed": { "type": "integer", "description": "Start line number (1-indexed)" }, "end_line_one_indexed_inclusive": { "type": "integer", "description": "End line number (1-indexed, inclusive)" }, "explanation": { "type": "string", "description": "Why you're reading this file" } }, "required": ["target_file", "explanation"] } } ``` **Best practice:** Read the relevant sections first, then edit with proper context. Agentic code search to locate relevant code: ```json theme={null} { "name": "codebase_search", "description": "Find snippets of code from the codebase most relevant to the search query", "parameters": { "properties": { "query": { "type": "string", "description": "The search query to find relevant code" }, "target_directories": { "type": "array", "items": {"type": "string"}, "description": "Optional: limit search scope to specific directories" }, "explanation": { "type": "string", "description": "Why you're searching for this" } }, "required": ["query", "explanation"] } } ``` **Best practice:** Search first to understand the codebase, then read specific files. When you need exact text or pattern matches: ```json theme={null} { "name": "grep_search", "description": "Fast text-based regex search that finds exact pattern matches within files", "parameters": { "properties": { "query": { "type": "string", "description": "The regex pattern to search for" }, "include_pattern": { "type": "string", "description": "File types to include (e.g. '*.ts')" }, "explanation": { "type": "string", "description": "Why you're searching for this pattern" } }, "required": ["query", "explanation"] } } ``` **Best practice:** Use for finding function names, imports, or specific strings. Navigate and understand the codebase structure: ```json theme={null} { "name": "list_dir", "description": "List the contents of a directory to understand project structure", "parameters": { "properties": { "relative_workspace_path": { "type": "string", "description": "Path to list contents of, relative to the workspace root" }, "explanation": { "type": "string", "description": "Why you're listing this directory" } }, "required": ["relative_workspace_path", "explanation"] } } ``` **Best practice:** Use to explore unknown codebases or find related files before editing. ## Agent Workflow Effective agents follow this pattern: 1. **πŸ” Search**: Find relevant code with `codebase_search` or `grep_search` 2. **πŸ“– Read**: Get context with `read_file` before editing 3. **✏️ Edit**: Make precise changes with `edit_file` 4. **βœ… Verify**: Read again to confirm changes worked ## Common Patterns **Delete a section in between:** ```javascript theme={null} // ... existing code ... function keepThis() { return "stay"; } function alsoKeepThis() { return "also stay"; } // ... existing code ... ``` **Add imports:** ```javascript theme={null} import { useState, useEffect } from "react"; import { calculateTax } from "./utils"; // New import // ... existing code ... ``` **Update configuration:** ```json theme={null} { "name": "my-app", "version": "2.0.0", "scripts": { "dev": "next dev", "build": "next build", "test": "jest" } } ``` **Add error handling:** ```javascript theme={null} // ... existing code ... function divide(a, b) { if (b === 0) { throw new Error("Cannot divide by zero"); } return a / b; } // ... existing code ... ``` **Update function parameters:** ```javascript theme={null} // ... existing code ... function authenticateUser(email, password) { const result = await verifyUser(email, password); if (result) { return "Authenticated"; } else { return "Unauthenticated"; } } // ... existing code ... ``` **Add new methods to a class:** ```javascript theme={null} // ... existing code ... class UserService { async getUser(id) { return await this.db.findUser(id); } async updateUser(id, data) { return await this.db.updateUser(id, data); } } // ... existing code ... ``` ## Error Handling Morph is trained to be robust to poor quality update snippets, but you should still follow these steps to ensure the best quality. When tools fail, follow these steps: 1. **Check file permissions**: Ensure the target file is writable 2. **Verify file path**: Confirm the file exists and path is correct 3. **Review syntax**: Check that your edit snippet follows the `// ... existing code ...` pattern 4. **Retry with context**: Read the file again and provide more context around your changes 5. **Simplify changes**: Break complex edits into smaller, focused changes **Common Error Patterns:** ```javascript theme={null} // ❌ Wrong - missing context function newFunction() { return "hello"; } // βœ… Correct - with context // ... existing code ... function newFunction() { return "hello"; } // ... existing code ... ``` ## Next Steps Ready to start building with Morph? Here's what to do next: Learn about the Apply API endpoints, models, and message formats for production use Step-by-step guide to configure your agent with the edit\_file tool and integrate with Morph's Fast Apply API For complex refactoring across multiple files, consider using multiple `edit_file` calls in sequence. For failed edits, read the file again and provide more context around your changes. # Vercel AI SDK Source: https://docs.morphllm.com/guides/ai-sdk Stream fast code edits with Morph using the Vercel AI SDK # Morph + Vercel AI SDK Stream code edits at 10,500+ tokens/second using the Vercel AI SDK with Morph's fast apply model. Use Vercel's AI Gateway for unified billing, rate limits, and failover across 100+ AI models. ## Setup ### Option 1: AI Gateway (Recommended) 1. Get an [AI Gateway API key](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai%2Fapi-keys%3Futm_source%3Dai_sdk_code_generator_modal\&title=Get+an+AI+Gateway+API+Key) from Vercel 2. Add it to your environment variables as `OPENAI_API_KEY` 3. Install the AI SDK: ```bash theme={null} npm install ai@beta ``` ### Option 2: Direct API 1. Get a Morph API key from the [Morph dashboard](https://morphllm.com) 2. Add it to your environment variables as `MORPH_API_KEY` 3. Install the AI SDK: ```bash theme={null} npm install ai@beta ``` ## Implementation ```typescript AI Gateway theme={null} import { streamText } from 'ai' import { createOpenAI } from '@ai-sdk/openai' const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY!, baseURL: 'https://gateway.ai.vercel.com/v1', headers: { 'X-Vercel-AI-Provider': 'morph', }, }) export async function POST(req: Request) { const { editInstructions, originalCode, update } = await req.json() // Get the morph model through AI Gateway const model = openai('morph-v3-fast') // Call the language model with the prompt const result = streamText({ model, messages: [ { role: 'user', content: `${editInstructions}\n${originalCode}\n${update}` } ], topP: 1, }) // Respond with a streaming response return result.toAIStreamResponse() } ``` ```typescript Direct API theme={null} import { streamText } from 'ai' import { createOpenAICompatible } from '@ai-sdk/openai-compatible' const morph = createOpenAICompatible({ apiKey: "YOUR_API_KEY", name: 'morph', baseURL: 'https://api.morphllm.com/v1' }) export async function POST(req: Request) { const { editInstructions, originalCode, update } = await req.json() // Get a language model const model = morph('morph-v3-fast') // Call the language model with the prompt const result = streamText({ model.chat(), messages: [ { role: 'user', content: `${editInstructions}\n${originalCode}\n${update}` } ], topP: 1, }) // Respond with a streaming response return result.toAIStreamResponse() } ``` ```` ```typescript components/CodeEditor.tsx 'use client' import { useCompletion } from 'ai/react' import { useState } from 'react' export function CodeEditor() { const [originalCode, setOriginalCode] = useState('') const [editInstructions, setEditInstructions] = useState('') const { completion, isLoading, complete } = useCompletion({ api: '/api/morph', }) const handleApplyEdit = async () => { await complete('', { body: { originalCode, editInstructions }, }) } return (