SentinelMeshAI Tutorials

Progressive learning paths for every skill level — from your first API call to enterprise-grade AI automation. Every tutorial includes working code, expected output, and common errors.

What you'll be able to build

Choose Your Path

🌱
Beginner
No prior AI experience needed. Learn core concepts, set up your account, and make your first API call.
Start here →
⚡
Intermediate
You know the basics. Integrate SentinelMeshAI into a real app, use streaming, memory, and monitoring.
Jump in →
🚀
Advanced
Production-ready patterns: agents with tools, webhooks, automated workflows, enterprise integration.
Go deep →

Prerequisites

SkillBeginnerIntermediateAdvanced
Python or JavaScriptBasic (can write a loop)ComfortableProficient
HTTP / REST APIsNot requiredHelpfulRequired
Async programmingNot requiredHelpfulRequired
Docker / deploymentNot requiredNot requiredHelpful
SentinelMeshAI accountRequiredRequiredRequired

Beginner Tutorial 1 — Set Up Your Account Beginner 10 min

⏱ 10 minutes 📦 No code required 🎯 Goal: API key in hand
Step 1 of 4 → Create account

Sign Up

  1. Go to app.sentinelmeshai.com
  2. Click Sign Up — use email or continue with GitHub / Google
  3. Verify your email (check spam if needed)
  4. You land on the Dashboard — you're in
Free tier
Your Community plan includes $10 in monthly credits — enough to make ~8,000 requests with Claude 3.5 Haiku. No credit card required to start.
Step 2 of 4 → Create API key

Get Your API Key

  1. In the dashboard, click API Keys in the left sidebar
  2. Click + New Key
  3. Name it "Tutorial Key" and select Live
  4. Click Generate Key
  5. Copy the full key (starts with sm_live_) — it is shown only once
  6. Paste it somewhere safe (your password manager or a .env file)
⚠ This key controls your billing
Never put it in frontend code, GitHub, or any public location. Always use environment variables.
Step 3 of 4 → Set environment variable

Store Your Key Securely

bash# Mac / Linux — add to ~/.zshrc or ~/.bashrc
export SENTINELMESHAI_API_KEY="sm_live_..."

# Windows PowerShell
$env:SENTINELMESHAI_API_KEY="sm_live_..."

# .env file (for projects)
echo 'SENTINELMESHAI_API_KEY=sm_live_...' > .env
Step 4 of 4 → Verify

Test the Key

bashcurl -X GET https://api.sentinelmeshai.com/health \
  -H "Authorization: Bearer $SENTINELMESHAI_API_KEY"
Expected response
{"status": "healthy", "version": "1.0.0", "tenant": "your-name"}
401 Unauthorized?

The key wasn't sent correctly. Make sure the variable is exported (echo $SENTINELMESHAI_API_KEY should print your key).

Beginner Tutorial 2 — Your First API Call Beginner 10 min

⏱ 10 minutes📦 Python 3.9+ or Node.js 18+🎯 Goal: send a prompt, read the response
Step 1 → Install the SDK

Install

Python
Node.js
bashpip install sentinelmeshai
bashnpm install sentinelmeshai
Step 2 → Send a prompt

Hello, SentinelMeshAI

Python
Node.js
cURL
pythonimport os, sentinelmeshai as sm

sm.api_key = os.getenv("SENTINELMESHAI_API_KEY")

result = sm.run("What are three interesting facts about octopuses?")

print(result["output"])
print()
print(f"Model used : {result['models_used']}")
print(f"Cost       : ${result['cost_usd']:.6f}")
print(f"Latency    : {result['latency_ms']}ms")
print(f"Cached     : {result['cached']}")
javascriptimport SentinelMeshAI from 'sentinelmeshai';

const sm = new SentinelMeshAI();

const result = await sm.run("What are three interesting facts about octopuses?");
console.log(result.output);
console.log(`Model: ${result.models_used[0]}`);
console.log(`Cost: $${result.cost_usd.toFixed(6)}`);
bashcurl -X POST https://api.sentinelmeshai.com/run \
  -H "Authorization: Bearer $SENTINELMESHAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "What are three interesting facts about octopuses?"}'
