DEV Community

Cover image for Building a Message-to-SQL AI Agent with Mastra and Telex.im
Ugochukwu Nebolisa
Ugochukwu Nebolisa

Posted on

Building a Message-to-SQL AI Agent with Mastra and Telex.im

Introduction

As developers, we spend a significant amount of time writing SQL queries. Whether it's a simple SELECT statement or a complex JOIN with multiple aggregations, remembering the exact syntax can be tedious. What if you could just describe what you want in plain English and get production-ready SQL?

That's exactly what I built for the HNG Stage 3 Backend Task - a Message-to-SQL AI Agent that translates natural language into SQL queries using Mastra AI and integrated with Telex.im.

The Problem

Every developer faces these challenges:

  1. Syntax Complexity: SQL has different dialects (PostgreSQL, MySQL, SQLite, etc.) with subtle differences
  2. Best Practices: It's easy to write working SQL that performs poorly or has security issues
  3. Context Switching: Moving between thinking about business logic and remembering SQL syntax breaks flow
  4. Security: SQL injection vulnerabilities are still one of the most common security issues

The Solution

I built an AI agent that:

  • Converts natural language to SQL queries
  • Validates syntax and suggests best practices
  • Explains complex queries in plain English
  • Optimizes queries for better performance
  • Works with multiple SQL dialects
  • Integrates seamlessly with Telex.im for team collaboration

Technical Architecture

Tech Stack

  • Framework: Mastra AI - A powerful TypeScript framework for building AI agents
  • LLM: Grok llama-3.1-8b-instant for natural language understanding
  • Integration Platform: Telex.im using A2A protocol
  • Language: TypeScript with Node.js
  • Storage: LibSQL for agent memory and observability

Why Mastra?

Mastra made this project straightforward because it provides:

  1. Built-in Agent Framework: No need to build from scratch
  2. Tool System: Easy to create specialized tools for SQL operations
  3. Workflow Management: Clean way to orchestrate multi-step processes
  4. Memory & Context: Built-in conversation memory
  5. Observability: Out-of-the-box tracing and monitoring
  6. Scoring System: Quality evaluation for agent outputs

Building the Agent

Step 1: Project Setup

First, I initialized the project with Mastra:

npm create mastra@latest -y
Enter fullscreen mode Exit fullscreen mode

The project structure:

src/mastra/
├── agents/
│   └── sql-agent.ts       # Main agent definition
├── tools/
│   └── sql-tool.ts        # SQL tools
├── scorers/
│   └── sql-scorer.ts      # Quality evaluation
├── workflows/
│   └── sql-workflow.ts    # Workflow orchestration
└── index.ts               # Mastra configuration
Enter fullscreen mode Exit fullscreen mode

Step 2: Creating SQL Tools

I built four specialized tools to enhance the agent's capabilities:

1. SQL Validator Tool

export const sqlValidatorTool = createTool({
  id: "sql-validator",
  description: "Validates and formats SQL queries",
  inputSchema: z.object({
    sql: z.string(),
    dialect: z
      .enum(["postgresql", "mysql", "sqlite", "mssql", "oracle"])
      .optional(),
  }),
  outputSchema: z.object({
    isValid: z.boolean(),
    formatted: z.string(),
    warnings: z.array(z.string()),
    suggestions: z.array(z.string()),
  }),
  execute: async ({ context }) => {
    return validateSQL(context.sql, context.dialect || "postgresql");
  },
});
Enter fullscreen mode Exit fullscreen mode

This tool checks for:

  • SQL syntax correctness
  • Dangerous patterns (missing WHERE in UPDATE/DELETE)
  • Best practice violations (SELECT *)
  • Security vulnerabilities

2. Schema Info Tool

Provides common database patterns and examples:

export const schemaInfoTool = createTool({
  id: "schema-info",
  description: "Provides common database schema patterns",
  inputSchema: z.object({
    tableType: z.string(),
  }),
  outputSchema: z.object({
    commonColumns: z.array(z.string()),
    relationships: z.array(z.string()),
    examples: z.array(z.string()),
  }),
  execute: async ({ context }) => {
    return getSchemaInfo(context.tableType);
  },
});
Enter fullscreen mode Exit fullscreen mode

3. SQL Explainer Tool

Breaks down complex queries into understandable components:

export const sqlExplainerTool = createTool({
  id: "sql-explainer",
  description: "Explains what a SQL query does in plain English",
  inputSchema: z.object({
    sql: z.string(),
  }),
  outputSchema: z.object({
    explanation: z.string(),
    components: z.array(
      z.object({
        part: z.string(),
        description: z.string(),
      })
    ),
  }),
  execute: async ({ context }) => {
    return explainSQL(context.sql);
  },
});
Enter fullscreen mode Exit fullscreen mode

4. SQL Optimizer Tool

Suggests performance improvements:

export const sqlOptimizerTool = createTool({
  id: "sql-optimizer",
  description: "Suggests optimizations for SQL queries",
  // ... implementation
});
Enter fullscreen mode Exit fullscreen mode

Step 3: Defining the Agent

The agent ties everything together with clear instructions:

