Monitoring Safari Park Camera Feeds with Mastra.ai

2 hours ago 2

A single AI tool can count tigers in a zoo surveillance camera feed. An intelligent agent can monitor an entire safari park. By coordinating multiple camera feeds, analyzing different animal behaviors, and synthesizing a comprehensive status report, an agent achieves what no individual tool could produce independently.

This shift from single-purpose tools to intelligent orchestration opens up new opportunities for organizations of all kinds. Instead of building isolated automation scripts, we can create agents that reason about complex tasks, break them into specialized subtasks, and coordinate the right tools at the right time.

Consider a zookeeper monitoring a safari park. Their expertise isn't operating individual cameras. It's knowing when to check each feed, how to interpret combined data, and what the complete picture means for park operations. The agent's job is strategic thinking and coordination, not just task execution.

Mastra.ai provides this reasoning layer to developers of AI agents. Or, the "zookeepers's brain", as our example shows, because of its ability to understand objectives, decompose tasks, and orchestrate tools intelligently. Meanwhile Anchor Browser provides specialized web automation capabilities–the eyes and hands–that navigates websites and analyzes visual content with human-like understanding.

Together, Mastra and Anchor Browser create agents that don't just automate web tasks, but solve complex, multi-faceted problems through intelligent tool coordination.

What is Mastra.ai?

Mastra.ai is a TypeScript agent framework that lets AI agents reason, remember, and act on workflows. Unlike traditional automation platforms that execute predetermined scripts, Mastra agents make decisions about which tools to use based on natural language instructions and contextual understanding.

The framework provides three core primitives that work together: agents that reason about tasks and coordinate tool usage, workflows that define structured sequences of operations with parallel execution and error handling, and tools that perform specialized tasks with type-safe input/output schemas.

What makes Mastra powerful is its declarative approach. Instead of writing imperative code that says, "do this, then do that," you define what the agent should accomplish and let it figure out how. The agent receives high-level instructions like "monitor the safari park" and autonomously decides whether to use individual counting tools, coordinate multiple tools in parallel, or execute complex workflows based on the situation.

Key capabilities of Mastra.ai include persistent memory for conversation history, semantic recall for retrieving relevant context from past interactions, streaming responses for real-time feedback, and comprehensive observability for monitoring agent behavior. Everything is built with TypeScript-first design, ensuring reliability across agent-tool interactions.

The Mastra + Anchor Pipeline: Intelligent Web Workflows

By combining Mastra's reasoning capabilities with Anchor's computer vision and browser tools, we get a powerful pipeline that is capable of transforming high-level objectives into coordinated web automation. For our safari monitoring example, we deploy an agent in Mastra, named "zookeeperAgent", which we ask to analyze live camera feeds. This agent coordinates tools that use Anchor Browser's computer vision capabilities to fetch camera feeds, analyze what animals they see, and extract meaningful information. From start to finish, the Mastra agent is in command, handling the strategic decisions about which tools to use and how to interpret their results.

When you tell the zookeeper agent to "monitor the safari park," Mastra doesn’t just execute a script. It reasons about the task. The agent understands that monitoring requires checking multiple camera feeds, the different animals need specialized analysis for identification, and that the results should be synthesized into a comprehensive report with confidence levels.

Anchor Browser provides the specialized tool capabilities. Each tool that Mastra coordinates uses Anchor’s computer vision to navigate to camera feeds and analyze what it sees. The tiger counting tool opens the tiger camera URL, takes a screenshot, and uses AI vision to identify and count tigers. The giraffe counting tool does the same for giraffes. Neither tool needs to parse pre-set camera masks. They see the rendered web pages and understand them visually.

Workflows coordinate complex operations. Mastra's workflow engine can execute the tiger and giraffe counting in parallel, handle errors gracefully if a camera feed is down, and aggregate the results into a structured format. The workflow defines the sequence and error handling declaratively, while the agent decides whether to use individual tools or the complete workflow based on the specific request.

Type-safe data flow to ensure reliability. Every tool defines its input and output schemas, so when the tiger counter returns tigerCount: 3, the workflow knows exactly how to handle that result and pass it to the report generation step.