Expected output
1. Octopuses have three hearts — two pump blood to the gills, one to the body.
2. Their blood is blue, due to hemocyanin (copper-based), not hemoglobin.
3. Each arm has its own mini "brain" — 2/3 of their neurons live in their arms.

Model used : ['anthropic:claude-3-5-sonnet-20241022']
Cost       : $0.000724
Latency    : 387ms
Cached     : False
Step 3 → Understand the response

Reading the Response Object

FieldTypeWhat it means
outputstringThe model's answer — this is what you display to users.
models_usedlistWhich model(s) generated the response. Format: provider:model-name.
cost_usdfloatWhat this single request cost in USD. Track this to stay in budget.
latency_msintEnd-to-end time from sending the request to receiving the full response.
cachedboolTrue = served from semantic cache, cost was $0. False = went to the LLM.
confidencefloatRouter's confidence score (0–1). Low confidence = consider using a stronger strategy.
trace_idstringUnique request ID. Include this when contacting support about a specific response.

Beginner Tutorial 3 — Reading Your Dashboard Beginner 10 min

The dashboard at app.sentinelmeshai.com gives you a real-time view of every request your API key makes.

💡 Pro tip
Filter Analytics to "24h" to debug a specific batch of calls. The trace_id in each API response matches the row in the analytics table — click any row to see the full request/response.

Intermediate Tutorial 4 — Integrate into Your App Intermediate 25 min

⏱ 25 minutes📦 Python / Node.js project Goal: AI endpoint in a real web app
Django REST endpoint

Add an AI Route to Django

python# myapp/views.py
import os
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
import sentinelmeshai as sm, json

sm.api_key = os.getenv("SENTINELMESHAI_API_KEY")

@csrf_exempt
@require_POST
async def ai_answer(request):
    body = json.loads(request.body)
    prompt = body.get("prompt", "").strip()
    if not prompt:
        return JsonResponse({"error": "prompt required"}, status=400)

    result = await sm.arun(
        prompt,
        strategy   = "standard",
        max_tokens = 1024,
        metadata   = {"user_id": str(request.user.id) if request.user.is_authenticated else "anon"},
    )
    return JsonResponse({
        "answer":   result["output"],
        "cost_usd": result["cost_usd"],
        "latency":  result["latency_ms"],
    })
python# myapp/urls.py
from django.urls import path
from . import views

urlpatterns = [
    path("api/ai/answer/", views.ai_answer, name="ai_answer"),
]
Express.js endpoint

Add an AI Route to Express

javascriptimport express from 'express';
import SentinelMeshAI from 'sentinelmeshai';

const app = express();
app.use(express.json());

const sm = new SentinelMeshAI();

app.post('/api/ai/answer', async (req, res) => {
  const { prompt } = req.body;
  if (!prompt?.trim()) return res.status(400).json({ error: 'prompt required' });

  try {
    const result = await sm.run(prompt, {
      strategy: 'standard',
      metadata: { userId: req.user?.id },
    });
    res.json({ answer: result.output, cost: result.cost_usd });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: 'AI service error' });
  }
});

app.listen(3000);

Intermediate Tutorial 5 — Streaming Responses Intermediate 15 min

Streaming eliminates the perception of waiting for long responses. Instead of waiting 3 seconds for a full answer, the user sees text appearing word by word from the first token (usually <200ms).

Server-Sent Events — FastAPI

Streaming with FastAPI

pythonfrom fastapi import FastAPI
from fastapi.responses import StreamingResponse
import sentinelmeshai as sm, os

sm.api_key = os.getenv("SENTINELMESHAI_API_KEY")
app = FastAPI()

@app.post("/stream")
async def stream_endpoint(body: dict):
    prompt = body.get("prompt", "")

    async def token_generator():
        async for chunk in sm.astream(prompt):
            yield f"data: {chunk}\n\n"
        yield "data: [DONE]\n\n"

    return StreamingResponse(token_generator(), media_type="text/event-stream")
