Technology
June 23, 2025
Building Autonomous Agents with the Alith Framework: Developer Guide
Share on:

Let’s skip the cheesy intros - you’re a dev, I’m a dev, so let’s just jump straight to the point.

(And if you’re just here for code, jump straight to section 3. No judgement, promise.)

Why Build with Alith?

Ever found yourself frustrated by frameworks that promise autonomous AI agents but deliver complexity, slow inference, or poor integration? Dev-to-dev speaking, we get it - we've been there too.

That's why we built Alith, the privacy-preserving AI agent framework built by devs, for devs. Alith empowers you to create robust, scalable, and truly decentralized agents without compromising on performance, usability, or privacy.

Alith: What Sets It Apart?

As a developer, you care about three things: performance, simplicity, and control. Here's why Alith stands out through its clear developer-first principles:

  • High-Performance Inference: Built on Rust, Alith leverages advanced graph optimizations and quantization for lightning-fast inference across CPUs, GPUs, and TPUs. Deploy AI agents that respond in real-time, every time.
  • Developer-First Experience: Enjoy cross-language SDKs (Python, Rust, Node.js), low-code orchestration tools, and effortless one-click deployment. No more endless configurations, just straightforward AI agent creation.
  • Native Web3 Integration: Blockchain-backed approach enables transparent governance and secure data handling out-of-the-box, seamlessly connecting your agents with decentralized applications and blockchain networks.
  • Privacy by Design: With native integration of Data Anchoring Tokens (DATs), Alith provides verifiable data sovereignty and privacy preservation, ensuring your sensitive information remains secure and private.

Simply put: Alith doesn't make you compromise. It helps you build better and faster.

Getting Started: Build Your First Alith Agent 

Prerequisites

Before starting, ensure you have:

  • Node.js 18+ installed
  • npm or yarn package manager
  • Basic knowledge of React, TypeScript, and Next.js
  • OpenAI API key (for AI conversations)
  • Code editor (VS Code recommended)

Project Setup

Toggle Arrow

Step 1: Create >Next.js Project

TypeScript
#Create a new Next.js project with TypeScript
npx create-next-app@latest ai-agent --typescript --tailwind --eslint --app --src-dir=false --import-alias="@/*"
#Navigate to the project directory
cd ai-agent
Toggle Arrow

Step 2: Verify Project Structure (expandable)
Your project should look like this:

Directory
ai-blockchain-chatbot/
├── app/
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.ts
├── package.json
└── tsconfig.json

Dependencies Installation

Toggle Arrow

Step 3: Install Required Packages (expandable)

Shell
# Install core dependencies
npm install ethers alith
# Install development dependencies
npm install --save-dev node-loader

What each package does:

  • ethers: Ethereum library for blockchain interactions
  • alith: AI SDK for OpenAI integration
  • node-loader: Webpack loader for native modules

Next.js Configuration

Toggle Arrow

Step 4: Configure next.config.ts (expandable)

TypeScript
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
webpack: (config, { isServer }) => {
if (isServer) {
// On the server side, handle native modules
config.externals = config.externals || [];
config.externals.push({
'@lazai-labs/alith-darwin-arm64': 'commonjs @lazai-labs/alith-darwin-arm64',
});
} else {
// On the client side, don't bundle native modules
config.resolve.fallback = {
...config.resolve.fallback,
'@lazai-labs/alith-darwin-arm64': false,
'alith': false,
};
}
return config;
},
// Mark packages as external for server components
serverExternalPackages: ['@lazai-labs/alith-darwin-arm64', 'alith'],
};
export default nextConfig;

Why this configuration is needed:

  • Handles native modules that can't be bundled by Webpack
  • Prevents client-side bundling of server-only packages
  • Ensures proper module resolution

Token Balance API

Toggle Arrow

Step 5: Create API Directory Structure (Expandable)

Shell
# Create the API directories
mkdir -p app/api/token-balance
mkdir -p app/api/chat
mkdir -p app/components
Toggle Arrow