The end product is a system where you can ask, "How many animals are in the safari park?" and get back not just numbers, but a detailed analysis: "Giraffes: 2, Tiger: 3, Total: 5 animals". High confidence in both counts. This level of contextual understanding and coordination is made much more challenging with traditional automation scripts.

Project Setup: Building a Safari Monitoring Agent

Prerequisites

Before building our intelligent safari monitoring system, you'll need:

Dependencies Installation

Initialize a new Node.js project and install the required packages:

npm init -y npm install @mastra/core @mastra/loggers @ai-sdk/groq npm install zod dotenv npm install -D typescript @types/node

Environment Configuration

Create a .env file in your project root:

GROQ_API_KEY=your_groq_api_key_here ANCHOR_API_KEY=sk-your_anchor_browser_api_key_here

Add the .env file to your .gitignore to avoid accidentally committing your API keys:

echo ".env" >> .gitignore

The Groq API key enables your Mastra agent access any of Groq's open source cloud-hosted models, which are essential for our agent to understand and reason about the responses from our custom tools. The Anchor Browser API key provides underlying remote browser sessions for requesting the camera feeds.

Safari Camera Monitoring System

Let's start by creating specialized tools that use computer vision to analyze live camera feeds. Each tool focuses on a specific subtask, counting one type of animal, which the agent can coordinate intelligently.

Create src/mastra/tools/index.ts:

