UNPKG

mastra-af-letta

Version:

Letta .af (Agent File) format support for Mastra - enables importing and exporting agents in Letta's portable format

415 lines (410 loc) 14.1 kB
import { z } from 'zod'; /** * mastra-af-letta * Letta .af (Agent File) format support for Mastra * @license MIT */ var iso8601Schema = z.string().datetime({ message: "Timestamp must be in ISO 8601 format (e.g., 2024-01-01T00:00:00Z)" }); var messageRoleSchema = z.enum(["user", "assistant", "system", "tool"], { errorMap: () => ({ message: "Role must be one of: user, assistant, system, tool" }) }); var toolTypeSchema = z.enum(["python", "javascript", "json_schema"], { errorMap: () => ({ message: "Tool type must be one of: python, javascript, json_schema" }) }); var toolRuleTypeSchema = z.string().min(1, "Rule type is required"); var llmConfigSchema = z.object({ provider: z.string().min(1, "Provider is required"), model: z.string().min(1, "Model is required"), temperature: z.number().min(0, "Temperature must be >= 0").max(2, "Temperature must be <= 2").optional(), max_tokens: z.number().positive("Max tokens must be positive").optional(), top_p: z.number().min(0, "Top-p must be >= 0").max(1, "Top-p must be <= 1").optional(), frequency_penalty: z.number().min(-2, "Frequency penalty must be >= -2").max(2, "Frequency penalty must be <= 2").optional(), presence_penalty: z.number().min(-2, "Presence penalty must be >= -2").max(2, "Presence penalty must be <= 2").optional() }).passthrough().describe("Language model configuration"); var embeddingConfigSchema = z.object({ provider: z.string().min(1, "Provider is required"), model: z.string().min(1, "Model is required"), dimensions: z.number().positive("Dimensions must be positive").optional() }).passthrough().describe("Embedding model configuration"); var coreMemoryBlockSchema = z.object({ label: z.string().min(1, "Memory block label is required"), value: z.string(), character_limit: z.number().positive("Character limit must be positive").optional(), metadata: z.record(z.unknown()).optional() }).describe("Core memory block"); var toolCallSchema = z.object({ id: z.string().min(1, "Tool call ID is required"), name: z.string().min(1, "Tool name is required"), arguments: z.record(z.unknown()), metadata: z.record(z.unknown()).optional() }).describe("Tool invocation request"); var toolResultSchema = z.object({ id: z.string().min(1, "Tool result ID is required"), name: z.string().min(1, "Tool name is required"), result: z.unknown().optional(), error: z.string().optional(), metadata: z.record(z.unknown()).optional() }).describe("Tool execution result"); var messageSchema = z.object({ id: z.string().min(1, "Message ID is required"), role: messageRoleSchema, text: z.string(), timestamp: iso8601Schema, tool_calls: z.array(toolCallSchema).optional(), tool_results: z.array(toolResultSchema).optional(), metadata: z.record(z.unknown()).optional() }).describe("Conversation message"); var parameterPropertySchema = z.lazy( () => z.object({ type: z.string().min(1, "Parameter type is required"), description: z.string().optional(), enum: z.array(z.unknown()).optional(), items: parameterPropertySchema.optional(), properties: z.record(parameterPropertySchema).optional() }).passthrough().describe("Parameter property definition") ); var toolParametersSchema = z.object({ type: z.literal("object", { errorMap: () => ({ message: 'Tool parameters must have type "object"' }) }), properties: z.record(parameterPropertySchema), required: z.array(z.string()).optional(), additionalProperties: z.boolean().optional() }).describe("Tool parameter schema"); var authReferenceSchema = z.object({ provider: z.enum(["env", "vault", "oauth2", "keychain", "dynamic"], { errorMap: () => ({ message: "Auth provider must be one of: env, vault, oauth2, keychain, dynamic" }) }), config_id: z.string().min(1, "Configuration ID is required"), metadata: z.object({ auth_type: z.enum(["bearer", "api_key", "oauth2", "basic", "custom"]).optional(), required_scopes: z.array(z.string()).optional(), expires_in: z.number().positive("Expiration must be positive").optional(), prompt: z.string().optional(), cache_duration: z.number().nonnegative("Cache duration must be non-negative").optional() }).optional() }).describe("Authentication reference"); var mastraToolMetadataSchema = z.object({ type: z.enum(["mcp", "url", "reference"], { errorMap: () => ({ message: "Mastra tool type must be one of: mcp, url, reference" }) }), server: z.string().url("Server must be a valid URL").optional(), tool_name: z.string().optional(), transport: z.enum(["stdio", "http"]).optional(), endpoint: z.string().url("Endpoint must be a valid URL").optional(), method: z.enum(["GET", "POST"]).optional(), auth_ref: authReferenceSchema.optional() }).refine( (data) => { if (data.type === "mcp") { return !!data.server && !!data.tool_name; } if (data.type === "url") { return !!data.endpoint; } return true; }, { message: "MCP tools require server and tool_name, URL tools require endpoint" } ).describe("Mastra tool metadata"); var toolSchema = z.object({ name: z.string().min(1, "Tool name is required"), description: z.string().min(1, "Tool description is required"), type: toolTypeSchema, parameters: toolParametersSchema, source_code: z.string().optional(), metadata: z.record(z.unknown()).optional().refine( (metadata) => { if (metadata && "_mastra_tool" in metadata) { return mastraToolMetadataSchema.safeParse(metadata._mastra_tool).success; } return true; }, { message: "Invalid _mastra_tool metadata structure" } ) }).refine( (tool) => { if ((tool.type === "python" || tool.type === "javascript") && !tool.source_code) { return false; } return true; }, { message: "Source code is required for python and javascript tool types", path: ["source_code"] } ).describe("Tool definition"); var toolRuleSchema = z.object({ tool_name: z.string().min(1, "Tool name is required"), rule_type: toolRuleTypeSchema, rule_content: z.string().min(1, "Rule content is required") }).describe("Tool usage rule"); var afAgentSchema = z.object({ // Core identification agent_type: z.string().min(1, "Agent type is required"), name: z.string().min(1, "Agent name is required"), description: z.string().optional(), // System configuration system: z.string().min(1, "System prompt is required"), // Model configuration llm_config: llmConfigSchema, embedding_config: embeddingConfigSchema.optional(), // Memory components - object with named memory blocks core_memory: z.record(coreMemoryBlockSchema).refine( (memory) => memory.persona && memory.human, "Core memory must contain at least persona and human blocks" ), messages: z.array(messageSchema), in_context_message_indices: z.array(z.number().nonnegative("Message index must be non-negative")).optional(), // Tools tools: z.array(toolSchema), tool_rules: z.array(toolRuleSchema).optional(), tool_exec_environment_variables: z.record(z.string()).optional(), // Metadata tags: z.array(z.string()).optional(), metadata_: z.record(z.unknown()).optional(), // Versioning version: z.string().min(1, "Version is required"), created_at: iso8601Schema, updated_at: iso8601Schema }).refine( (agent) => { if (agent.in_context_message_indices) { const maxIndex = agent.messages.length - 1; return agent.in_context_message_indices.every((idx) => idx <= maxIndex); } return true; }, { message: "in_context_message_indices contains out-of-range message references", path: ["in_context_message_indices"] } ).refine( (agent) => { if (agent.tool_rules) { const toolNames = new Set(agent.tools.map((t) => t.name)); return agent.tool_rules.every((rule) => toolNames.has(rule.tool_name)); } return true; }, { message: "tool_rules references non-existent tools", path: ["tool_rules"] } ).describe("Complete agent file schema"); function isValidAfSchema(value) { return afAgentSchema.safeParse(value).success; } function parseAfSchema(data) { try { return afAgentSchema.parse(data); } catch (error) { if (error instanceof z.ZodError) { const enhancedError = new Error("Agent file validation failed"); enhancedError.validationErrors = error.errors.map((err) => ({ path: err.path.join("."), message: err.message, code: err.code })); throw enhancedError; } throw error; } } function safeParseAfSchema(data) { return afAgentSchema.safeParse(data); } // src/parser.ts var AgentFileParseError = class _AgentFileParseError extends Error { constructor(message, options) { super(message); this.name = "AgentFileParseError"; this.cause = options?.cause; this.validationErrors = options?.validationErrors; Object.setPrototypeOf(this, _AgentFileParseError.prototype); } }; function parseAgentFile(jsonString, options = {}) { const { maxSize = 52428800, autoFix = true } = options; const byteSize = new TextEncoder().encode(jsonString).length; if (byteSize > maxSize) { throw new AgentFileParseError( `Agent file too large: ${byteSize} bytes (max: ${maxSize} bytes)` ); } let data; try { data = JSON.parse(jsonString); } catch (error) { throw new AgentFileParseError("Invalid JSON format", { cause: error }); } if (autoFix) { data = applyAutoFixes(data); } try { return parseAfSchema(data); } catch (error) { if (error instanceof Error && "validationErrors" in error) { throw new AgentFileParseError("Schema validation failed", { validationErrors: error.validationErrors, cause: error }); } throw new AgentFileParseError("Unexpected validation error", { cause: error }); } } function safeParseAgentFile(jsonString, options = {}) { try { const data = parseAgentFile(jsonString, options); return { success: true, data }; } catch (error) { if (error instanceof AgentFileParseError) { return { success: false, error }; } return { success: false, error: new AgentFileParseError("Unknown parsing error", { cause: error }) }; } } function parseAgentFileObject(data, options = {}) { const { autoFix = true } = options; if (autoFix) { data = applyAutoFixes(data); } try { return parseAfSchema(data); } catch (error) { if (error instanceof Error && "validationErrors" in error) { throw new AgentFileParseError("Schema validation failed", { validationErrors: error.validationErrors, cause: error }); } throw new AgentFileParseError("Unexpected validation error", { cause: error }); } } function isValidAgentFile(jsonString) { try { const data = JSON.parse(jsonString); return safeParseAfSchema(data).success; } catch { return false; } } function getValidationErrors(jsonString) { try { const data = JSON.parse(jsonString); const result = safeParseAfSchema(data); if (result.success) { return null; } return result.error.errors.map((err) => ({ path: err.path.join("."), message: err.message })); } catch (error) { return [ { path: "", message: error instanceof Error ? error.message : "Invalid JSON" } ]; } } function applyAutoFixes(data) { if (!data || typeof data !== "object") { return data; } const fixed = { ...data }; const now = (/* @__PURE__ */ new Date()).toISOString(); if (!fixed.created_at) { fixed.created_at = now; } if (!fixed.updated_at) { fixed.updated_at = now; } if (!fixed.version) { fixed.version = "0.1.0"; } if (!fixed.core_memory || typeof fixed.core_memory !== "object" || Array.isArray(fixed.core_memory)) { fixed.core_memory = { persona: { label: "persona", value: "I am a helpful AI assistant.", limit: 2e3 }, human: { label: "human", value: "The user needs assistance.", limit: 2e3 } }; } if (!Array.isArray(fixed.messages)) { fixed.messages = []; } if (!Array.isArray(fixed.tools)) { fixed.tools = []; } if (Array.isArray(fixed.messages)) { fixed.messages = fixed.messages.map((msg, index) => { if (!msg.timestamp) { const msgTime = new Date(now); msgTime.setMinutes(msgTime.getMinutes() - (fixed.messages.length - index)); return { ...msg, timestamp: msgTime.toISOString() }; } return msg; }); } if (Array.isArray(fixed.tools)) { fixed.tools = fixed.tools.map((tool) => { if (tool.parameters && typeof tool.parameters === "object") { if (!tool.parameters.type) { tool.parameters.type = "object"; } if (!tool.parameters.properties) { tool.parameters.properties = {}; } } return tool; }); } return fixed; } function extractAgentMetadata(jsonString) { try { const data = JSON.parse(jsonString); if (!data || typeof data !== "object") { return null; } return { name: data.name, description: data.description, version: data.version, agent_type: data.agent_type, created_at: data.created_at, tags: Array.isArray(data.tags) ? data.tags : void 0 }; } catch { return null; } } // src/index.ts var SUPPORTED_AF_VERSION = "0.1.0"; var PACKAGE_NAME = "mastra-af-letta"; var PACKAGE_VERSION = "0.1.0"; export { AgentFileParseError, PACKAGE_NAME, PACKAGE_VERSION, SUPPORTED_AF_VERSION, afAgentSchema, authReferenceSchema, coreMemoryBlockSchema, embeddingConfigSchema, extractAgentMetadata, getValidationErrors, isValidAfSchema, isValidAgentFile, llmConfigSchema, mastraToolMetadataSchema, messageSchema, parseAfSchema, parseAgentFile, parseAgentFileObject, safeParseAfSchema, safeParseAgentFile, toolCallSchema, toolParametersSchema, toolResultSchema, toolRuleSchema, toolSchema }; //# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map