TODO: Update Tag Filtering Logic in Featured Agents
This document outlines the steps to refine the tag filtering functionality in `ai-agent-hub-web/components/featured-agents.tsx` by utilizing a tag alias map. The goal is to reduce redundancy in displayed filter tags and improve user experience.
TODO: Update Tag Filtering Logic in Featured Agents
This document outlines the steps to refine the tag filtering functionality in ai-agent-hub-web/components/featured-agents.tsx by utilizing a tag alias map. The goal is to reduce redundancy in displayed filter tags and improve user experience.
1. Manually Review and Refine tagAliasMap
The automatically generated tag_aliases_proposal.ts provides a starting point. It needs careful manual review to ensure accuracy and completeness.
File to review: tag_aliases_proposal.ts
Content of tag_aliases_proposal.ts (as of generation):
// Generated by script. Please review and refine manually.
// This is a best-effort attempt and may require significant curation.
const tagAliasMap: Record<string, string[]> = {
"12-factor": ["12-factor-agents"],
"3d": ["3d-engine", "3d-model", "3d-models"],
"a2a": ["a2a-protocol", "a2a-server"],
"actor": ["actor-framework", "actors"],
"aea": ["open-aea"],
"agent": ["agent-based", "agent-framework", "agent-runtime", "agents", "multi-agent"],
"agent-monitoring": ["ai-agent-monitoring"],
"agent-tools": ["ai-agent-tools"],
"agentic": ["agentic-framework"],
"agentic-ai": ["agentic-ai-cli"],
"agents-sdk": ["ai-agents-sdk"],
"ai": ["ai-agent", "ai-agents", "ai-framework", "ai-os", "ai-platform", "ai-runtime", "gen-ai"],
"ai-agent-framework": ["aiagentframework"],
"ai-agents-framework": ["aiagentsframework"],
"ai-directory": ["ai-directories"],
"aiagent": ["aiagents"],
"api": ["api-platform", "apis"],
"api-gateway": ["apigateway"],
"api-management": ["apimanagement"],
"app": ["apps"],
"application": ["llm-application"],
"art": ["ai-art"],
"assistant": ["ai-assistant", "assistants"],
"automatic": ["automatic-api"],
"automation": ["automation-framework", "web-automation"],
"autonomous": ["autonomous-agent", "autonomous-agents"],
"autonomous agent": ["autonomous agents"],
"autonomy": ["open-autonomy"],
"awesome-list": ["awesome-lists"],
"azd-templates": ["ai-azd-templates"],
"azure-openai": ["azureopenai"],
"baby-agi": ["babyagi"],
"benchmark": ["ai-benchmark", "benchmark-framework"],
"bot": ["bot-framework"],
"chat": ["ai-chat"],
"chatbot": ["chatbot-framework", "chatbots"],
"chatgpt": ["chatgpt-api", "chatgpt-app"],
"chest-xray": ["chest-xrays"],
"claude": ["claude-api"],
"cli": ["cli-app"],
"cloud-native": ["cloudnative"],
"cloudflare": ["cloudflare-agents"],
"cloudflare-worker": ["cloudflare-workers"],
"code-review": ["ai-code-review"],
"coding": ["ai-coding", "coding-agents"],
"command-line": ["command-line-tool"],
"community": ["community-driven"],
"component": ["components"],
"container": ["containers"],
"conversational": ["conversational-agents"],
"course": ["courses"],
"crawler": ["crawlers", "web-crawler"],
"crawling": ["web-crawling"],
"crdt": ["crdts"],
"cryptocurrency": ["cryptocurrencies"],
"cursor-ai": ["cursorai"],
"dashboard": ["dashboards"],
"data": ["data-driven"],
"data-analysis": ["ai-data-analysis"],
"data-flow": ["dataflow"],
"database": ["databases"],
"deployment": ["llm-deployment"],
"design": ["design-system"],
"desktop": ["desktop-agent", "desktop-app", "web-desktop"],
"developer-tools": ["ai-developer-tools"],
"development": ["ai-development"],
"distributed": ["distributed-system"],
"ecommerce": ["ecommerce-platform"],
"elevenlabs": ["elevenlabs-api"],
"email": ["emails"],
"embedding": ["embeddings"],
"embodied": ["embodied-agent", "embodied-agents"],
"engineering": ["ai-engineering"],
"etl": ["etl-framework"],
"evaluation": ["ai-evaluation", "evaluation-framework", "evaluation-metrics", "llm-evaluation"],
"fine-tuning": ["finetuning"],
"foundation-model": ["foundation-models"],
"framwork": ["ai-framwork"],
"full-stack": ["fullstack"],
"function-call": ["llm-function-call"],
"function-calling": ["llm-function-calling"],
"game": ["game-engine", "games"],
"gateway": ["ai-gateway", "llm-gateway"],
"gemini": ["gemini-api"],
"genai": ["genai-agents"],
"generative": ["generative-agents", "generative-model", "generative-models"],
"generative-ai": ["generativeai"],
"github": ["github-api", "github-models"],
"godot": ["godot-engine"],
"golang-whatsapp": ["golang-whatsapp-api"],
"gpt": ["auto-gpt", "gpts"],
"gpt-3": ["gpt3"],
"gpt-4": ["gpt-4-api", "gpt4"],
"gpt-4o": ["gpt-4o-api", "gpt4o"],
"graph-rag": ["graphrag"],
"guardrails": ["llm-guardrails"],
"gui": ["gui-agents"],
"inference": ["inference-ui", "llm-inference"],
"integration": ["integration-framework", "integrations"],
"javascript": ["javascript-sdk"],
"job": ["jobs"],
"knowledge": ["knowledge-base", "knowledge-graph"],
"knowlege": ["knowlege-base"],
"lab": ["labs"],
"langchain": ["langchain-agent", "langchain-agents", "langchain-app"],
"language model": ["language models"],
"language-model": ["language-models"],
"large-language-model": ["large-language-models"],
"list": ["ai-list"],
"live-chat": ["livechat"],
"llama": ["llama-api"],
"llama-index": ["llamaindex"],
"llm": ["llm-agent", "llm-agents", "llm-apps", "llm-chain", "llm-framework", "llm-interface", "llm-ops", "llms"],
"local-ai": ["localai"],
"local-llm": ["localllm"],
"low-code": ["low-code-platform"],
"machine-learning": ["machinelearning"],
"mcp": ["mcp-agent", "mcp-client", "mcp-framework", "mcp-server", "mcps"],
"memory": ["ai-memory"],
"microservice": ["microservices"],
"midjourney": ["midjourney-app"],
"mind-map": ["mindmap"],
"ml": ["ml-ops"],
"ml-engineering": ["mlengineering"],
"model-context-protocol": ["modelcontextprotocol"],
"multi-agent-system": ["multi-agent-systems"],
"multi-ai-agent": ["multi-ai-agents"],
"music": ["ai-music"],
"native": ["ai-native"],
"news": ["news-agent"],
"newsletter": ["ai-newsletter", "newsletters"],
"nlp": ["natural-language-processing"],
"observability": ["llm-observability"],
"obsidian-md": ["obsidianmd"],
"ollama": ["ollama-client", "ollama-ui"],
"open-source": ["open-source-gpt", "opensource"],
"openai": ["openai-agents", "openai-api"],
"openai-assistants": ["openai-assistants-api"],
"openapi-generator": ["openapi-generators"],
"operating-system": ["operating-systems"],
"os": ["llm-os"],
"paper": ["paper-agent", "papers"],
"payment": ["payments"],
"playground": ["ai-playground"],
"plugin": ["plugins"],
"pocket-flow": ["pocketflow"],
"prisma": ["prisma-client"],
"privacy": ["llm-privacy"],
"productivity": ["productivity-app"],
"prompt": ["prompts"],
"proxy": ["proxies", "proxy-server"],
"python": ["python-library", "python-sdk"],
"question-answering": ["question-answering-system"],
"rag": ["llm-rag", "retrieval-augmented-generation"],
"real-time": ["real-time-data"],
"realtime": ["realtime-api"],
"reasoning": ["llm-reasoning", "reasoning-agent"],
"red-team": ["redteam"],
"research": ["ai-research"],
"resources": ["dev-resources"],
"rest": ["rest-api"],
"routing": ["llm-routing"],
"saleor": ["saleor-app"],
"scraping": ["ai-scraping", "web-scraping"],
"search": ["search-agent", "search-engine"],
"security": ["ai-security", "llm-security"],
"server": ["servers"],
"serving": ["llm-serving"],
"shadcn": ["shadcn-ui"],
"shell": ["shell-gpt"],
"simulation": ["simulation-framework"],
"smart-glasses": ["smartglasses"],
"spreadsheet": ["spreadsheets"],
"sql": ["sql-server"],
"starter": ["starter-kit"],
"structured-output": ["structured-outputs"],
"summer-school": ["summer-schools"],
"suno-ai": ["suno-ai-api"],
"survey": ["surveys"],
"swarm": ["ai-swarm", "swarms"],
"swe": ["swe-agent"],
"t3": ["t3-stack"],
"tavily": ["tavily-api"],
"team": ["teams"],
"tensorflow": ["tensorflow-library"],
"terminal": ["terminal-app"],
"testing": ["llm-testing"],
"text-to-speech": ["text-to-speech-app"],
"tool": ["tools"],
"toolkit": ["ai-toolkit", "toolkits"],
"tracing": ["llm-tracing"],
"training": ["llm-training"],
"transformer": ["transformers"],
"tutorial": ["tutorials"],
"ui": ["llm-ui"],
"unified": ["unified-api"],
"unofficial-api": ["unofficial-apis"],
"vector": ["vector-db"],
"vector-search": ["vectorsearch"],
"vertex-ai": ["vertexai"],
"virtual-assistant": ["virtualassistant"],
"virtualization": ["virtualization-framework"],
"voice": ["voice-agent", "voice-agents"],
"voice-assistant": ["ai-voice-assistant"],
"vulcan-sql": ["vulcansql"],
"wearable": ["wearables"],
"web": ["web-agent", "web-data"],
"webui": ["llm-webui", "open-webui"],
"whatsapp": ["whatsapp-api"],
"workflow": ["ai-workflow", "workflow-engine", "workflows"],
};
export default tagAliasMap;
Action:
- Go through the
tagAliasMap. - Add, remove, or modify entries to ensure semantic groupings are correct and useful.
- For example, ensure "llm" is the primary tag for "large language model", "llms", etc.
- Consider edge cases and desired specificity.
2. Integrate tagAliasMap into featured-agents.tsx
Modify the component to use the curated tagAliasMap.
File to edit: ai-agent-hub-web/components/featured-agents.tsx
Steps:
-
Import
tagAliasMap:import tagAliasMap from "@/path/to/your/tag_aliases_proposal"; // Adjust path as necessary(Note: After review, you might rename
tag_aliases_proposal.tsto something liketag-alias-map.tsand place it in a suitable directory, e.g.,ai-agent-hub-web/lib/). -
Update
tagsPerCategoryCalculation:- When calculating
tagsPerCategory, transform the raw tags from agents into their primary display versions usingtagAliasMap. - The goal is to have
tagsPerCategory[category.id]contain only the keys fromtagAliasMap(primary tags) plus any tags not found in the map (which are considered primary by default).
Current Logic (Simplified):
const tagsPerCategory = useMemo(() => { const calculatedTags: Record<string, string[]> = {}; categories.forEach(category => { const allTagsForCategory = new Set<string>(); category.agents.forEach(agent => { agent.tags.forEach(tag => allTagsForCategory.add(tag)); }); calculatedTags[category.id] = Array.from(allTagsForCategory).sort(); }); return calculatedTags; }, [categories]);Proposed Update Snippet (Conceptual):
// Helper to get primary tag or original if not in map const getPrimaryTag = (tag: string): string => { for (const [primary, aliases] of Object.entries(tagAliasMap)) { if (aliases.includes(tag.toLowerCase()) || primary === tag.toLowerCase()) { return primary; } } return tag; // Return original (lowercased) if no mapping found }; const tagsPerCategory = useMemo(() => { const calculatedTags: Record<string, string[]> = {}; categories.forEach(category => { const allDisplayTagsForCategory = new Set<string>(); category.agents.forEach(agent => { agent.tags.forEach(rawTag => { allDisplayTagsForCategory.add(getPrimaryTag(rawTag)); }); }); calculatedTags[category.id] = Array.from(allDisplayTagsForCategory).sort(); }); return calculatedTags; }, [categories, tagAliasMap]); // Add tagAliasMap to dependenciesSelf-correction: The
getPrimaryTaghelper above is not quite right for only showing keys. The logic should be: iterate agent tags, find their primary mapping if one exists, otherwise use the tag itself. Then collect unique primary tags.Revised Proposed Update Snippet (Conceptual):
const getPrimaryDisplayTag = (rawTag: string): string => { const lowerRawTag = rawTag.toLowerCase(); for (const [primary, aliases] of Object.entries(tagAliasMap)) { if (primary === lowerRawTag || aliases.includes(lowerRawTag)) { return primary; // Return the key (primary tag) } } return lowerRawTag; // If not in map (neither key nor alias), use the lowercased original tag }; const tagsPerCategory = useMemo(() => { const calculatedTags: Record<string, string[]> = {}; categories.forEach(category => { const displayablePrimaryTags = new Set<string>(); category.agents.forEach(agent => { agent.tags.forEach(rawTag => { displayablePrimaryTags.add(getPrimaryDisplayTag(rawTag)); }); }); calculatedTags[category.id] = Array.from(displayablePrimaryTags).sort(); }); return calculatedTags; }, [categories]); // Assuming tagAliasMap is imported and stable - When calculating
-
Update Agent Filtering Logic:
- When filtering agents based on
selectedFilterTags(which now contain primary tags), the agent's tags must also be mapped to their primary versions before checking for inclusion.
Current Logic (Simplified):
const filteredAgents = currentCategorySelectedTags.length === 0 ? category.agents : category.agents.filter(agent => agent.tags && agent.tags.some(agentTag => currentCategorySelectedTags.includes(agentTag)) );Proposed Update Snippet (Conceptual):
const filteredAgents = currentCategorySelectedTags.length === 0 ? category.agents : category.agents.filter(agent => { if (!agent.tags) return false; // Get primary display tags for this agent const agentPrimaryTags = new Set(agent.tags.map(rawTag => getPrimaryDisplayTag(rawTag))); // Check if any of the agent's primary tags are in the selected filter tags return currentCategorySelectedTags.some(selectedPrimaryTag => agentPrimaryTags.has(selectedPrimaryTag)); } ); - When filtering agents based on
-
Ensure
handleTagClickandclearCategoryFilterswork with primary tags.handleTagClickshould receive the primary tag when a tag button (which now displays a primary tag) is clicked. This should be inherently handled ifcategoryUniqueTags(which populates the buttons) is correctly derived from primary tags.
3. Testing
Thoroughly test the updated filtering logic.
-
Manual Testing:
- Verify that the displayed filter tags for each category are indeed the primary tags (keys from
tagAliasMapor unmapped tags). - Check that selecting a primary filter tag correctly filters agents that have either that primary tag OR any of its alias tags (values from
tagAliasMap). - Test with multiple selected filter tags (OR logic should still apply to primary tags).
- Test categories with many tags, few tags, and no tags.
- Test the "Show all / Collapse" functionality for tags.
- Test clearing filters.
- Verify that the displayed filter tags for each category are indeed the primary tags (keys from
-
Unit Testing (Conceptual):
-
Goal: Ensure that the UI only displays primary tags for selection and that filtering correctly uses the alias map.
-
Test Case 1:
tagsPerCategorygeneration- Given: A mock list of categories with agents having various tags (including aliases).
- And: A defined
tagAliasMap. - When:
tagsPerCategoryis computed. - Then: The resulting list of unique tags for a category should only contain primary tags (keys from the map or unmapped tags), and no alias tags directly.
- Example:
// Mock data const mockAgents = [ { tags: ["llm-agent", "fast"] }, // "llm-agent" is an alias for "llm" { tags: ["llm", "slow"] }, // "llm" is a primary tag { tags: ["experimental"] } // "experimental" is not in map ]; const mockTagAliasMap = { "llm": ["llm-agent", "large-language-model"] }; // Simplified conceptual test logic const primaryTags = getUniquePrimaryTagsForCategory(mockAgents, mockTagAliasMap); expect(primaryTags).toContain("llm"); expect(primaryTags).toContain("fast"); expect(primaryTags).toContain("slow"); expect(primaryTags).toContain("experimental"); expect(primaryTags).not.toContain("llm-agent"); expect(primaryTags.length).toBe(4); // Or whatever the expected count of unique primary tags is
-
Test Case 2: Agent filtering with aliasing
- Given: A list of mock agents, some with primary tags, some with alias tags.
- And: A defined
tagAliasMap. - When: A primary tag is selected for filtering (e.g., "llm").
- Then: Agents containing either the primary tag "llm" OR any of its aliases (e.g., "llm-agent") should be included in the filtered results.
- Example:
(Note:const agent1 = { name: "Agent A", tags: ["llm-agent", "data"] }; // Alias const agent2 = { name: "Agent B", tags: ["llm", "visualization"] }; // Primary const agent3 = { name: "Agent C", tags: ["ai", "automation"] }; // Different tag const mockAgents = [agent1, agent2, agent3]; const mockTagAliasMap = { "llm": ["llm-agent", "llms"] }; const selectedFilters = ["llm"]; const filtered = filterAgentsWithAliases(mockAgents, selectedFilters, mockTagAliasMap); expect(filtered).toContain(agent1); expect(filtered).toContain(agent2); expect(filtered).not.toContain(agent3);filterAgentsWithAliaseswould encapsulate the filtering logic fromfeatured-agents.tsx)
-
4. Code Cleanup and Final Review
- Move the finalized
tagAliasMapto a sensible location (e.g.,ai-agent-hub-web/lib/tag-alias-map.ts). - Update import paths.
- Remove any console logs or temporary code.
- Perform a final code review.
Related Documents
AI Tools for Developers
Attachments (**docs or images**) supported in chat.
Lesson 01: Evaluation Frameworks Overview
**Module 07: Evaluation and Testing**
Evaluating AI Agent Systems: Metrics, Benchmarks, and Quality Assurance (2024-2026)
> Research compiled February 2026 for the **aiai** self-improving AI infrastructure project.
IATA BCBP Standard Compliance
**Implementation Guide:** IATA Resolution 792 - Bar Coded Boarding Pass (BCBP)