Step 6: Create Token Balance API (Expandable)

TypeScript
Create app/api/token-balance/route.ts:
import { NextRequest, NextResponse } from 'next/server';
import { ethers } from 'ethers';
// ERC-20 Token ABI (minimal for balance checking)
const ERC20_ABI = [
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "balance", "type": "uint256" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [{ "name": "", "type": "uint8" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "name": "", "type": "string" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "name": "", "type": "string" }],
"type": "function"
}
];
// LazAI Testnet configuration
const LAZAI_RPC = 'https://lazai-testnet.metisdevops.link';
const LAZAI_CHAIN_ID = 133718;
export async function POST(request: NextRequest) {
try {
const { contractAddress, walletAddress } = await request.json();
if (!contractAddress || !walletAddress) {
return NextResponse.json(
{ error: 'Contract address and wallet address are required' },
{ status: 400 }
);
}
if (!ethers.isAddress(contractAddress)) {
return NextResponse.json(
{ error: 'Invalid contract address format' },
{ status: 400 }
);
}
if (!ethers.isAddress(walletAddress)) {
return NextResponse.json(
{ error: 'Invalid wallet address format' },
{ status: 400 }
);
}
const provider = new ethers.JsonRpcProvider(LAZAI_RPC);
const contract = new ethers.Contract(contractAddress, ERC20_ABI, provider);
try {
let balance, decimals, symbol, name;
try { balance = await contract.balanceOf(walletAddress); } catch (error) {
return NextResponse.json(
{ error: 'Failed to get token balance. Contract might not be a valid ERC-20 token.' },
{ status: 400 }
);
}
try { decimals = await contract.decimals(); } catch { decimals = 18; }
try { symbol = await contract.symbol(); } catch { symbol = 'UNKNOWN'; }
try { name = await contract.name(); } catch { name = 'Unknown Token'; }
return NextResponse.json({
name,
symbol,
balance: ethers.formatUnits(balance, decimals)
});
} catch (error) {
return NextResponse.json(
{ error: 'Failed to fetch token data' },
{ status: 500 }
);
}
} catch (error) {
return NextResponse.json(
{ error: 'Internal Server Error' },
{ status: 500 }
);
}
}

Key Features:

  • Validates Ethereum addresses
  • Handles BigInt serialization
  • Provides fallback values for missing token data
  • Comprehensive error handling
  • Returns both token and native currency balances

Toggle Arrow

Step 7: Create Smart Chat API
Create app/api/chat/route.ts

