mastra-af-letta
Version:
Letta .af (Agent File) format support for Mastra - enables importing and exporting agents in Letta's portable format
393 lines (303 loc) • 10.5 kB
Markdown
# mastra-af-letta
An npm package that enables seamless portability of AI agents between [Mastra.ai](https://mastra.ai) and [Letta](https://github.com/letta-ai/letta) (formerly MemGPT) through the .af (Agent File) format.
## Overview
The Agent File (.af) format is an open standard introduced by [Letta](https://github.com/letta-ai/letta) (formerly MemGPT) for serializing AI agents into portable JSON files. This package provides:
- **Import**: Parse and validate .af files to create Mastra agents
- **Export**: Serialize Mastra agents to .af format
- **Type Safety**: Full TypeScript types and Zod schemas
- **Validation**: Comprehensive error messages for debugging
- **MCP Support**: Extended support for Model Context Protocol tools
- **Secure Auth**: Authentication references without embedded credentials
## Installation
```bash
npm install mastra-af-letta
# or
pnpm add mastra-af-letta
# or
yarn add mastra-af-letta
```
**Note**: This package requires `@mastra/core` as a peer dependency. Make sure you have Mastra installed:
```bash
npm install @mastra/core
```
## Quick Start
### Core .af Format Support
```typescript
import { parseAgentFile, isValidAgentFile, afAgentSchema } from 'mastra-af-letta';
import { readFileSync } from 'fs';
// 1. Parse and validate an .af file
const afContent = readFileSync('./agent.af', 'utf-8');
const afData = parseAgentFile(afContent);
// 2. Work with the parsed agent data
console.log(`Agent: ${afData.name}`);
console.log(`Tools: ${afData.tools.map(t => t.name).join(', ')}`);
// 3. Validate agent files
if (isValidAgentFile(afContent)) {
console.log('Valid agent file!');
}
```
> **Note**: Mastra.ai integration (import/export functions) will be available in a future version once the correct Mastra interfaces are finalized.
### Parsing an Agent File
```typescript
import { parseAgentFile } from 'mastra-af-letta';
import { readFileSync } from 'fs';
// Parse an .af file
const agentJson = readFileSync('./my-agent.af', 'utf-8');
const agentData = parseAgentFile(agentJson);
console.log(`Loaded agent: ${agentData.name}`);
console.log(`Tools: ${agentData.tools.map(t => t.name).join(', ')}`);
```
### Safe Parsing with Error Handling
```typescript
import { safeParseAgentFile } from 'mastra-af-letta';
const result = safeParseAgentFile(agentJson);
if (result.success) {
console.log(`Agent: ${result.data.name}`);
} else {
console.error('Parse failed:', result.error.message);
if (result.error.validationErrors) {
result.error.validationErrors.forEach(err => {
console.error(` ${err.path}: ${err.message}`);
});
}
}
```
### Validating Agent Files
```typescript
import { isValidAgentFile, getValidationErrors } from 'mastra-af-letta';
// Quick validation
if (isValidAgentFile(agentJson)) {
console.log('Agent file is valid');
}
// Get detailed errors
const errors = getValidationErrors(agentJson);
if (errors) {
errors.forEach(err => {
console.error(`${err.path}: ${err.message}`);
});
}
```
### Working with TypeScript Types
```typescript
import type { AfAgentSchema, AfTool, AfMessage } from 'mastra-af-letta';
// Type-safe agent manipulation
function addTool(agent: AfAgentSchema, tool: AfTool): AfAgentSchema {
return {
...agent,
tools: [...agent.tools, tool],
updated_at: new Date().toISOString(),
};
}
// Type-safe message creation
const message: AfMessage = {
id: crypto.randomUUID(),
role: 'user',
text: 'Hello, assistant!',
timestamp: new Date().toISOString(),
};
```
### Using Zod Schemas Directly
```typescript
import { afAgentSchema, toolSchema } from 'mastra-af-letta';
// Validate partial data
const toolResult = toolSchema.safeParse({
name: 'calculator',
description: 'Perform calculations',
type: 'python',
parameters: {
type: 'object',
properties: {
expression: {
type: 'string',
description: 'Math expression to evaluate',
},
},
required: ['expression'],
},
source_code: 'def calculate(expression: str): return eval(expression)',
});
if (toolResult.success) {
console.log('Valid tool:', toolResult.data.name);
}
```
## MCP Tool Support
This package extends the .af format to support MCP (Model Context Protocol) tools and secure authentication through metadata fields.
### Defining MCP Tools
```typescript
const mcpTool: AfTool = {
name: 'github_search',
description: 'Search GitHub repositories',
type: 'json_schema',
parameters: {
type: 'object',
properties: {
query: { type: 'string' }
},
required: ['query']
},
metadata: {
_mastra_tool: {
type: 'mcp',
server: 'https://mcp-github.example.com',
tool_name: 'search',
transport: 'http',
auth_ref: {
provider: 'env',
config_id: 'GITHUB_TOKEN',
metadata: {
auth_type: 'bearer'
}
}
}
}
};
```
### Authentication References
Never store credentials in .af files. Instead, use authentication references:
```typescript
// Environment variable reference
auth_ref: {
provider: 'env',
config_id: 'API_KEY'
}
// Vault reference
auth_ref: {
provider: 'vault',
config_id: 'secret/api-keys/service'
}
// OAuth2 reference
auth_ref: {
provider: 'oauth2',
config_id: 'github_oauth',
metadata: {
required_scopes: ['repo', 'read:user']
}
}
```
### URL-Based Tools
```typescript
const urlTool: AfTool = {
name: 'webhook',
type: 'json_schema',
parameters: { /* ... */ },
metadata: {
_mastra_tool: {
type: 'url',
endpoint: 'https://api.example.com/webhook',
method: 'POST',
auth_ref: {
provider: 'env',
config_id: 'WEBHOOK_TOKEN'
}
}
}
};
```
## API Reference
### Parser Functions
#### `parseAgentFile(jsonString, options?)`
Parse and validate an .af file from a JSON string.
- **Throws**: `AgentFileParseError` on invalid input
- **Options**:
- `maxSize`: Maximum file size in bytes (default: 50MB)
- `autoFix`: Apply automatic fixes for common issues (default: true)
- `strict`: Strict validation mode (default: false)
#### `safeParseAgentFile(jsonString, options?)`
Parse an .af file with a result object (never throws).
- **Returns**: `{ success: true, data: AfAgentSchema } | { success: false, error: AgentFileParseError }`
#### `parseAgentFileObject(data, options?)`
Parse an already-parsed JSON object.
#### `isValidAgentFile(jsonString)`
Quick validation check.
- **Returns**: `boolean`
#### `getValidationErrors(jsonString)`
Get detailed validation errors.
- **Returns**: `Array<{ path: string, message: string }> | null`
#### `extractAgentMetadata(jsonString)`
Extract basic metadata without full validation.
- **Returns**: Partial agent metadata or null
### Schema Exports
All Zod schemas are exported for direct use:
- `afAgentSchema` - Complete agent file schema
- `llmConfigSchema` - Language model configuration
- `embeddingConfigSchema` - Embedding configuration
- `coreMemoryBlockSchema` - Core memory blocks
- `messageSchema` - Conversation messages
- `toolSchema` - Tool definitions
- `toolRuleSchema` - Tool usage rules
- `toolCallSchema` - Tool invocations
- `toolResultSchema` - Tool results
- `toolParametersSchema` - Tool parameter schemas
### Type Exports
All TypeScript interfaces are exported:
- `AfAgentSchema` - Main agent file structure
- `AfLLMConfig` - LLM configuration
- `AfEmbeddingConfig` - Embedding configuration
- `AfCoreMemoryBlock` - Core memory block
- `AfMessage` - Message with tool calls
- `AfTool` - Tool definition
- `AfToolRule` - Tool usage rule
- `AfToolCall` - Tool invocation
- `AfToolResult` - Tool execution result
- `AfToolParameters` - Tool parameter schema
- `AfParameterProperty` - Individual parameter
- `MastraToolMetadata` - MCP and external tool metadata
- `AuthReference` - Secure authentication reference
## Auto-Fix Features
The parser can automatically fix common issues:
1. **Missing timestamps**: Adds current time for `created_at` and `updated_at`
2. **Missing version**: Defaults to "0.1.0"
3. **Empty arrays**: Initializes `core_memory`, `messages`, and `tools` as empty arrays
4. **Message timestamps**: Generates reasonable timestamps for messages without them
5. **Tool parameters**: Ensures proper structure with `type: "object"` and `properties`
Disable auto-fix with `{ autoFix: false }` in parse options.
## Error Handling
The `AgentFileParseError` class provides detailed error information:
```typescript
try {
const agent = parseAgentFile(json);
} catch (error) {
if (error instanceof AgentFileParseError) {
console.error('Parse error:', error.message);
// Check for validation errors
if (error.validationErrors) {
error.validationErrors.forEach(err => {
console.error(` ${err.path}: ${err.message}`);
});
}
// Access original error
if (error.cause) {
console.error('Caused by:', error.cause.message);
}
}
}
```
## Validation Rules
The parser enforces these validation rules:
1. **Required fields**: `agent_type`, `name`, `system`, `llm_config`, `version`, timestamps
2. **Tool source code**: Required for `python` and `javascript` tool types
3. **Message indices**: `in_context_message_indices` must reference valid message positions
4. **Tool rules**: Must reference existing tools
5. **Timestamps**: Must be in ISO 8601 format
6. **Parameter schemas**: Must follow JSON Schema specification
## Requirements
- Node.js 18+
- @mastra/core (peer dependency)
- TypeScript 5.0+ (for TypeScript projects)
## How It Works
This package acts as a bridge between Mastra's agent system and Letta's .af format:
1. **Import**: Converts .af files to Mastra's `AgentConfig` format
2. **Export**: Converts Mastra agents back to .af format
3. **Validation**: Ensures data integrity during conversion
4. **Type Safety**: Provides full TypeScript support
### Limitations
- Dynamic instructions and tools (functions) are converted to static values during export
- Some Mastra-specific features may not have direct .af equivalents
- Tool rules from .af files are not directly supported in Mastra
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
MIT - See [LICENSE](./LICENSE) for details.
## Related Projects
- [Mastra](https://github.com/mastra-ai/mastra) - The AI framework this package extends
- [Letta](https://github.com/letta-ai/letta) - The source of the .af format