import { createTool } from '@mastra/core/tools'; import { z } from 'zod'; async function directApiCall(endpoint: string, payload: any, method: string = 'POST') { const options: RequestInit = { method, headers: { 'anchor-api-key': process.env.ANCHOR_API_KEY!, 'Content-Type': 'application/json', }, }; if (method !== 'DELETE' && payload) { options.body = JSON.stringify(payload); } const response = await fetch(`https://api.anchorbrowser.io/v1${endpoint}`, options); if (!response.ok) { const errorText = await response.text(); throw new Error(`HTTP ${response.status}: ${errorText}`); } const contentType = response.headers.get('content-type'); console.log('Response content type:', contentType); if (contentType && contentType.includes('application/json')) { return response.json(); } else { const text = await response.text(); console.log('Non-JSON response:', text.substring(0, 200)); try { return JSON.parse(text); } catch (parseError) { return { content: text, rawResponse: true }; } } } async function createConfiguredSession() { return await directApiCall('/sessions', { session: { recording: { active: true }, proxy: { active: true, type: 'anchor_residential', country_code: 'us' }, timeout: { max_duration: 15, idle_timeout: 1 }, live_view: { read_only: false } }, browser: { adblock: { active: true }, popup_blocker: { active: false }, extra_stealth: { active: true }, headless: { active: false }, viewport: { width: 1440, height: 900 }, fullscreen: { active: false }, captcha_solver: { active: false } } }); } export const tigerCountTool = createTool({ id: 'count-tigers', description: 'Analyze the tiger camera feed to count the number of tigers present', inputSchema: z.object({}), outputSchema: z.object({ tigerCount: z.number(), confidence: z.string(), details: z.string(), success: z.boolean(), }), execute: async () => { let sessionId = null; try { const sessionResult = await createConfiguredSession(); sessionId = sessionResult.data?.id; if (!sessionId) { throw new Error('Failed to create session'); } console.log('Analyzing tiger camera feed...'); const tigerImageUrl = 'https://zssd-tiger.preview.api.camzonecdn.com/previewimage'; const result = await directApiCall('/tools/perform-web-task', { prompt: 'Analyze this image and count the number of tigers visible. Look carefully at the entire image. Return just the number of tigers you can see clearly. Be precise and only count tigers that are clearly visible.', url: tigerImageUrl, provider: 'groq', model: 'meta-llama/llama-4-scout-17b-16e-instruct', headless: false, proxy: { active: true, type: 'anchor_residential', country_code: 'us' }, browser: { adblock: { active: true }, extra_stealth: { active: true } } }); const analysisResult = result.result || ''; console.log('Tiger analysis result:', analysisResult); const numberMatch = analysisResult.match(/(\d+)/); const tigerCount = numberMatch ? parseInt(numberMatch[1], 10) : 0; return { tigerCount, confidence: 'High', details: analysisResult, success: true, }; } catch (error) { console.error('Error in tigerCountTool:', error); return { tigerCount: 0, confidence: 'Error', details: `Error analyzing tiger image: ${error.message}`, success: false, }; } finally { if (sessionId) { try { await directApiCall(`/sessions/${sessionId}`, {}, 'DELETE'); } catch (cleanupError) { console.log('Session cleanup failed:', cleanupError.message); } } } }, }); export const giraffeCountTool = createTool({ id: 'count-giraffes', description: 'Analyze the giraffe camera feed to count the number of giraffes present', inputSchema: z.object({}), outputSchema: z.object({ giraffeCount: z.number(), confidence: z.string(), details: z.string(), success: z.boolean(), }), execute: async () => { let sessionId = null; try { const sessionResult = await createConfiguredSession(); sessionId = sessionResult.data?.id; if (!sessionId) { throw new Error('Failed to create session'); } console.log('Analyzing giraffe camera feed...'); const giraffeImageUrl = 'https://zssd-kijami.preview.api.camzonecdn.com/previewimage'; const result = await directApiCall('/tools/perform-web-task', { prompt: 'Analyze this image and count the number of giraffes visible. Look carefully at the entire image. Return just the number of giraffes you can see clearly. Be precise and only count giraffes that are clearly visible.', url: giraffeImageUrl, provider: 'groq', model: 'meta-llama/llama-4-scout-17b-16e-instruct', headless: false, proxy: { active: true, type: 'anchor_residential', country_code: 'us' }, browser: { adblock: { active: true }, extra_stealth: { active: true } } }); const analysisResult = result.result || ''; console.log('Giraffe analysis result:', analysisResult); const numberMatch = analysisResult.match(/(\d+)/); const giraffeCount = numberMatch ? parseInt(numberMatch[1], 10) : 0; return { giraffeCount, confidence: 'High', details: analysisResult, success: true, }; } catch (error) { console.error('Error in giraffeCountTool:', error); return { giraffeCount: 0, confidence: 'Error', details: `Error analyzing giraffe image: ${error.message}`, success: false, }; } finally { if (sessionId) { try { await directApiCall(`/sessions/${sessionId}`, {}, 'DELETE'); } catch (cleanupError) { console.log('Session cleanup failed:', cleanupError.message); } } } }, }); export const animalWatchTool = createTool({ id: 'animal-watch-tool', description: 'Get complete count of animals in the safari park by analyzing both camera feeds', inputSchema: z.object({}), outputSchema: z.object({ giraffes: z.number(), tigers: z.number(), totalAnimals: z.number(), report: z.string(), success: z.boolean(), }), execute: async () => { try { console.log('Starting complete safari animal count...'); const tigerResult = await tigerCountTool.execute({}); console.log('Tiger count result:', tigerResult); const giraffeResult = await giraffeCountTool.execute({}); console.log('Giraffe count result:', giraffeResult); const giraffes = giraffeResult.giraffeCount || 0; const tigers = tigerResult.tigerCount || 0; const totalAnimals = giraffes + tigers; const report = `Safari Park Animal Count Report: - Giraffes: ${giraffes} (${giraffeResult.confidence} confidence) - Tigers: ${tigers} (${tigerResult.confidence} confidence) - Total Animals: ${totalAnimals} Details: Tiger Analysis: ${tigerResult.details} Giraffe Analysis: ${giraffeResult.details}`; return { giraffes, tigers, totalAnimals, report, success: tigerResult.success && giraffeResult.success, }; } catch (error) { console.error('Error in animalWatchTool:', error); return { giraffes: 0, tigers: 0, totalAnimals: 0, report: `Error during safari analysis: ${error.message}`, success: false, }; } }, }); export const testTool = createTool({ id: 'test-session-approach', description: 'Test session-based fetch webpage approach with correct query param', inputSchema: z.object({ testUrl: z.string().optional(), }), outputSchema: z.object({ status: z.string(), message: z.string(), sessionId: z.string().optional(), }), execute: async ({ context }) => { let sessionId = null; try { const sessionResult = await createConfiguredSession(); sessionId = sessionResult.data?.id; if (!sessionId) { throw new Error('Failed to create session'); } console.log('Created session:', sessionId); const testUrl = context.testUrl || 'https://httpbin.org/ip'; const result = await directApiCall(`/tools/fetch-webpage?sessionId=${sessionId}`, { url: testUrl, format: 'markdown' }); return { status: 'SUCCESS', message: `Session approach worked! Content length: ${result.content?.length || 'unknown'}`, sessionId: sessionId, }; } catch (error) { return { status: 'ERROR', message: `Session approach failed: ${error.message}`, sessionId: sessionId || 'none', }; } finally { if (sessionId) { try { await directApiCall(`/sessions/${sessionId}`, {}, 'DELETE'); console.log('Session cleaned up:', sessionId); } catch (cleanupError) { console.log('Session cleanup failed:', cleanupError.message); } } } }, });

