> Discover all available pages from the documentation index: https://mastra.zisheng.pro/ko/llms.txt # Custom model gateways 사용자 지정 Model 게이트웨이를 사용하면 다음을 통해 비공개 또는 특수 LLM Provider 통합을 구현할 수 있습니다: `MastraModelGatewayInterface` interface or the `MastraModelGateway` base class. ## Overview 게이트웨이는 언어 Model에 접근하기 위한 Provider별 로직을 처리합니다: - Provider configuration and model discovery - Authentication and API key management - URL construction for API endpoints - Language model instance creation Create custom gateways to support: - Private or enterprise LLM deployments - Custom authentication schemes - Specialized routing logic - Gateway versioning with unique IDs ## Creating a Custom Gateway Implement `MastraModelGatewayInterface` for a plain object gateway, or extend `MastraModelGateway` when you want base class defaults. ```typescript import { type MastraModelGatewayInterface, type ProviderConfig } from '@mastra/core/llm'; import { createOpenAICompatible } from '@ai-sdk/openai-compatible-v5'; const myPrivateGateway: MastraModelGatewayInterface = { id: 'private', name: 'My Private Gateway', async fetchProviders(): Promise> { return { 'my-provider': { name: 'My Provider', models: ['openai/gpt-5.6-sol'], apiKeyEnvVar: 'MY_API_KEY', gateway: 'private', url: 'https://api.myprovider.com/v1', }, }; }, buildUrl() { return 'https://api.myprovider.com/v1'; }, async getApiKey() { return process.env.MY_API_KEY ?? ''; }, async resolveLanguageModel({ modelId, providerId, apiKey }) { return createOpenAICompatible({ name: providerId, apiKey, baseURL: 'https://api.myprovider.com/v1', }).chatModel(modelId); }, }; ``` The following example extends the `MastraModelGateway` class: ```typescript import { MastraModelGateway, type ProviderConfig } from '@mastra/core/llm'; import { createOpenAICompatible } from '@ai-sdk/openai-compatible-v5'; import type { LanguageModelV2 } from '@ai-sdk/provider-v5'; class MyPrivateGateway extends MastraModelGateway { // Required: Unique identifier for the gateway // This ID is used as the prefix for all providers from this gateway readonly id = 'private'; // Required: Human-readable name readonly name = 'My Private Gateway'; /** * Fetch provider configurations from your gateway * Returns a record of provider configurations */ async fetchProviders(): Promise> { return { 'my-provider': { name: 'My Provider', models: ['openai/gpt-5.6-sol', 'anthropic/claude-sonnet-4-6'], apiKeyEnvVar: 'MY_API_KEY', gateway: this.id, url: 'https://api.myprovider.com/v1', }, }; } /** * Build the API URL for a model * @param modelId - Full model ID (e.g., "private/my-provider/model-1") * @param envVars - Environment variables (optional) */ buildUrl(modelId: string, envVars?: Record): string { return 'https://api.myprovider.com/v1'; } /** * Get the API key for authentication * @param modelId - Full model ID */ async getApiKey(modelId: string): Promise { const apiKey = process.env.MY_API_KEY; if (!apiKey) { throw new Error(`Missing MY_API_KEY environment variable`); } return apiKey; } /** * Create a language model instance * @param args - Model ID, provider ID, and API key */ async resolveLanguageModel({ modelId, providerId, apiKey, }: { modelId: string; providerId: string; apiKey: string; }): Promise { const baseURL = this.buildUrl(`${providerId}/${modelId}`); return createOpenAICompatible({ name: providerId, apiKey, baseURL, supportsStructuredOutputs: true, }).chatModel(modelId); } } ``` ### Gateway-owned authentication Add `resolveAuth` 게이트웨이가 자격 증명 조회를 담당하는 경우에 사용합니다. Mastra는 다음으로 대체하기 전에 이 후크를 사용합니다: `getApiKey()`. ```typescript const myPrivateGateway: MastraModelGatewayInterface = { // ...gateway fields and methods async resolveAuth() { const apiKey = process.env.MY_API_KEY; return apiKey ? { apiKey, source: 'gateway' } : undefined; }, }; ``` ## Registering Custom Gateways ### During Initialization Mastra 인스턴스를 생성할 때 게이트웨이를 레코드로 전달하세요: ```typescript import { Mastra } from '@mastra/core'; const mastra = new Mastra({ gateways: { myGateway: new MyPrivateGateway(), anotherGateway: new AnotherGateway(), }, }); ``` ### After Initialization Add gateways dynamically using `addGateway`: ```typescript const mastra = new Mastra(); // Add with explicit key mastra.addGateway(new MyPrivateGateway(), 'myGateway'); // Add using gateway's ID mastra.addGateway(new MyPrivateGateway()); // Stored with key 'my-private-gateway' (the gateway's id) ``` ## Using Custom Gateways 게이트웨이 ID를 접두사로 사용하여 사용자 지정 게이트웨이의 Model을 참조하세요: ```typescript import { Agent } from '@mastra/core/agent'; const agent = new Agent({ id: 'my-agent', name: 'My Agent', instructions: 'You are a helpful assistant', model: 'private/my-provider/openai/gpt-5.6-sol', // Uses MyPrivateGateway }); mastra.addAgent(agent, 'myAgent'); ``` Agent를 생성하거나 Model을 사용할 때 Mastra의 Model 라우터는 Model ID를 기준으로 적절한 게이트웨이를 자동 선택합니다. 게이트웨이 ID가 접두사 역할을 합니다. 일치하는 사용자 지정 게이트웨이가 없으면 기본 제공 게이트웨이로 대체됩니다. ### TypeScript Autocomplete #### Automatic type generation in development When running in development mode (`MASTRA_DEV=true`), Mastra는 사용자 지정 게이트웨이에 대한 TypeScript 타입을 자동으로 생성합니다. 1. **Set the environment variable**: ```bash export MASTRA_DEV=true ``` 2. **Register your gateways**: ```typescript const mastra = new Mastra({ gateways: { myGateway: new MyPrivateGateway(), }, }); ``` 3. **Types are generated automatically**: - 게이트웨이를 추가하면 Mastra가 GatewayRegistry와 동기화됩니다. - 레지스트리는 사용자 지정 게이트웨이에서 Provider를 가져옵니다. - TypeScript types are regenerated in `~/.cache/mastra/` - IDE가 몇 초 안에 새 타입을 인식합니다. 4. **Autocomplete now works**: ```typescript const agent = new Agent({ model: 'my-gateway-id/my-provider/model-1', // Full autocomplete! }); ``` #### How it works The GatewayRegistry runs an hourly sync that: - Calls `fetchProviders()` on all registered gateways - Generates TypeScript type definitions - 전역 캐시와 프로젝트의 다음 위치 모두에 해당 타입을 기록합니다: `dist/` directory - TypeScript 서버가 변경 사항을 자동으로 인식합니다. > **팁:** 게이트웨이를 처음 추가하면 타입을 생성하는 데 몇 초 정도 걸릴 수 있습니다. 이후 업데이트는 백그라운드에서 매시간 이루어집니다. #### Manual Type Generation Alternatives 개발 모드에서 실행 중이 아니거나 타입을 즉시 업데이트해야 하는 경우: **Option 1: Use type assertion (simplest)** ```typescript const agent = new Agent({ id: 'my-agent', name: 'my-agent', instructions: 'You are a helpful assistant', model: 'private/my-provider/model-1' as any, // Bypass type checking }); ``` **Option 2: Create a custom type union (type-safe)** ```typescript import type { ModelRouterModelId } from '@mastra/core/llm'; // Define your custom model IDs type CustomModelId = | 'private/my-provider/model-1' | 'private/my-provider/model-2' | 'private/my-provider/model-3'; // Combine with built-in models type AllModelIds = ModelRouterModelId | CustomModelId; const agent = new Agent({ id: 'my-agent', name: 'my-agent', instructions: 'You are a helpful assistant', model: 'private/my-provider/model-1' satisfies AllModelIds, }); ``` **Option 3: Extend ModelRouterModelId globally (advanced)** ```typescript // In a types.d.ts file in your project // The import is required: it makes this file a module, so the block below // merges into the existing types instead of replacing the module. import '@mastra/core/llm'; declare module '@mastra/core/llm' { interface ProviderModelsMap { 'my-provider': readonly ['model-1', 'model-2', 'model-3']; } } ``` 이렇게 하면 기본 제공 타입이 확장되어 사용자 지정 Model이 포함되므로 완전한 자동 완성 기능을 사용할 수 있습니다. ## Gateway Management ### getGateway(key) Retrieve a gateway by its registration key: ```typescript const gateway = mastra.getGateway('myGateway'); console.log(gateway.name); // 'My Private Gateway' ``` ### getGatewayById(id) Retrieve a gateway by its unique ID: ```typescript const gateway = mastra.getGatewayById('my-private-gateway'); console.log(gateway.name); // 'My Private Gateway' ``` This is useful when: - Gateway에 등록 키와 다른 명시적 ID가 있는 경우 - 서로 다른 인스턴스에서 ID로 Gateway를 찾아야 하는 경우 - Supporting gateway versioning (e.g., `'gateway-v1'`, `'gateway-v2'`) ### listGateways() Get all registered gateways: ```typescript const gateways = mastra.listGateways(); console.log(Object.keys(gateways)); // ['myGateway', 'anotherGateway'] ``` ## Gateway Properties ### Required | Property | Type | Description | | -------- | -------- | ------------------------------------------------- | | `id` | `string` | Gateway의 고유 식별자이며, Model 문자열에서 Gateway 접두사로 사용됩니다 | | `name` | `string` | Human-readable gateway name | ### Methods | Method | Description | | ----------------------------- | --------------------------------------- | | `fetchProviders()` | Fetch provider configurations | | `buildUrl(modelId, envVars?)` | Build API URL for a model | | `getApiKey(modelId)` | Get API key for authentication | | `resolveLanguageModel(args)` | Create language model instance | | `getId()` | Get gateway ID (returns `id` or `name`) | ## Provider Configuration The `fetchProviders()` method returns a record of `ProviderConfig` objects: ```typescript interface ProviderConfig { name: string; // Display name models: string[]; // Available model IDs apiKeyEnvVar: string | string[]; // Environment variable(s) for API key gateway: string; // Gateway identifier url?: string; // Optional API base URL apiKeyHeader?: string; // Optional custom auth header docUrl?: string; // Optional documentation URL } ``` ## Gateway IDs vs Keys Understanding the distinction: - **Key**: Mastra에 Gateway를 추가할 때 사용하는 등록 키(레코드 키) - **ID**: The gateway's unique identifier (via `id` property or `name` if not set) ```typescript class VersionedGateway extends MastraModelGateway { readonly id = 'my-gateway-v2'; // Unique ID for versioning and prefixing readonly name = 'My Gateway'; // Display name } const mastra = new Mastra({ gateways: { currentGateway: new VersionedGateway(), // Key: 'currentGateway' }, }); // Retrieve by key const byKey = mastra.getGateway('currentGateway'); // Retrieve by ID const byId = mastra.getGatewayById('my-gateway-v2'); // Both return the same gateway console.log(byKey === byId); // true ``` ## Model ID Format 사용자 지정 Gateway를 통해 액세스하는 Model은 다음 형식을 따릅니다: ```text [gatewayId]/[provider]/[model] ``` Examples: - `private/my-provider/model-1` ## Advanced example Token-based gateway with caching: ```typescript class TokenGateway extends MastraModelGateway { readonly id = 'token-gateway-v1'; readonly name = 'Token Gateway'; private tokenCache: Map = new Map(); async fetchProviders(): Promise> { const response = await fetch('https://api.gateway.com/providers'); const data = await response.json(); return { provider: { name: data.name, models: data.models, apiKeyEnvVar: 'GATEWAY_TOKEN', gateway: this.id, }, }; } async buildUrl(modelId: string, envVars?: Record): Promise { const token = await this.getApiKey(modelId); const siteId = envVars?.SITE_ID || process.env.SITE_ID; const response = await fetch(`https://api.gateway.com/sites/${siteId}/token`, { headers: { Authorization: `Bearer ${token}` }, }); const { url } = await response.json(); return url; } async getApiKey(modelId: string): Promise { const cached = this.tokenCache.get(modelId); if (cached && cached.expiresAt > Date.now()) { return cached.token; } const token = process.env.GATEWAY_TOKEN; if (!token) { throw new Error('Missing GATEWAY_TOKEN'); } // Cache token for 1 hour this.tokenCache.set(modelId, { token, expiresAt: Date.now() + 3600000, }); return token; } async resolveLanguageModel({ modelId, providerId, apiKey }: { modelId: string; providerId: string; apiKey: string; }): Promise { const baseURL = await this.buildUrl(`${providerId}/${modelId}`); return createOpenAICompatible({ name: providerId, apiKey, baseURL, supportsStructuredOutputs: true, }).chatModel(modelId); } } ``` ## Error handling Provide descriptive errors for common failure scenarios: ```typescript class RobustGateway extends MastraModelGateway { // ... properties async getApiKey(modelId: string): Promise { const apiKey = process.env.MY_API_KEY; if (!apiKey) { throw new Error( `Missing MY_API_KEY environment variable for model: ${modelId}. ` + `Please set MY_API_KEY in your environment.` ); } return apiKey; } async buildUrl(modelId: string, envVars?: Record): Promise { const baseUrl = envVars?.BASE_URL || process.env.BASE_URL; if (!baseUrl) { throw new Error( `No base URL configured for model: ${modelId}. ` + `Set BASE_URL environment variable or pass it in envVars.` ); } return baseUrl; } } ``` ## Testing Custom Gateways Example test structure: ```typescript import { describe, it, expect, beforeEach } from 'vitest'; import { Mastra } from '@mastra/core'; describe('MyPrivateGateway', () => { beforeEach(() => { process.env.MY_API_KEY = 'test-key'; }); it('should fetch providers', async () => { const gateway = new MyPrivateGateway(); const providers = await gateway.fetchProviders(); expect(providers['my-provider']).toBeDefined(); expect(providers['my-provider'].models).toContain('model-1'); }); it('should integrate with Mastra', () => { const mastra = new Mastra({ gateways: { private: new MyPrivateGateway(), }, }); const gateway = mastra.getGateway('private'); expect(gateway.name).toBe('My Private Gateway'); }); it('should resolve models by ID', () => { const mastra = new Mastra({ gateways: { key: new MyPrivateGateway(), }, }); const gateway = mastra.getGatewayById('my-private-gateway'); expect(gateway).toBeDefined(); }); }); ``` ## Best practices 1. **Use descriptive IDs for versioning**: Set explicit `id` Gateway의 버전을 관리해야 할 때 사용하는 값 ```typescript readonly id = 'my-gateway-v1'; ``` 2. **Implement proper error handling**: Throw descriptive errors with actionable messages 3. **Cache expensive operations**: 적절한 경우 토큰, URL 또는 Provider 구성을 캐시하세요 4. **Validate environment variables**: Check for required environment variables in `getApiKey` and `buildUrl` 5. **Document your gateway**: Gateway의 용도와 구성을 설명하는 JSDoc 주석을 추가하세요 6. **Follow naming conventions**: Provider와 Model에 명확하고 일관된 이름을 사용하세요 7. **Handle async operations**: Use `async/await` for network requests and I/O operations 8. **Test thoroughly**: Write unit tests for all gateway methods ## Showing only custom gateways in Studio By default, **Studio** 에는 등록한 모든 사용자 지정 Gateway와 함께 모든 외부 Model Provider(예: OpenAI, Anthropic, Gemini)가 나열됩니다. 외부 Provider를 숨기려면 `AUTO_BLOCK_EXTERNAL_PROVIDERS` environment variable: ```bash AUTO_BLOCK_EXTERNAL_PROVIDERS=true ``` When this variable is set to `true` or `1`로 설정하면 Mastra는 직접 등록한 Gateway의 Provider만 반환합니다. 정적 Provider 레지스트리와 기본 제공 Gateway(`models.dev`, `netlify`, and `mastra`)는 Model 선택기에서 숨겨집니다. 모든 Model 트래픽을 하나의 비공개 Gateway를 통해 라우팅하고 다른 Provider가 표시되지 않도록 하려는 경우 유용합니다. 이 변수가 설정되어 있고 등록된 사용자 지정 Gateway가 없으면 Model 선택기가 비어 있습니다. Model을 표시하려면 사용자 지정 Gateway를 하나 이상 등록하세요. ## Built-in Gateways Mastra includes built-in gateways as reference implementations: - **NetlifyGateway**: Netlify AI Gateway integration with token exchange - **ModelsDevGateway**: Registry of OpenAI-compatible providers from models.dev See [Netlify](https://mastra.zisheng.pro/ko/models/gateways/netlify), [OpenRouter](https://mastra.zisheng.pro/ko/models/gateways/openrouter), and [Vercel](https://mastra.zisheng.pro/ko/models/gateways/vercel) for examples of gateway usage.