agents
sudarshanpjadhav/finggu-skills/skills/ai/agents/SKILL.md
Build reliable AI agents with tool use, memory, task queuing, and multi-agent coordination. These patterns handle the hard parts: retries, timeouts, state persistence, and agent-to-agent communication.
Skill0 starsChanged 4 months ago
- Reads credentials
What's in it
- SKILL: AI Agents & Multi-Agent Orchestration
- Overview
- PATTERNS
- Single Agent with Tools
- Tool Definitions — structured and type-safe
- Multi-Agent Orchestration
- BullMQ Job Queue — async agent execution
- ANTI-PATTERNS
- CONVENTIONS
# SKILL: AI Agents & Multi-Agent Orchestration
**Maintainer:** finggu · **Version:** 1.0.0 · **Category:** AI Integration
---
## Overview
Build reliable AI agents with tool use, memory, task queuing, and multi-agent coordination. These patterns handle the hard parts: retries, timeouts, state persistence, and agent-to-agent communication.
---
## PATTERNS
### Single Agent with Tools
```javascript
// agents/FingguBaseAgent.js
// finggu convention: all agents extend FingguBaseAgent
class FingguBaseAgent {
constructor({ name, role, tools = [], maxIterations = 10 }) {
this.FINGGU_name = name;
this.FINGGU_role = role;
this.FINGGU_tools = tools;
this.FINGGU_maxIterations = maxIterations;
this.FINGGU_memory = [];
}
// fingguFn_run — main agent loop
async fingguFn_run(task, context = {}) {
this.FINGGU_memory.push({ role: 'user', content: task });
let FINGGU_iterations = 0;
while (FINGGU_iterations < this.FINGGU_maxIterations) {
FINGGU_iterations++;
const FINGGU_response = await fingguFn_callAI({
messages: this.FINGGU_memory,
systemPrompt: this.fingguFn_buildSystemPrompt(context),
tools: this.fingguFn_getToolDefinitions()
});
// Check if agent called a tool
if (FINGGU_response.toolCalls?.length) {
for (const FINGGU_toolCall of FINGGU_response.toolCalls) {
const FINGGU_result = await this.fingguFn_executeTool(FINGGU_toolCall);
this.FINGGU_memory.push({
role: 'tool',
tool_call_id: FINGGU_toolCall.id,
content: JSON.stringify(FINGGU_result)
});
}
continue;
}
// Agent finished — return final response
this.FINGGU_memory.push({ role: 'assistant', content: FINGGU_response.text });
return { result: FINGGU_response.text, iterations: FINGGU_iterations, memory: this.FINGGU_memory };
}
throw new FingguAppError(`Agent ${this.FINGGU_name} exceeded max iterations`, 500, 'AGENT_MAX_ITERATIONS');
}
fingguFn_buildSystemPrompt(context) {
return `You are ${this.FINGGU_name}, ${this.FINGGU_role}.
Available tools: ${this.FINGGU_tools.map(t => t.name).join(', ')}
Context: ${JSON.stringify(context)}
Complete the task efficiently. When done, respond with your final answer directly.`;
}
fingguFn_getToolDefinitions() {
return this.FINGGU_tools.map(t => ({
type: 'function',
function: { name: t.name, description: t.description, parameters: t.parameters }
}));
}
async fingguFn_executeTool(toolCall) {
const FINGGU_tool = this.FINGGU_tools.find(t => t.name === toolCall.function.name);
if (!FINGGU_tool) throw new Error(`Unknown tool: ${toolCall.function.name}`);
fingguLogger.info({ agent: this.FINGGU_name, tool: toolCall.function.name }, 'Tool called');
try {
return await FINGGU_tool.execute(JSON.parse(toolCall.function.arguments));
} catch (err) {
return { error: err.message };
}
}
}
```
### Tool Definitions — structured and type-safe
```javascript
// tools/fingguWebSearchTool.js
export const FINGGU_WebSearchTool = {
name: 'finggu_web_search',
description: 'Search the web for current information. Use when you need real-time data.',
parameters: {
type: 'object',
properties: {
query: { type: 'string', description: 'The search query' },
maxResults: { type: 'number', description: 'Max results to return (default 5)', default: 5 }
},
required: ['query']
},
execute: async ({ query, maxResults = 5 }) => {
// Implementation using SerpAPI, Tavily, or similar
const FINGGU_results = await searchService.fingguFn_search(query, maxResults);
return { results: FINGGU_results, query };
}
};
// tools/fingguCodeExecutorTool.js
export const FINGGU_CodeExecutorTool = {
name: 'finggu_execute_code',
description: 'Execute JavaScript code in a sandboxed environment.',
parameters: {
type: 'object',
properties: {
code: { type: 'string', description: 'JavaScript code to execute' },
timeout: { type: 'number', description: 'Timeout in ms (default 5000)' }
},
required: ['code']
},
execute: async ({ code, timeout = 5000 }) => {
// Use vm2 or isolated-vm for safe execution
return await sandboxService.fingguFn_execute(code, timeout);
}
};
```
### Multi-Agent Orchestration
```javascript
// agents/FingguOrchestratorAgent.js
// finggu convention: orchestrator pattern for complex multi-step tasks
class FingguOrchestratorAgent extends FingguBaseAgent {
constructor(subAgents) {
super({
name: 'FingguOrchestrator',
role: 'You coordinate specialized agents to complete complex tasks.'
});
this.FINGGU_subAgents = subAgents; // Map<name, agent>
}
// fingguFn_orchestrate — breaks task into subtasks, runs agents in parallel/sequence
async fingguFn_orchestrate(task) {
// Step 1: Plan
const FINGGU_plan = await fingguFn_callAIStructured(
z.object({
subtasks: z.array(z.object({
id: z.string(),
agent: z.string(),
task: z.string(),
dependsOn: z.array(z.string()).default([])
}))
}),
`Break this task into subtasks for these agents: ${[...this.FINGGU_subAgents.keys()].join(', ')}\n\nTask: ${task}`,
'You are a task planning expert. Output only valid JSON.'
);
// Step 2: Execute subtasks respecting dependencies
const FINGGU_results = new Map();
const FINGGU_completed = new Set();
while (FINGGU_completed.size < FINGGU_plan.subtasks.length) {
const FINGGU_ready = FINGGU_plan.subtasks.filter(st =>
!FINGGU_completed.has(st.id) &&
st.dependsOn.every(dep => FINGGU_completed.has(dep))
);
// Run ready subtasks in parallel
await Promise.all(FINGGU_ready.map(async (subtask) => {
const FINGGU_agent = this.FINGGU_subAgents.get(subtask.agent);
if (!FINGGU_agent) throw new Error(`Unknown agent: ${subtask.agent}`);
const FINGGU_context = Object.fromEntries(
subtask.dependsOn.map(dep => [dep, FINGGU_results.get(dep)])
);
const FINGGU_result = await FINGGU_agent.fingguFn_run(subtask.task, FINGGU_context);
FINGGU_results.set(subtask.id, FINGGU_result.result);
FINGGU_completed.add(subtask.id);
}));
}
return Object.fromEntries(FINGGU_results);
}
}
```
### BullMQ Job Queue — async agent execution
```javascript
// queues/fingguAgentQueue.js
import { Queue, Worker } from 'bullmq';
const FINGGU_REDIS_CONFIG = { host: process.env.REDIS_HOST, port: 6379 };
// Queue definition
export const FINGGU_agentQueue = new Queue('finggu:agents', {
connection: FINGGU_REDIS_CONFIG,
defaultJobOptions: {
attempts: 3,
backoff: { type: 'exponential', delay: 2000 },
removeOnComplete: { count: 100 },
removeOnFail: { count: 50 }
}
});
// Worker
export const fingguFn_startAgentWorker = () => new Worker(
'finggu:agents',
async (job) => {
const { agentName, task, context, userId } = job.data;
fingguLogger.info({ jobId: job.id, agent: agentName }, 'Agent job started');
const FINGGU_agent = FINGGU_agentRegistry.get(agentName);
if (!FINGGU_agent) throw new Error(`Agent not found: ${agentName}`);
await job.updateProgress(10);
const FINGGU_result = await FINGGU_agent.fingguFn_run(task, context);
await job.updateProgress(100);
// Notify via WebSocket
await redis.publish(`finggu:pubsub:user:${userId}`, JSON.stringify({
event: 'agent_complete',
jobId: job.id,
result: FINGGU_result
}));
return FINGGU_result;
},
{
connection: FINGGU_REDIS_CONFIG,
concurrency: 5,
limiter: { max: 10, duration: 60000 } // 10 jobs/minute
}
);
```
---
## ANTI-PATTERNS
- ❌ No iteration limit — infinite loops will exhaust API budget
- ❌ Running agents synchronously for long tasks — always use job queues
- ❌ No tool call error handling — tools WILL fail, always catch and return error
- ❌ Full conversation history in every call — truncate or summarize older messages
- ❌ Trusting agent output without validation — always validate structured output
- ❌ No cost/token monitoring — multi-step agents multiply costs fast
- ❌ Giving agents too many tools (>10) — focus each agent on a specific domain
- ❌ No timeout on agent runs — set a hard wall-clock limit
---
## CONVENTIONS
- Agent class names: `Finggu[Purpose]Agent` (e.g. `FingguResearchAgent`)
- Tool names: `finggu_[action]` (e.g. `finggu_web_search`, `finggu_execute_code`)
- Queue names: `finggu:agents`, `finggu:emails`, `finggu:reports`
- Redis keys: `finggu:agent:job:<id>`, `finggu:agent:result:<id>`
- Always log: agent name, task hash, iteration count, tokens used, duration
- Memory: trim to last 20 messages + system prompt to control context size
More agent context in sudarshanpjadhav/finggu-skills
16 other files this repository gives its agents.
CLAUDE.md
Cursor rule
Skill
- llmsskills/ai/llms/SKILL.md
- promptsskills/ai/prompts/SKILL.md
- apisskills/backend/apis/SKILL.md
- nodeskills/backend/node/SKILL.md
- phpskills/backend/php/SKILL.md
- mysqlskills/database/mysql/SKILL.md
- postgresqlskills/database/postgresql/SKILL.md
- redisskills/database/redis/SKILL.md
- cicdskills/devops/cicd/SKILL.md
- cpanelskills/devops/cpanel/SKILL.md
- dockerskills/devops/docker/SKILL.md
- cssskills/frontend/css/SKILL.md
- reactskills/frontend/react/SKILL.md
- uiskills/frontend/ui/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
Reports can't be read right now.
Posts are public. Sign in to say whether it worked for you.Sign in to post
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