javascript// React frontend — consume the stream
async function AskAI({ prompt }) {
  const [answer, setAnswer] = useState('');

  const fetchStream = async () => {
    const resp = await fetch('/stream', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ prompt }),
    });
    const reader = resp.body.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;
      const text = decoder.decode(value);
      // parse SSE: "data: chunk\n\n"
      for (const line of text.split('\n')) {
        if (line.startsWith('data: ') && !line.includes('[DONE]')) {
          setAnswer(prev => prev + line.slice(6));
        }
      }
    }
  };

  return <div><button onClick={fetchStream}>Ask</button><p>{answer}</p></div>;
}

Intermediate Tutorial 6 — Memory & Conversations Intermediate 20 min

Build a multi-turn chatbot

Persistent Conversation Session

pythonimport uuid, sentinelmeshai as sm, os

sm.api_key = os.getenv("SENTINELMESHAI_API_KEY")

# One session_id per user/conversation — store in DB or session cookie
def create_session() -> str:
    return f"chat_{uuid.uuid4().hex[:12]}"

async def chat(session_id: str, user_message: str) -> str:
    result = await sm.arun_with_memory(
        user_message,
        session_id  = session_id,
        strategy    = "standard",
        system_prompt = "You are a helpful assistant. Be concise.",
    )
    return result["output"]

# Django view example
async def chatbot_view(request):
    session_id = request.session.get("chat_session") or create_session()
    request.session["chat_session"] = session_id

    user_msg = request.POST.get("message", "")
    response = await chat(session_id, user_msg)

    return JsonResponse({"response": response, "session_id": session_id})
💡 Session ID strategy
Use one session ID per user + conversation thread. Store it in your DB alongside the conversation. When a user starts a new conversation, generate a new session ID. Don't reuse session IDs across different topics — the model will confuse context.

Intermediate Tutorial 7 — Alerts & Monitoring Intermediate 20 min

Register a usage alert webhook

Get notified when approaching limits

pythonimport requests, os

# Register webhook via admin endpoint
requests.post(
    "https://api.sentinelmeshai.com/admin/webhook",
    headers={"X-Admin-Key": os.getenv("SENTINELMESHAI_ADMIN_KEY")},
    json={
        "url":    "https://yourapp.com/webhooks/ai-alerts",
        "events": ["usage.threshold", "rate_limit.hit", "model.error"],
        "secret": "your_webhook_signing_secret",
    }
)