TypeScript
import { NextRequest, NextResponse } from 'next/server';
import { Agent } from 'alith';
// Function to detect token balance requests
function isTokenBalanceRequest(message: string): { isRequest: boolean; contractAddress?: string; walletAddress?: string } {
const lowerMessage = message.toLowerCase();
const balancePatterns = [
/check.*balance/i,
/token.*balance/i,
/balance.*check/i,
/how much.*token/i,
/token.*amount/i
];
const hasBalanceIntent = balancePatterns.some(pattern => pattern.test(lowerMessage));
if (!hasBalanceIntent) { return { isRequest: false }; }
const addressPattern = /0x[a-fA-F0-9]{40}/g;
const addresses = message.match(addressPattern);
if (!addresses || addresses.length < 2) { return { isRequest: false }; }
return { isRequest: true, contractAddress: addresses[0], walletAddress: addresses[1] };
}
export async function POST(request: NextRequest) {
try {
const { message } = await request.json();
if (!message || typeof message !== 'string') {
return NextResponse.json({ error: 'Message is required and must be a string' }, { status: 400 });
}
const balanceRequest = isTokenBalanceRequest(message);
if (balanceRequest.isRequest && balanceRequest.contractAddress && balanceRequest.walletAddress) {
try {
const balanceResponse = await fetch(`${request.nextUrl.origin}/api/token-balance`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
contractAddress: balanceRequest.contractAddress,
walletAddress: balanceRequest.walletAddress
})
});
const balanceData = await balanceResponse.json();
if (balanceData.success) {
const formattedResponse = `🔍 **Token Balance Check Results** **Token Information:** • Name: ${balanceData.data.tokenName} • Symbol: ${balanceData.data.tokenSymbol} • Contract: \`${balanceData.data.contractAddress}\` **Wallet Information:** • Address: \`${balanceData.data.walletAddress}\` • Token Balance: **${balanceData.data.balance} ${balanceData.data.tokenSymbol}** • LAZAI Balance: **${balanceData.data.lazaiBalance} LAZAI** **Network:** ${balanceData.data.network.name} (Chain ID: ${balanceData.data.network.chainId}) You can view this transaction on the [block explorer](${balanceData.data.network.explorer}/address/${balanceData.data.walletAddress}).`;
return NextResponse.json({ response: formattedResponse });
} else {
let errorMessage = `❌ **Error checking token balance:** ${balanceData.error}`;
if (balanceData.error.includes('not a valid ERC-20 token')) {
errorMessage += ` \n\n💡 **Suggestions:** • Make sure the contract address is a valid ERC-20 token on LazAI testnet • Verify the contract exists and is deployed on the network • Check if the contract implements the standard ERC-20 interface`;
} else if (balanceData.error.includes('Invalid contract address')) {
errorMessage += ` \n\n💡 **Suggestion:** Please provide a valid Ethereum address starting with 0x followed by 40 hexadecimal characters.`;
} else if (balanceData.error.includes('Invalid wallet address')) {
errorMessage += ` \n\n💡 **Suggestion:** Please provide a valid Ethereum wallet address starting with 0x followed by 40 hexadecimal characters.`;
}
return NextResponse.json({ response: errorMessage });
}
} catch (error) {
console.error('Error calling token balance API:', error);
return NextResponse.json({ response: "❌ **Error:** Failed to check token balance. Please try again later.\n\n💡 **Possible causes:**\n• Network connection issues\n• Invalid contract or wallet addresses\n• Contract not deployed on LazAI testnet" });
}
}
if (!process.env.OPENAI_API_KEY) {
return NextResponse.json({ error: 'OpenAI API key is not configured' }, { status: 500 });
}
// Initialize the Alith agent with enhanced preamble
const agent = new Agent({
model: "gpt-4",
preamble: ` Your name is Alith. You are a helpful AI assistant with blockchain capabilities. **Available Features:** 1. **Token Balance Checker**: Users can check ERC-20 token balances on the LazAI testnet by providing a contract address and wallet address. The format should include both addresses in the message. **Network Information:** - Network: LazAI Testnet - Chain ID: 133718 - RPC: https://lazai-testnet.metisdevops.link - Explorer: https://lazai-testnet-explorer.metisdevops.link **How to use token balance checker:** Users can ask questions like: - "Check token balance for contract 0x... and wallet 0x..." - "What's the balance of token 0x... in wallet 0x..." - "Check balance: contract 0x... wallet 0x..." Provide clear, concise, and accurate responses. Be friendly and engaging in your conversations. If users ask about token balances, guide them to provide both contract and wallet addresses.` });
const response = await agent.prompt(message);
return NextResponse.json({ response });
} catch (error) {
console.error('Error in chat API:', error);
return NextResponse.json({ error: 'Failed to get response from AI' }, { status: 500 });
}
}

Key Features:

  • Smart message routing based on content analysis
  • Pattern recognition for balance requests
  • Automatic address extraction
  • Enhanced AI prompts with blockchain context
  • Comprehensive error handling
  • Chat Interface Component

Toggle Arrow

Step 8: Create Chat Interface (expandable)