The tools tigerCountTool and giraffeCountTool use computer vision to view and analyze the most recent image displayed from the camera feed. Their response is structured with the model's confidence levels, enabling intelligent decision-making. Error handling ensures graceful degradation when camera feeds fail.

Orchestrating Intelligence: The Safari Monitoring Workflow

Now let's create the workflow that coordinates multiple counting tools and synthesizes their results. Create src/mastra/workflows/index.ts:

import { createWorkflow } from '@mastra/core/workflows'; import { z } from 'zod'; export const safariMonitoringWorkflow = createWorkflow({ name: 'Safari Park Animal Monitoring', triggerSchema: z.object({ scheduleCheck: z.boolean().optional(), }), steps: { countTigers: { tool: 'tigerCountTool', outputSchema: z.object({ tigerCount: z.number(), confidence: z.string(), details: z.string(), success: z.boolean(), }), }, countGiraffes: { tool: 'giraffeCountTool', outputSchema: z.object({ giraffeCount: z.number(), confidence: z.string(), details: z.string(), success: z.boolean(), }), }, generateReport: { inputSchema: z.object({ tigerData: z.object({ tigerCount: z.number(), confidence: z.string(), details: z.string(), success: z.boolean(), }), giraffeData: z.object({ giraffeCount: z.number(), confidence: z.string(), details: z.string(), success: z.boolean(), }), }), outputSchema: z.object({ report: z.string(), totalAnimals: z.number(), timestamp: z.string(), }), func: async ({ tigerData, giraffeData }) => { const timestamp = new Date().toISOString(); const totalAnimals = tigerData.tigerCount + giraffeData.giraffeCount; const report = ` Safari Park Monitoring Report Generated: ${timestamp} Animal Counts: - Giraffes: ${giraffeData.giraffeCount} (${giraffeData.confidence} confidence) - Tigers: ${tigerData.tigerCount} (${tigerData.confidence} confidence) - Total Animals: ${totalAnimals} Camera Feed Analysis: Tiger Camera: ${tigerData.details} Giraffe Camera: ${giraffeData.details} Status: ${tigerData.success && giraffeData.success ? 'All cameras operational' : 'Some camera issues detected'} `.trim(); return { report, totalAnimals, timestamp, }; }, }, }, });

The power of declarative workflows

This workflow demonstrates Mastra's intelligent coordination capabilities. The countTigers and countGiraffes steps run in parallel automatically—Mastra's workflow engine recognizes they don't depend on each other and executes them concurrently for efficiency.

The generateReport step shows how workflows can include both tool calls and custom functions. This step takes the structured output from both counting tools and synthesizes them into a comprehensive report with timestamps, confidence levels, and operational status.

Creating an Intelligent Agent with Mastra

Now we create the agent that brings everything together. The agent uses natural language instructions to guide its behavior and leverages Groq's Meta-Llama model to understand and reason about the task at hand.