# Webhook receiver (Django view)
import hmac, hashlib, json
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def webhook_receiver(request):
    sig = request.headers.get("X-Webhook-Signature", "")
    expected = hmac.new(
        b"your_webhook_signing_secret",
        request.body,
        hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(sig, expected):
        return HttpResponse(status=401)

    event = json.loads(request.body)
    if event["event"] == "usage.threshold":
        # e.g. notify the user, pause non-critical jobs
        print(f"Usage alert: {event['data']['used_pct']}% of monthly credits used")

    return HttpResponse(status=200)

Advanced Tutorial 9 — AI Agents with Tools Advanced 30 min

⏱ 30 minutes📦 SentinelMeshAI server running locally Goal: agent that calls real APIs
Step 1 — Define tools

Creating a Multi-Tool Research Agent

pythonimport aiohttp
from core.tools.base_tool    import BaseTool
from core.tools.tool_registry import ToolRegistry
from core.agents.tool_agent   import ToolAgent
from app import router  # global router from app.py


class WebSearchTool(BaseTool):
    name        = "web_search"
    description = "Search the web and return the top 5 results for a query"
    async def execute(self, query: str) -> str:
        # Replace with your real search API (Brave, SerpAPI, etc.)
        async with aiohttp.ClientSession() as s:
            resp = await s.get("https://api.example.com/search",
                                params={"q": query, "count": 5})
            data = await resp.json()
        return "\n".join(f"- {r['title']}: {r['url']}" for r in data["results"])


class CalculateTool(BaseTool):
    name        = "calculate"
    description = "Evaluate a math expression, e.g. '15 * 0.089' or 'sqrt(256)'"
    async def execute(self, expression: str) -> str:
        # Walk the AST instead of calling eval() -- a restricted-builtins
        # eval() *looks* sandboxed but is a well-known escape (any object
        # reachable from the expression can chain through __class__ /
        # __subclasses__ back to os.system). This is the same AST-walking
        # approach SentinelMesh's own built-in `calculate` tool uses.
        import ast, math, operator
        if len(expression) > 500:
            return "Error: expression exceeds 500-character limit."
        BIN_OPS   = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul,
                     ast.Div: operator.truediv, ast.Pow: operator.pow, ast.Mod: operator.mod}
        UNARY_OPS = {ast.USub: operator.neg, ast.UAdd: operator.pos}
        FUNCS = {n: getattr(math, n) for n in
                 ("sqrt", "sin", "cos", "tan", "log", "log10", "exp", "floor", "ceil")}

        def _eval(node):
            if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
                return node.value
            if isinstance(node, ast.BinOp) and type(node.op) in BIN_OPS:
                return BIN_OPS[type(node.op)](_eval(node.left), _eval(node.right))
            if isinstance(node, ast.UnaryOp) and type(node.op) in UNARY_OPS:
                return UNARY_OPS[type(node.op)](_eval(node.operand))
            if (isinstance(node, ast.Call) and isinstance(node.func, ast.Name)
                    and node.func.id in FUNCS and len(node.args) == 1 and not node.keywords):
                return FUNCS[node.func.id](_eval(node.args[0]))
            raise ValueError(f"Unsupported expression: {ast.dump(node)}")

        try:
            return str(_eval(ast.parse(expression, mode="eval").body))
        except Exception as e:
            return f"Error: {e}"


class SummariseTool(BaseTool):
    name        = "summarise_url"
    description = "Fetch a URL and return a summary of its content"
    async def execute(self, url: str) -> str:
        async with aiohttp.ClientSession() as s:
            resp = await s.get(url, headers={"User-Agent": "SentinelMeshAIBot/1.0"})
            html = await resp.text()
        # Strip HTML tags (simplified)
        import re
        text = re.sub(r"<[^>]+>", " ", html)[:3000]
        return text.strip()


registry = ToolRegistry()
registry.register(WebSearchTool())
registry.register(CalculateTool())
registry.register(SummariseTool())

agent = ToolAgent("research_agent", router=router, tool_registry=registry)
Step 2 — Run the agent

Executing a Multi-Step Research Task

pythonresult = await agent.run(
    "Research the current price of Nvidia stock, calculate what $10,000 "
    "invested 5 years ago would be worth today if it grew at the same rate, "
    "and summarise the latest news about Nvidia's AI chip business."
)

print(result.output)
print(f"\nTools called : {result.tool_calls_made}")  # ['web_search', 'calculate', 'summarise_url']
print(f"Total cost   : ${result.cost_usd:.4f}")
print(f"Rounds       : {result.rounds}")              # ≤ 5 (loop protection built in)
Agent reasoning trace
Round 1 → [tool_call] web_search("Nvidia stock price 2024")
Round 1 → [tool_result] "NVDA: $875.35 (as of...)"
Round 2 → [tool_call] calculate("875.35 / 135.58 * 10000")
Round 2 → [tool_result] "64568.08"
Round 3 → [tool_call] summarise_url("https://reuters.com/technology/nvidia...")
Round 3 → [tool_result] "Nvidia announced H200 GPU availability..."
Round 4 → [final answer] "Based on Nvidia's current price of $875..."

Advanced Tutorial 10 — Automated Workflows Advanced 30 min

GitHub PR reviewer — webhook-driven

Auto-Review Pull Requests with AI

pythonfrom django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import hmac, hashlib, json, os
import sentinelmeshai as sm, httpx

sm.api_key = os.getenv("SENTINELMESHAI_API_KEY")

GITHUB_SECRET = os.getenv("GITHUB_WEBHOOK_SECRET", "").encode()
GITHUB_TOKEN  = os.getenv("GITHUB_TOKEN", "")