TypeScript
# Create app/components/ChatInterface.tsx:
'use client';
import {'{'} useState, useRef, useEffect {'}'} from 'react';
interface Message {'{'}
  id: string;
  content: string;
  role: 'user' | 'assistant';
  timestamp: Date;
{'}'}
// Simple markdown renderer for basic formatting
const renderMarkdown = (text: string) => {'{'}
  return text
    .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
    .replace(/\*(.*?)\*/g, '<em>$1</em>')
    .replace(/(.*?)/g, '<code class="bg-gray-100 px-1 py-0.5 rounded text-sm font-mono">$1</code>')
    .replace(/\n/g, '<br>')
    .replace(/•/g, '•');
{'}'};
export default function ChatInterface() {'{'}
  const [messages, setMessages] = useState<Message[]>([]);
  const [inputMessage, setInputMessage] = useState('');
  const [isLoading, setIsLoading] = useState(false);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  useEffect(() => {'{'}
    // Auto-scroll to bottom when new messages are added
    messagesEndRef.current?.scrollIntoView({'{'} behavior: 'smooth' {'}'});
  {'}'}, [messages]);
  const handleSendMessage = async () => {'{'}
    if (!inputMessage.trim() || isLoading) return;
    const userMessage: Message = {'{'}
      id: Date.now().toString(),
      content: inputMessage.trim(),
      role: 'user',
      timestamp: new Date(),
setMessages(prev => [...prev, userMessage]);
setInputMessage('');
setIsLoading(true);
try {'{'}
  const response = await fetch('/api/chat', {'{'}
    method: 'POST',
    headers: {'{'}
      'Content-Type': 'application/json',
    {'}'},
    body: JSON.stringify({'{'} message: inputMessage.trim() {'}'}),
  {'}'});
  if (!response.ok) {'{'}
    throw new Error('Failed to get response');
  {'}'}
  const data = await response.json();
  if (data.error) {'{'}
    throw new Error(data.error);
  {'}'}
  const assistantMessage: Message = {'{'}
    id: (Date.now() + 1).toString(),
    content: data.response,
    role: 'assistant',
    timestamp: new Date(),
  {'}'};
  setMessages(prev => [...prev, assistantMessage]);
} catch (error) {'{'}
  console.error('Error getting response:', error);
  const errorMessage: Message = {'{'}
    id: (Date.now() + 1).toString(),
    content: 'Sorry, I encountered an error. Please try again.',
    role: 'assistant',
    timestamp: new Date(),
  {'}'};
  setMessages(prev => [...prev, errorMessage]);
} finally {'{'}
  setIsLoading(false);
{'}'};
const handleKeyPress = (e: React.KeyboardEvent) => {'{'}
  if (e.key === 'Enter' && !e.shiftKey) {'{'}
    e.preventDefault();
    handleSendMessage();
  {'}'}
};
const formatTime = (date: Date) => {'{'}
  return date.toLocaleTimeString([], {'{'} hour: '2-digit', minute: '2-digit' {'}'});
};
return (
  <div className="flex flex-col h-screen bg-gray-50">
    {/* Header */}
    <div className="bg-white border-b border-gray-200 px-6 py-4">
      <h1 className="text-2xl font-bold text-gray-900">Alith AI Assistant</h1>
      <p className="text-sm text-gray-600">Powered by Alith SDK & ChatGPT • Blockchain Capabilities</p>
    </div>
    {/* Messages Container */}
    <div className="flex-1 overflow-y-auto px-6 py-4 space-y-4">
      {messages.length === 0 && (
        <div className="text-center text-gray-500 mt-8">
          <div className="text-6xl mb-4">🤖</div>
          <h3 className="text-lg font-medium mb-2">Welcome to Alith AI!</h3>
          <p className="text-sm mb-4">I can help you with general questions and blockchain operations.</p>
          {/* Feature showcase */}
          <div className="bg-white rounded-lg p-4 max-w-md mx-auto border border-gray-200">
            <h4 className="font-medium text-gray-900 mb-2">Available Features:</h4>
            <ul className="text-sm text-gray-600 space-y-1">
              <li>• 💬 General AI conversations</li>
              <li>• 🔍 Token balance checking on LazAI testnet</li>
              <li>• 📊 Blockchain data queries</li>
            </ul>
            <div className="mt-3 p-2 bg-blue-50 rounded text-xs text-blue-700">
              <strong>Example:</strong> "Check token balance for contract 0x1234... and wallet 0x5678..."
            </div>
          </div>
          </div>
      )};
      {messages.map((message) => (
        <div
          key={message.id}
          className="flex ${message.role === 'user' ? 'justify-end' : 'justify-start'}"
        >
          <div
            className="max-w-[70%] rounded-lg px-4 py-3 ${message.role === 'user' ? 'bg-blue-600 text-white' : 'bg-white text-gray-900 border border-gray-200'}"
<div
className="text-sm whitespace-pre-wrap ${'{'}"
message.role === 'assistant' ? 'prose prose-sm max-w-none' : ''
{'}'}
dangerouslySetInnerHTML={{'{'}
__html: message.role === 'assistant'
? renderMarkdown(message.content)
: message.content,
{'}'}}
/>
<div
className="text-xs mt-2 ${'{'}"
message.role === 'user' ? 'text-blue-100' : 'text-gray-500'
{'}'}
>
{formatTime(message.timestamp)}
</div>
</div>
</div>
{isLoading && (
<div className="flex justify-start">
<div className="bg-white text-gray-900 border border-gray-200 rounded-lg px-4 py-3">
<div className="flex items-center space-x-2">
<div className="flex space-x-1">
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div>
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{'{'} animationDelay: '0.1s' {'}'}}></div>
<div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{'{'} animationDelay: '0.2s' {'}'}}></div>
</div>
<span className="text-sm text-gray-600">Alith is thinking...</span>
</div>
</div>
</div>
)}
<div ref={messagesEndRef} />
{/* Input Container */}
<div className="bg-white border-t border-gray-200 px-6 py-4">
<div className="flex space-x-4">
<div className="flex-1">
<textarea
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
onKeyPress={handleKeyPress}
placeholder="Ask me anything or check token balances..."
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent resize-none"
rows={1}
disabled={isLoading}
/>
</div>
<button
onClick={handleSendMessage}
disabled={!inputMessage.trim() || isLoading}
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
<svg
className="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
/>
</svg>
</button>
</div>
{/* Quick help */}
<div className="mt-2 text-xs text-gray-500">
💡 <strong>Tip:</strong> Include both contract and wallet addresses to check token balances on LazAI testnet
</div>
</div>
</div>
);
}

