Agent skill
docs-nguyenquocviet2005-examples
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/docs-nguyenquocviet2005-examples
SKILL.md
Example Agent Skill: Text Analyzer
Overview
The Text Analyzer skill is a comprehensive example of how to build agent skills in AnythingLLM. It demonstrates all key patterns and best practices for skill development.
What It Does
The Text Analyzer skill performs four types of text analysis:
- Keywords - Extracts the top 10 most common meaningful words
- Sentiment - Determines if text is positive, negative, or neutral
- Statistics - Calculates word count, sentence count, character count, and averages
- Readability - Computes Flesch-Kincaid grade level for text difficulty
File Locations
- Backend Implementation:
server/utils/agents/aibitat/plugins/text-analyzer.js - Plugin Registration:
server/utils/agents/aibitat/plugins/index.js - Frontend UI:
frontend/src/pages/Admin/Agents/skills.js
How to Use
In a Chat with @agent
Users can invoke the skill by asking the agent to analyze text:
@agent: Analyze the sentiment of this paragraph: "I love this product! It's amazing and works perfectly."
Or:
@agent: What are the most common keywords in this article? [article text]
Skill Parameters
The skill accepts two parameters:
| Parameter | Type | Values | Description |
|---|---|---|---|
text |
string | Any text | The content to analyze |
analysis_type |
string | keywords, sentiment, statistics, readability |
Type of analysis to perform |
Architecture Breakdown
1. Skill Definition Object
const textAnalyzer = {
name: "text-analyzer", // Unique identifier
startupConfig: { params: {} }, // Optional config
plugin: function() { ... } // Plugin factory function
}
2. Plugin Setup
setup(aibitat) {
aibitat.function({
// Function metadata and schema
name: this.name,
description: "What this skill does",
// JSON Schema for input validation
parameters: { ... },
// Examples for LLM few-shot learning
examples: [ ... ],
// Main execution handler
handler: async function({ text, analysis_type }) { ... }
});
}
3. Handler Function Flow
handler() called
↓
Check for duplicates (prevent redundant calls)
↓
Route to appropriate analysis function
↓
Execute analysis logic
↓
Log action via introspect()
↓
Track execution
↓
Return result to LLM
Key Patterns Demonstrated
1. Deduplication
const { Deduplicator } = require("../utils/dedupe");
tracker: new Deduplicator(),
if (this.tracker.isDuplicate(this.name, { text, analysis_type })) {
return "Already analyzed.";
}
this.tracker.trackRun(this.name, { text, analysis_type });
Why: Prevents the agent from calling the same skill twice with identical parameters.
2. Function Metadata
parameters: {
$schema: "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
text: { type: "string" },
analysis_type: { type: "string", enum: [...] }
}
}
Why: Validates inputs and helps the LLM understand what parameters to provide.
3. Examples for LLM
examples: [
{
prompt: "What are the most common words in this text?",
call: JSON.stringify({ text: "...", analysis_type: "keywords" })
}
]
Why: Few-shot learning helps the LLM learn how to properly invoke the function.
4. Logging & Introspection
this.super.introspect(
`${this.caller}: Analyzing text for ${analysis_type}.`
);
this.super.handlerProps.log(`Error message`);
Why: Helps with debugging and provides visibility into skill execution.
5. Helper Methods
analyzeKeywords: async function(text) { ... }
analyzeSentiment: async function(text) { ... }
analyzeStatistics: async function(text) { ... }
analyzeReadability: async function(text) { ... }
Why: Organizing logic into separate methods keeps code clean and maintainable.
Extending the Example
Adding a New Analysis Type
- Add to enum in parameters:
analysis_type: {
enum: ["keywords", "sentiment", "statistics", "readability", "ngrams"]
}
- Add to switch statement in handler:
case "ngrams":
result = await this.analyzeNgrams(text);
break;
- Implement analysis method:
analyzeNgrams: async function(text) {
// Implementation here
return "Results";
}
Adding Socket Communication
For skills that need to send data to the frontend in real-time:
this.super.socket.send("eventName", {
key: "value",
data: "payload"
});
Examples in codebase:
rechart.js: SendsrechartVisualizeevent for chart renderingsave-file-browser.js: SendsfileDownloadevent for file downloads
Adding Complex Return Values
For skills that return structured data:
this.super._replySpecialAttributes = {
saveAsType: "customType",
storedResponse: (additionalText = "") =>
JSON.stringify({ data, additionalText }),
postSave: () => { /* cleanup */ }
};
Testing the Skill
Once enabled, the skill will be available to the agent. Test with:
@agent: Analyze the sentiment of "This is fantastic! I love it!"
Expected response:
Sentiment: Positive (Positive: 2, Negative: 0)
Available Context in Handler
Inside the handler, you have access to:
this.super // AIbitat framework instance
this.super.socket // WebSocket for real-time communication
this.super.introspect() // Log visible to frontend
this.super.handlerProps // Configuration and utilities
this.caller // Name of the agent calling this
this.tracker // Deduplication tracker
Common Skill Patterns
1. Search Skill (Like web-browsing)
Takes query string → performs search → returns results
2. Generation Skill (Like create-chart)
Takes data/parameters → generates content → sends via socket
3. Storage Skill (Like save-file-to-browser)
Takes content → prepares for storage → sends download signal
4. Analysis Skill (Text Analyzer - this example)
Takes content → performs calculation → returns formatted results
Skill Lifecycle
- Startup - Skill plugin
setup()called when AIbitat initializes - Function Registration -
aibitat.function()registers the skill - LLM Decision - Agent decides to call the skill
- Validation - Parameters validated against JSON Schema
- Execution - Handler function runs async logic
- Response - Result returned to LLM for processing
- Completion - Deduplication tracked for future calls
Best Practices
- ✅ Use JSON Schema for clear parameter validation
- ✅ Provide Examples for few-shot learning
- ✅ Handle Errors gracefully with try-catch
- ✅ Deduplicate to prevent redundant execution
- ✅ Log Actions via introspect() for debugging
- ✅ Document parameters and behavior
- ✅ Keep Handlers Async for I/O operations
- ✅ Return Clear Messages for user feedback
Anti-Patterns to Avoid
- ❌ Long-running Sync Operations - Use async/await
- ❌ Ignoring Deduplication - Always check for duplicates
- ❌ Unclear Parameter Names - Use descriptive names
- ❌ No Error Handling - Wrap in try-catch
- ❌ Complex Nested Callbacks - Use async/await
- ❌ Silent Failures - Always log errors
- ❌ No Examples - Provide few-shot examples
Related Skills in Codebase
memory.js- Search and store in RAG systemweb-browsing.js- Search using multiple enginessave-file-browser.js- Download files to clientsummarize.js- Summarize documentssql-agent/index.js- Query SQL databasesrechart.js- Render interactive charts
References
Didn't find tool you were looking for?