Create src/mastra/agents/index.ts:

import { createGroq } from '@ai-sdk/groq'; import { Agent } from '@mastra/core/agent'; import { animalWatchTool, tigerCountTool, giraffeCountTool, testTool } from '../tools'; const groq = createGroq({ apiKey: process.env.GROQ_API_KEY, }); export const zookeeperAgent = new Agent({ name: 'Zookeeper Agent', instructions: ` You are a professional Zookeeper responsible for monitoring the safari park. Your primary function is to analyze camera feeds to count the number of animals present in different areas of the safari park. When performing animal counts: - Be patient and wait for images to load completely - Use the available tools to analyze tiger and giraffe camera feeds - Provide accurate counts for each animal type - Always present results in this clear format: Giraffes: X Tigers: Y Total Animals: Z - If there are any issues with the camera feeds, report them clearly - Keep responses professional and concise - Focus on accuracy over speed Use the available tools to gather the latest animal count data from both camera feeds. `, model: groq('meta-llama/llama-4-scout-17b-16e-instruct'), tools: { animalWatchTool, tigerCountTool, giraffeCountTool, testTool }, });

The agent as a reasoning engine

The zookeeperAgent demonstrates strategic tool coordination rather than predetermined execution. When asked, "How many animals are in the safari park?", the agent reasons about the request and chooses appropriate tools. For example, individual counters for giraffes versus tigers, the comprehensive animalWatchTool, or coordinated workflows.

Note the computer vision work in this case (analyzing camera feed images) happens in Anchor Browser's cloud platform, while the Mastra agent handles the reasoning about which Mastra-defined tools to use and how to interpret their results.

View full Mastra agent source code.

Deploy to production

zookeeperAgent deployed in Mastra Cloud

Register your agent with Mastra Cloud for scalable execution and monitoring.

Special thank you to the San Diego Zoo Wildlife Alliance for providing the live camera feeds used in this example project.

Real-World Applications Beyond Safari Monitoring

The Intelligent agent orchestration pattern we've demonstrated with safari monitoring extends far beyond animal counting. Here are a few additional practical applications that leverage the same Mastra and Anchor Browser architecture.

E-commerce Price Intelligence

Deploy agents that monitor competitor pricing across multiple platforms. Individual tools track specific retailers (Amazon, eBay, direct competitors), while the orchestrating agent identifies pricing trends, calculates optimal pricing strategies, and generates alerts when competitors make significant moves.

Social Media Sentiment Analysis

Create specialized agents that analyze brand mentions across Twitter, LinkedIn, Instagram, and Reddit. Each tool focuses on platform-specific content extraction, while the coordinating agent synthesizes sentiment patterns, identifies emerging issues, and generates comprehensive brand health reports.

Financial Data Aggregation

Build agents that monitor trading dashboards, financial news sites, and market data feeds. Tools extract specific metrics (stock prices, volume, news sentiment), while the agent correlates information across sources to identify trading opportunities or risk patterns.

Quality Assurance Testing

Create agents that perform visual regression testing across different browsers and devices. Tools capture screenshots and compare visual elements, while the coordinating agent identifies patterns in failures, prioritizes issues by impact, and generates detailed bug reports with visual evidence.

Conclusion

Intelligent agent orchestration changes web automation from brittle scripts into adaptive reasoning systems. By combining Mastra's strategic coordination with Anchor Browser’s vision-capable browser tooling, we’ve built agents that understand objectives, decompose complex problems, and coordinate specialized tools to achieve outcomes no single tool could accomplish.

This approach scales from safari monitoring to comprehensive automation across a variety of business applications. Unlike traditional scrapers that break with every website update, these agents evolve with the systems they monitor.

The pattern is clear: break complex objectives into specialized subtasks, deploy the right tools for each subtask, and synthesize results into actionable intelligence. As these technologies mature, we’ll see agents handling increasingly sophisticated workflows that transform how organizations approach complex data collection and analysis challenges.

If you'd like a hand getting started with Mastra and Anchor Browser, get in touch with your use case.

Read Entire Article