export const sqlAgent = new Agent({
  name: "SQL Generator Agent",
  instructions: `
You are an expert SQL assistant that helps developers translate 
natural language queries into SQL statements.

Guidelines:
- Ask for clarification on table/column names if not specified
- Default to PostgreSQL syntax unless specified
- Use explicit JOIN syntax
- Avoid SELECT * in production queries
- Include security warnings for dangerous patterns
- Format with proper indentation
  `,
  model: "openai/gpt-4o-mini",
  tools: {
    sqlValidatorTool,
    schemaInfoTool,
    sqlExplainerTool,
    sqlOptimizerTool,
  },
  scorers: {
    sqlCorrectness: {
      /* ... */
    },
    intentMatch: {
      /* ... */
    },
    readability: {
      /* ... */
    },
  },
  memory: new Memory({
    storage: new LibSQLStore({ url: "file:../mastra.db" }),
  }),
});
Enter fullscreen mode Exit fullscreen mode

Step 4: Quality Scoring

I implemented three scorers to ensure high-quality outputs:

SQL Correctness Scorer

Uses groq/llama-3.1-8b-instant as a judge to evaluate:

  • Syntax correctness
  • Best practices adherence
  • Security issues
export const sqlCorrectnessScorer = createScorer({
  name: "SQL Correctness",
  type: "agent",
  judge: {
    model: "groq/llama-3.1-8b-instant",
    instructions: "Evaluate SQL for syntax, best practices, and security...",
  },
})
  .preprocess(({ run }) => {
    /* Extract SQL */
  })
  .analyze({
    /* Analyze quality */
  })
  .generateScore(({ results }) => {
    /* Calculate score */
  })
  .generateReason(({ results, score }) => {
    /* Explain score */
  });
Enter fullscreen mode Exit fullscreen mode

Intent Match Scorer

Ensures the generated SQL matches what the user actually wanted:

export const intentMatchScorer = createScorer({
  name: "Intent Match",
  // Checks if SELECT query was generated for retrieval intent, etc.
});
Enter fullscreen mode Exit fullscreen mode

Readability Scorer

Evaluates formatting and documentation:

export const readabilityScorer = createScorer({
  name: "SQL Readability",
  // Checks formatting, indentation, comments
});
Enter fullscreen mode Exit fullscreen mode

Step 5: Creating the Workflow

The workflow orchestrates the entire process:

const generateSQLStep = createStep({
  id: "generate-sql",
  description: "Generates SQL query from natural language",
  execute: async ({ inputData, mastra }) => {
    const agent = mastra?.getAgent("sqlAgent");

    const response = await agent.stream([
      { role: "user", content: inputData.message },
    ]);

    let responseText = "";
    for await (const chunk of response.textStream) {
      responseText += chunk;
    }

    return { sql: extractSQL(responseText), explanation: responseText };
  },
});

const sqlWorkflow = createWorkflow({
  id: "sql-workflow",
  inputSchema: z.object({
    message: z.string(),
    dialect: z
      .enum(["postgresql", "mysql", "sqlite", "mssql", "oracle"])
      .optional(),
  }),
}).then(generateSQLStep);
Enter fullscreen mode Exit fullscreen mode

Integrating with Telex.im

Setting Up the Integration

  1. Create an AI Co-Worker in Telex
    In your Telex dashboard, navigate to the AI Co-Workers section and create a new co-worker.

  2. Deploy the Agent
    I deployed with Mastra Cloud for easy hosting

  3. Create Workflow JSON

  {
  "active": true,
  "category": "productivity",
  "description": "A project manager bot that tracks and summarizes tasks for Telex users.",
  "id": "unique_id_generated",
  "long_description": "You help users manage tasks and summarize chat history. Recognize project deadlines, remind users, and provide friendly nudges. Use clear, concise language and ask for missing details.",
  "name": "project_helper_agent",
  "nodes": [
    {
      "id": "task_agent_node",
      "name": "Project helper bot",
      "parameters": {},
      "position": [100, 100],
      "type": "a2a/mastra-a2a-node",
      "typeVersion": 1,
      "url": "https://your-domain.com/a2a/agent/sqlAgent"
    }
  ],
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "short_description": "Task/project manager for Telex"
}
Enter fullscreen mode Exit fullscreen mode
  1. Import to Telex
    • Upload workflow JSON to Telex
    • Activate the workflow

Testing the Integration

The agent works beautifully in Telex! Here's a real conversation:

Me: "Get all users who registered in the last 30 days"

Agent:

SELECT id, username, email, created_at
FROM users
WHERE created_at >= CURRENT_DATE - INTERVAL '30 days'
ORDER BY created_at DESC;
Enter fullscreen mode Exit fullscreen mode

Explanation: This query retrieves user information for accounts created in the last 30 days, sorted by most recent first. It uses explicit column selection (avoiding SELECT *) and includes proper date arithmetic.

Security Note: Use parameterized queries to prevent SQL injection when implementing this.


Conclusion

Building this SQL agent taught me:

  1. AI agents are powerful when combined with specialized tools
  2. Mastra makes building production-ready agents surprisingly straightforward
  3. Quality scoring is essential for reliable outputs
  4. Integration platforms like Telex make agents accessible to teams

Try It Yourself

The project is open source! Check it out:

Resources

Acknowledgments

Thanks to:


What would you build with AI agents? Let me know in the comments!

If you found this helpful, please share it with other developers building AI agents.

Top comments (0)