Key Features:

  • Real-time message updates
  • Markdown rendering for formatted responses
  • Auto-scroll to the latest messages
  • Loading indicators
  • Responsive design
  • Feature showcase for new users

Environment Setup

Toggle Arrow

Step 9: Configure Environment Variables (Expandable)

None
# Create a .env.local file in your project root
# OpenAI API Key for AI conversations
OPENAI_API_KEY=your_openai_api_key_here

Step 10: Get OpenAI API Key (expandable)

  • Go to OpenAI Platform
  • Sign up or log in to your account
  • Navigate to "API Keys" in the sidebar
  • Click "Create new secret key"
  • Copy the generated key
  • Paste it in your .env.local file

Security Note: Never commit your API key to version control!

Testing

Toggle Arrow

Step 11: Start Development Server (Expandable)

TypeScript
npm run dev

Step 12: Test General Chat

Try these general questions:

"What is blockchain technology?"

"How does cryptocurrency work?"

"Tell me a joke"

"What are the benefits of decentralized systems?"

Step 13: Test Token Balance Checking

Try these formats:

"Check token balance for contract 0x1234567890123456789012345678901234567890 and wallet 0x0987654321098765432109876543210987654321"

"What's the balance of token 0x... in wallet 0x..."

"Check balance: contract 0x... wallet 0x..."

Note: You'll need valid contract and wallet addresses on the LazAI testnet for this to work.

Ready to Build?

Stay tuned - comprehensive code samples, real-world scenarios, and detailed tutorials are coming shortly. Until then:

Start building with Alith, and let's redefine what's possible with decentralized autonomous agents.

The future of AI agents starts here with Alith, built by developers, for developers.

Related Posts
Subscribe to our Newsletter
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.