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.
- Conversational AI apps with persistent memory in under 30 minutes
- Vision-capable systems that extract data from images and PDFs
- Multi-step AI agents with real-world tool access
- Automated workflows triggered by webhooks, schedules, or API events
- Production systems that reduce LLM costs by 80–90% over time
Choose Your Path
Prerequisites
| Skill | Beginner | Intermediate | Advanced |
|---|---|---|---|
| Python or JavaScript | Basic (can write a loop) | Comfortable | Proficient |
| HTTP / REST APIs | Not required | Helpful | Required |
| Async programming | Not required | Helpful | Required |
| Docker / deployment | Not required | Not required | Helpful |
| SentinelMeshAI account | Required | Required | Required |
Beginner Tutorial 1 — Set Up Your Account Beginner 10 min
Sign Up
- Go to app.sentinelmeshai.com
- Click Sign Up — use email or continue with GitHub / Google
- Verify your email (check spam if needed)
- You land on the Dashboard — you're in
Get Your API Key
- In the dashboard, click API Keys in the left sidebar
- Click + New Key
- Name it "Tutorial Key" and select Live
- Click Generate Key
- Copy the full key (starts with sm_live_) — it is shown only once
- Paste it somewhere safe (your password manager or a .env file)
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
Test the Key
bashcurl -X GET https://api.sentinelmeshai.com/health \
-H "Authorization: Bearer $SENTINELMESHAI_API_KEY"
{"status": "healthy", "version": "1.0.0", "tenant": "your-name"}
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
Install
bashpip install sentinelmeshaibashnpm install sentinelmeshaiHello, SentinelMeshAI
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?"}'
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
Reading the Response Object
| Field | Type | What it means |
|---|---|---|
output | string | The model's answer — this is what you display to users. |
models_used | list | Which model(s) generated the response. Format: provider:model-name. |
cost_usd | float | What this single request cost in USD. Track this to stay in budget. |
latency_ms | int | End-to-end time from sending the request to receiving the full response. |
cached | bool | True = served from semantic cache, cost was $0. False = went to the LLM. |
confidence | float | Router's confidence score (0–1). Low confidence = consider using a stronger strategy. |
trace_id | string | Unique 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.
- Analytics tab — requests per day, success rate, average latency, cost trend
- API Keys tab — see when each key was last used and its total request count
- Billing tab — credits used this month vs your plan limit, invoice history
- Models tab — which models the router is picking and their relative cost/quality
Intermediate Tutorial 4 — Integrate into Your App Intermediate 25 min
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"),
]
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).
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
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})
Intermediate Tutorial 7 — Alerts & Monitoring Intermediate 20 min
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
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)
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)
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
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
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 type | Recommended strategy | Why |
|---|---|---|
| FAQ / general questions | fast_cheap | DeepSeek Chat is 20× cheaper than GPT-4o with comparable quality for simple tasks |
| Code generation | code_specialist | Codestral is trained specifically for code — better results at lower cost |
| Document summarisation | rag_specialist | Command-R-Plus excels at long-context retrieval |
| Customer decisions | standard | Claude 3.5 Sonnet: best quality-per-dollar |
| Critical reasoning | fast_reasoning | o3-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
- API key stored in environment variables, not source code
- Using async client (
arun) in async web frameworks - Error handling on all API calls (AuthError, RateLimitError)
- Retry logic with exponential backoff for 5xx errors
- Set a timeout (30–60s) on all requests
- Log
trace_idfor every request to your observability system - Test with sm_test_... key before going live
- Set up usage alert webhook before launch
- Monitor cache hit rate — low rates suggest caching is misconfigured
Common Errors & Fixes
Cause: Key not set, expired, or revoked. Fix: echo $SENTINELMESHAI_API_KEY to confirm the variable is exported. Regenerate key in dashboard if needed.
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.
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.
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
- Always use HTTPS — never HTTP in production
- Never expose your API key to browser code or mobile apps — proxy through your backend
- Validate and sanitise user input before passing to AI (prevent prompt injection)
- Enable guardrails for PII detection on user-submitted content
- Rotate API keys every 90 days or on any suspected exposure
Performance
- Use /run-cached for any endpoint where similar questions are likely
- Use streaming for responses >100 tokens to improve perceived latency
- Run AI tasks in background workers (Celery) rather than blocking request threads
- Set
max_tokensto the minimum needed — reduces cost and latency - Batch related prompts with
asyncio.gather()/Promise.all()
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