@csrf_exempt
async def github_webhook(request):
    # 1. Verify the GitHub signature
    sig = request.headers.get("X-Hub-Signature-256", "")
    expected = "sha256=" + hmac.new(GITHUB_SECRET, request.body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        return JsonResponse({"error": "invalid signature"}, status=401)

    event = json.loads(request.body)
    if event.get("action") not in ("opened", "synchronize"):
        return JsonResponse({"ok": True, "skipped": True})

    # 2. Fetch the diff
    diff_url  = event["pull_request"]["diff_url"]
    pr_number = event["number"]
    repo      = event["repository"]["full_name"]

    async with httpx.AsyncClient() as client:
        diff_resp = await client.get(diff_url,
                                      headers={"Authorization": f"Bearer {GITHUB_TOKEN}"})
        diff = diff_resp.text[:8000]  # truncate for token budget

    # 3. AI review
    review = await sm.arun(
        f"""Review this pull request diff and provide:
1. A summary of what changes were made
2. Any potential bugs or security issues
3. Code quality suggestions
4. An overall verdict (APPROVE / REQUEST_CHANGES)

Diff:
{diff}""",
        strategy    = "code_specialist",
        temperature = 0.1,
    )

    # 4. Post the review back to GitHub
    async with httpx.AsyncClient() as client:
        await client.post(
            f"https://api.github.com/repos/{repo}/issues/{pr_number}/comments",
            headers={"Authorization": f"Bearer {GITHUB_TOKEN}"},
            json={"body": f"🤖 **SentinelMeshAI AI Review**\n\n{review['output']}"},
        )

    return JsonResponse({"ok": True, "cost_usd": review["cost_usd"]})

Advanced Tutorial 11 — Real-Time Event Processing Advanced 25 min

Celery + SentinelMeshAI

Process AI Tasks in the Background

python# tasks.py
import os, asyncio
from celery import shared_task
import sentinelmeshai as sm

sm.api_key = os.getenv("SENTINELMESHAI_API_KEY")

@shared_task(bind=True, max_retries=3, default_retry_delay=5)
def classify_support_ticket(self, ticket_id: int, ticket_text: str):
    """Classify a support ticket's urgency and route to the right team."""
    try:
        result = asyncio.run(sm.arun(
            f"""Classify this support ticket:

"{ticket_text}"

Return JSON only:
{{
  "urgency": "critical|high|medium|low",
  "category": "billing|technical|account|feature",
  "sentiment": "angry|frustrated|neutral|positive",
  "one_line_summary": "string"
}}""",
            strategy    = "fast_reasoning",
            temperature = 0.0,
        ))
        import json
        classification = json.loads(result["output"])

        # Update the ticket in DB
        from support.models import Ticket
        ticket = Ticket.objects.get(id=ticket_id)
        ticket.urgency    = classification["urgency"]
        ticket.category   = classification["category"]
        ticket.ai_summary = classification["one_line_summary"]
        ticket.save()

        # Route critical tickets immediately
        if classification["urgency"] == "critical":
            notify_on_call_team.delay(ticket_id)

    except Exception as exc:
        self.retry(exc=exc)


# Fire the task when a ticket is created
from django.db.models.signals import post_save
from support.models import Ticket

@receiver(post_save, sender=Ticket)
def on_ticket_created(sender, instance, created, **kwargs):
    if created:
        classify_support_ticket.delay(instance.id, instance.body)

Advanced Tutorial 12 — Enterprise Integration Patterns Advanced 40 min

Multi-tenant SaaS — per-user cost tracking

pythonclass AIUsageTracker:
    """
    Wrap SentinelMeshAI calls to track per-user cost and enforce quotas.
    Each paying user gets their own SentinelMeshAI API key so costs are
    automatically separated at the API level — and the self-model learns
    per user.
    """
    def __init__(self, user):
        self.user   = user
        self.client = sm.SentinelMeshAI(
            api_key = user.sentinelmeshai_api_key  # stored at account creation
        )

    async def run(self, prompt: str, **kwargs) -> dict:
        result = await self.client.arun(prompt, **kwargs)

        # Record in your DB for billing
        AIUsage.objects.create(
            user        = self.user,
            cost_usd    = result["cost_usd"],
            latency_ms  = result["latency_ms"],
            model       = result["models_used"][0],
            prompt_hash = hashlib.md5(prompt.encode()).hexdigest(),
        )

        # Enforce per-user monthly quota
        month_cost = AIUsage.objects.filter(
            user=self.user,
            created_at__month=timezone.now().month
        ).aggregate(t=Sum("cost_usd"))["t"] or 0

        if month_cost > self.user.subscription.ai_budget_usd:
            raise QuotaExceededError("Monthly AI budget exceeded")

        return result

Cost Optimisation Deep Dive

Three independent levers, each compounding on the last: caching and strategy selection give most teams around 40% lower cost from day one — model training adds much more on top of that over time as your own models take on more traffic.

1. Semantic Caching (40–65% reduction)

Always use /run-cached for read-heavy endpoints. Customer support queries, FAQ pages, and documentation assistants are particularly good candidates — many users ask the same questions in different words.

python# First call in the morning
r1 = sm.run_cached("What are your pricing plans?")
print(r1["cached"])    # False — $0.000180

# Another user asks the same thing differently
r2 = sm.run_cached("How much does SentinelMeshAI cost per month?")
print(r2["cached"])    # True — $0.000000  ← semantic match!

2. Strategy selection (30–50% reduction)

Use the cheapest strategy that meets your quality bar. Don't use high_accuracy for simple tasks.

Task typeRecommended strategyWhy
FAQ / general questionsfast_cheapDeepSeek Chat is 20× cheaper than GPT-4o with comparable quality for simple tasks
Code generationcode_specialistCodestral is trained specifically for code — better results at lower cost
Document summarisationrag_specialistCommand-R-Plus excels at long-context retrieval
Customer decisionsstandardClaude 3.5 Sonnet: best quality-per-dollar
Critical reasoningfast_reasoningo3-mini: reasoning at 4× lower cost than o1

3. Model training (50–89% reduction, long-term)

After ~200 high-quality interactions, SentinelMeshAI begins training a custom self-model on your data. Once the self-model reaches 95% accuracy parity with the external LLM, the router starts preferring it. This is fully automatic.

bash# Check your self-model independence progress
curl -X GET https://api.sentinelmeshai.com/admin/world-model \
  -H "X-Admin-Key: $SENTINELMESHAI_ADMIN_KEY"

# Response
{
  "independence_score": 0.43,   # 43% of requests now served by self-model
  "episodes_trained": 847,
  "accuracy_parity":  0.96,     # self-model matches external at 96%
  "estimated_cost_reduction": "38%"
}

Production Deployment Checklist

Common Errors & Fixes

401 Unauthorized

Cause: Key not set, expired, or revoked. Fix: echo $SENTINELMESHAI_API_KEY to confirm the variable is exported. Regenerate key in dashboard if needed.

429 Too Many Requests

Cause: Hitting your plan's RPM limit. Fix: Implement exponential backoff. Upgrade plan. Or distribute load with semantic caching to cut the number of real LLM calls.

asyncio.run() nested event loop error

Cause: Calling asyncio.run(sm.arun(...)) inside an already-running async context (FastAPI, Django ASGI, Jupyter). Fix: Use await sm.arun(...) directly — no asyncio.run() wrapper needed inside async contexts.

Low-quality responses / wrong model picked

Cause: Router defaulting to fast_cheap for a complex task. Fix: Pass strategy="standard" or strategy="high_accuracy" explicitly. Over time the router learns, but explicit overrides are fine.

Best Practices

Security

Performance

🎓 Tutorials Complete

You now have everything you need to build, deploy, and optimise AI-powered applications with SentinelMeshAI. The natural next step is the SDK reference for complete API signatures, or the full docs for advanced topics like webhooks, benchmarking, and the admin API.

📚 SentinelMeshAI Tutorials · Updated April 2026 · v1.0
API Docs · SDK Reference · Dashboard