diff --git a/data/glossary-suggestions.json b/data/glossary-suggestions.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/data/glossary-suggestions.json @@ -0,0 +1 @@ +[] diff --git a/data/glossary.json b/data/glossary.json index 28fdbcc2..fe99bc58 100644 --- a/data/glossary.json +++ b/data/glossary.json @@ -1,247 +1,247 @@ [ { - "id": "agent", - "term": "Agent", - "definition": "An autonomous AI system that can perceive its environment, make decisions, and take actions to achieve specific goals. Unlike traditional chatbots, agents can use tools, access external data, and execute multi-step workflows.", - "relatedTerms": ["autonomy", "llm", "tool", "skill"], - "seeAlso": ["Multi-Agent System", "Agent Framework"] + "term": "ACP", + "definition": "Agent Communication Protocol, a structured approach for message exchange between autonomous systems with predictable schemas and transport semantics.", + "category": "protocols", + "relatedTerms": ["MCP", "Interoperability", "Tool Calling"], + "slug": "acp" }, { - "id": "autonomy", - "term": "Autonomy", - "definition": "The ability of an agent to operate independently, making decisions and taking actions without constant human intervention. Autonomous agents can plan, execute, and adapt to changing conditions.", - "relatedTerms": ["agent", "self-directed"], - "seeAlso": ["Agent", "Workflow"] + "term": "Agent", + "definition": "An autonomous software entity that can interpret goals, reason over context, and take actions using tools and workflows.", + "category": "core-concepts", + "relatedTerms": ["Autonomy", "Orchestration", "Tool Calling"], + "slug": "agent" }, { - "id": "bootstrap", - "term": "Bootstrap", - "definition": "The initial setup process for an agent, including configuration, identity establishment, and capability discovery. The bootstrap phase typically involves reading core files (SOUL.md, USER.md) and initializing the agent's workspace.", - "relatedTerms": ["initialization", "setup", "identity"], - "seeAlso": ["Gateway", "Identity"] + "term": "Agent Card", + "definition": "A machine-readable profile describing an agent's capabilities, interfaces, constraints, and metadata for discovery and trust.", + "category": "protocols", + "relatedTerms": ["Discovery", "Registry", "Identity"], + "slug": "agent-card" }, { - "id": "capability", - "term": "Capability", - "definition": "A specific function or skill that an agent can perform. Capabilities can be native (built into the agent platform) or acquired through skill installation and tool integration.", - "relatedTerms": ["skill", "tool", "function"], - "seeAlso": ["Skill", "Tool", "MCP"] + "term": "Autonomy", + "definition": "The degree to which an agent can decide and execute actions without requiring constant human confirmation.", + "category": "core-concepts", + "relatedTerms": ["Agent", "Guardrails", "Human-in-the-Loop"], + "slug": "autonomy" }, { - "id": "discovery", - "term": "Discovery", - "definition": "The process by which agents find and catalog available tools, skills, APIs, and other resources. Discovery mechanisms enable agents to adapt to new capabilities without manual configuration.", - "relatedTerms": ["registry", "capability", "protocol"], - "seeAlso": ["Registry", "Protocol"] + "term": "Chain of Thought", + "definition": "An internal reasoning process an LLM may use to arrive at an answer; typically kept private while exposing concise rationale.", + "category": "patterns", + "relatedTerms": ["Prompt Engineering", "Reflection", "Task Decomposition"], + "slug": "chain-of-thought" }, { - "id": "endpoint", - "term": "Endpoint", - "definition": "A network address (URL) where an API, service, or agent can be accessed. In agent systems, endpoints define where agents send requests and receive data from external services.", - "relatedTerms": ["api", "url", "webhook"], - "seeAlso": ["API", "Webhook", "Gateway"] + "term": "Context Window", + "definition": "The maximum amount of input and generated tokens an LLM can process in a single interaction cycle.", + "category": "infrastructure", + "relatedTerms": ["Token Budget", "Memory", "RAG"], + "slug": "context-window" }, { - "id": "framework", - "term": "Framework", - "definition": "A structured platform that provides the foundation for building and deploying agents. Agent frameworks typically include runtime environments, tool integrations, memory management, and orchestration capabilities.", - "relatedTerms": ["platform", "infrastructure", "openclaw"], - "seeAlso": ["OpenClaw", "Protocol"] + "term": "Discovery", + "definition": "The mechanism by which agents find tools, services, and other agents through metadata, registries, or protocol introspection.", + "category": "protocols", + "relatedTerms": ["Registry", "Agent Card", "Interoperability"], + "slug": "discovery" }, { - "id": "gateway", - "term": "Gateway", - "definition": "A service that routes messages and requests between agents, users, and external systems. Gateways handle authentication, protocol translation, and message delivery across different platforms.", - "relatedTerms": ["router", "proxy", "endpoint"], - "seeAlso": ["Endpoint", "Protocol", "OpenClaw"] + "term": "Embedding", + "definition": "A dense vector representation of text or data used for semantic search, retrieval, clustering, and similarity scoring.", + "category": "infrastructure", + "relatedTerms": ["RAG", "Vector Database", "Memory"], + "slug": "embedding" }, { - "id": "heartbeat", - "term": "Heartbeat", - "definition": "A periodic check-in mechanism where an agent proactively evaluates its state, environment, and pending tasks. Heartbeats enable agents to stay responsive and perform background maintenance without explicit user commands.", - "relatedTerms": ["polling", "monitoring", "proactive"], - "seeAlso": ["Autonomy", "Workflow"] + "term": "Evaluation Harness", + "definition": "A repeatable test system for scoring agent behavior against predefined tasks, metrics, and expected outcomes.", + "category": "patterns", + "relatedTerms": ["Observability", "Regression Testing", "Task Decomposition"], + "slug": "evaluation-harness" }, { - "id": "identity", - "term": "Identity", - "definition": "The unique identifier and associated metadata that defines an agent's persona, role, permissions, and authentication credentials. Agent identity is typically established during bootstrap and persists across sessions.", - "relatedTerms": ["authentication", "persona", "bootstrap"], - "seeAlso": ["Bootstrap", "Zero-Trust", "Verification"] + "term": "Function Calling", + "definition": "A model capability for emitting structured arguments that map to executable tools, APIs, or internal functions.", + "category": "protocols", + "relatedTerms": ["Tool Calling", "Schema Validation", "MCP"], + "slug": "function-calling" }, { - "id": "json-ld", - "term": "JSON-LD", - "definition": "JSON for Linking Data - a method of encoding linked data using JSON. In agent systems, JSON-LD provides structured, machine-readable metadata about skills, capabilities, and relationships between entities.", - "relatedTerms": ["metadata", "schema", "semantic-web"], - "seeAlso": ["Protocol", "Registry"] + "term": "Gateway", + "definition": "A routing and policy layer that brokers traffic between agents, users, and external systems with auth and rate limits.", + "category": "infrastructure", + "relatedTerms": ["Identity", "Zero Trust", "Interoperability"], + "slug": "gateway" }, { - "id": "kit", - "term": "Kit", - "definition": "A bundled collection of related skills, tools, and configurations designed to solve a specific use case. Kits provide a quick-start package for agents to gain multiple capabilities at once.", - "relatedTerms": ["bundle", "package", "skill"], - "seeAlso": ["Skill", "Tool"] + "term": "Guardrails", + "definition": "Safety, policy, and quality controls that constrain or validate model and agent actions before execution.", + "category": "security", + "relatedTerms": ["Prompt Injection", "Policy Enforcement", "Human-in-the-Loop"], + "slug": "guardrails" }, { - "id": "llm", - "term": "LLM", - "definition": "Large Language Model - a neural network trained on vast amounts of text data to understand and generate human language. LLMs power the reasoning and decision-making capabilities of AI agents.", - "relatedTerms": ["model", "ai", "reasoning"], - "seeAlso": ["Agent", "Tool"] + "term": "Human-in-the-Loop", + "definition": "An operating pattern where critical or high-risk actions require explicit human approval before completion.", + "category": "patterns", + "relatedTerms": ["Autonomy", "Guardrails", "Policy Enforcement"], + "slug": "human-in-the-loop" }, { - "id": "mcp", - "term": "MCP", - "definition": "Model Context Protocol - a standardized protocol for connecting LLMs to external data sources and tools. MCP servers expose capabilities that agents can discover and invoke dynamically.", - "relatedTerms": ["protocol", "integration", "tool"], - "seeAlso": ["Protocol", "Tool", "Discovery"] + "term": "Identity", + "definition": "A verifiable representation of an agent, user, or system principal used for authentication, authorization, and auditing.", + "category": "security", + "relatedTerms": ["Zero Trust", "Policy Enforcement", "Gateway"], + "slug": "identity" }, { - "id": "node", - "term": "Node", - "definition": "An individual instance or execution environment in a distributed agent system. Nodes can host agents, run tools, store data, or provide specialized capabilities within a network.", - "relatedTerms": ["instance", "runtime", "distributed"], - "seeAlso": ["Gateway", "Multi-Agent System"] + "term": "Interoperability", + "definition": "The ability of heterogeneous agent stacks and tools to work together through shared protocols and data contracts.", + "category": "protocols", + "relatedTerms": ["ACP", "MCP", "Discovery"], + "slug": "interoperability" }, { - "id": "openclaw", - "term": "OpenClaw", - "definition": "An open-source agent framework that provides tools for building, deploying, and managing AI agents. OpenClaw includes gateway services, skill management, and cross-platform integrations.", - "relatedTerms": ["framework", "platform", "gateway"], - "seeAlso": ["Framework", "Gateway", "Skill"] + "term": "Least Privilege", + "definition": "A security principle where each agent or tool is granted only the minimum permissions needed to perform tasks.", + "category": "security", + "relatedTerms": ["Zero Trust", "Policy Enforcement", "Identity"], + "slug": "least-privilege" }, { - "id": "protocol", - "term": "Protocol", - "definition": "A standardized set of rules and formats for communication between agents, tools, and services. Protocols ensure interoperability and enable agents to work with diverse systems.", - "relatedTerms": ["standard", "interface", "mcp"], - "seeAlso": ["MCP", "Gateway", "Endpoint"] + "term": "MCP", + "definition": "Model Context Protocol, a standard interface for connecting models and agents to external data sources and tools.", + "category": "protocols", + "relatedTerms": ["ACP", "Function Calling", "Tool Calling"], + "slug": "mcp" }, { - "id": "queue", - "term": "Queue", - "definition": "A data structure that manages tasks or messages in a first-in, first-out (FIFO) order. In agent systems, queues coordinate work distribution, handle asynchronous operations, and manage task priorities.", - "relatedTerms": ["task", "async", "workflow"], - "seeAlso": ["Workflow", "Multi-Agent System"] + "term": "Memory", + "definition": "Persisted or transient state that allows an agent to retain context, preferences, and prior outcomes across interactions.", + "category": "core-concepts", + "relatedTerms": ["RAG", "Context Window", "Vector Database"], + "slug": "memory" }, { - "id": "registry", - "term": "Registry", - "definition": "A centralized catalog of available skills, tools, agents, or services. Registries enable discovery and provide metadata about capabilities, versions, dependencies, and compatibility.", - "relatedTerms": ["catalog", "discovery", "repository"], - "seeAlso": ["Discovery", "Skill", "Protocol"] + "term": "Observability", + "definition": "Instrumentation for tracing, logging, and measuring agent behavior to diagnose quality, latency, and reliability issues.", + "category": "infrastructure", + "relatedTerms": ["Evaluation Harness", "Policy Enforcement", "Regression Testing"], + "slug": "observability" }, { - "id": "skill", - "term": "Skill", - "definition": "A packaged capability that agents can install and use to extend their functionality. Skills typically include installation scripts, configuration files (SKILL.md), and integration code for specific tools or services.", - "relatedTerms": ["capability", "plugin", "extension"], - "seeAlso": ["Tool", "Kit", "Capability"] + "term": "Orchestration", + "definition": "The coordination of multiple agents, tools, and workflow steps to achieve complex goals with dependency control.", + "category": "patterns", + "relatedTerms": ["Task Decomposition", "Workflow", "Multi-Agent System"], + "slug": "orchestration" }, { - "id": "tool", - "term": "Tool", - "definition": "A specific function or API that an agent can invoke to perform actions or retrieve information. Tools provide the building blocks for agent capabilities, from web searches to database queries.", - "relatedTerms": ["function", "api", "capability"], - "seeAlso": ["Skill", "MCP", "Capability"] + "term": "Policy Enforcement", + "definition": "Runtime application of organizational rules governing data access, action permissions, compliance, and approvals.", + "category": "security", + "relatedTerms": ["Guardrails", "Least Privilege", "Identity"], + "slug": "policy-enforcement" }, { - "id": "uri", - "term": "URI", - "definition": "Uniform Resource Identifier - a string that identifies a resource by location, name, or both. In agent systems, URIs provide standard ways to reference skills, tools, endpoints, and data sources.", - "relatedTerms": ["url", "identifier", "reference"], - "seeAlso": ["Endpoint", "Protocol"] + "term": "Prompt Engineering", + "definition": "Designing prompts, constraints, and examples to shape model outputs for reliability, relevance, and tool correctness.", + "category": "patterns", + "relatedTerms": ["Chain of Thought", "Reflection", "Tool Calling"], + "slug": "prompt-engineering" }, { - "id": "verification", - "term": "Verification", - "definition": "The process of confirming the authenticity, integrity, and authorization of agents, skills, or data. Verification mechanisms prevent unauthorized access and ensure trust in agent operations.", - "relatedTerms": ["authentication", "security", "trust"], - "seeAlso": ["Identity", "Zero-Trust"] + "term": "Prompt Injection", + "definition": "A security attack where malicious instructions are inserted into model inputs to override intended behavior or exfiltrate data.", + "category": "security", + "relatedTerms": ["Guardrails", "Zero Trust", "Sandboxing"], + "slug": "prompt-injection" }, { - "id": "webhook", - "term": "Webhook", - "definition": "An HTTP callback that delivers real-time data to applications when specific events occur. Agents use webhooks to receive notifications, trigger workflows, and integrate with external services.", - "relatedTerms": ["callback", "event", "integration"], - "seeAlso": ["Endpoint", "Gateway", "Protocol"] + "term": "RAG", + "definition": "Retrieval-Augmented Generation, a pattern that combines model inference with external retrieval to improve factual grounding.", + "category": "patterns", + "relatedTerms": ["Embedding", "Vector Database", "Memory"], + "slug": "rag" }, { - "id": "workflow", - "term": "Workflow", - "definition": "A sequence of tasks or operations that an agent executes to achieve a goal. Workflows can include conditional logic, loops, error handling, and coordination between multiple tools or agents.", - "relatedTerms": ["task", "pipeline", "orchestration"], - "seeAlso": ["Queue", "Multi-Agent System", "Autonomy"] + "term": "Reflection", + "definition": "An iterative reasoning pattern where an agent critiques and improves its own outputs before finalizing an action.", + "category": "patterns", + "relatedTerms": ["Prompt Engineering", "Task Decomposition", "Evaluation Harness"], + "slug": "reflection" }, { - "id": "x402", - "term": "x402", - "definition": "A protocol extension for micropayments and value exchange in agent-to-agent interactions. x402 enables agents to pay for API access, computational resources, or services from other agents.", - "relatedTerms": ["payment", "micropayment", "protocol"], - "seeAlso": ["Protocol", "Gateway"] + "term": "Regression Testing", + "definition": "Re-running known scenarios to ensure model updates, prompt changes, or infrastructure modifications do not degrade behavior.", + "category": "patterns", + "relatedTerms": ["Evaluation Harness", "Observability", "Workflow"], + "slug": "regression-testing" }, { - "id": "yaml", - "term": "YAML", - "definition": "YAML Ain't Markup Language - a human-readable data serialization format commonly used for configuration files. In agent systems, YAML files define skill manifests, workflow definitions, and environment settings.", - "relatedTerms": ["config", "format", "serialization"], - "seeAlso": ["JSON-LD", "Skill"] + "term": "Registry", + "definition": "A canonical directory for publishing and discovering agent capabilities, schemas, endpoints, and trust metadata.", + "category": "infrastructure", + "relatedTerms": ["Discovery", "Agent Card", "Interoperability"], + "slug": "registry" }, { - "id": "zero-trust", - "term": "Zero-Trust", - "definition": "A security model that assumes no user, device, or service should be trusted by default. In agent systems, zero-trust principles require continuous verification and least-privilege access for all operations.", - "relatedTerms": ["security", "verification", "authentication"], - "seeAlso": ["Verification", "Identity"] + "term": "Sandboxing", + "definition": "Executing code or tools in isolated environments to limit blast radius, protect secrets, and contain unsafe behavior.", + "category": "security", + "relatedTerms": ["Zero Trust", "Prompt Injection", "Policy Enforcement"], + "slug": "sandboxing" }, { - "id": "api", - "term": "API", - "definition": "Application Programming Interface - a set of rules and protocols that allows different software systems to communicate. Agents use APIs to access external services, retrieve data, and execute remote functions.", - "relatedTerms": ["interface", "endpoint", "integration"], - "seeAlso": ["Endpoint", "Tool", "MCP"] + "term": "Schema Validation", + "definition": "Checking structured inputs and outputs against a strict schema to prevent malformed tool invocations and runtime faults.", + "category": "protocols", + "relatedTerms": ["Function Calling", "Tool Calling", "Policy Enforcement"], + "slug": "schema-validation" }, { - "id": "context", - "term": "Context", - "definition": "The information and state that an agent maintains about its environment, conversation history, and current tasks. Context enables agents to make informed decisions and maintain continuity across interactions.", - "relatedTerms": ["state", "memory", "session"], - "seeAlso": ["Memory", "Session"] + "term": "Task Decomposition", + "definition": "Breaking complex objectives into smaller ordered subtasks that can be solved by one or more agents.", + "category": "patterns", + "relatedTerms": ["Orchestration", "Workflow", "Reflection"], + "slug": "task-decomposition" }, { - "id": "memory", - "term": "Memory", - "definition": "The persistent storage of information that agents use to recall past interactions, learned patterns, and important context. Memory can be short-term (session-based) or long-term (persistent across sessions).", - "relatedTerms": ["storage", "persistence", "context"], - "seeAlso": ["Context", "Session"] + "term": "Token Budget", + "definition": "The planned allocation of input and output tokens used to control cost, latency, and model context usage.", + "category": "infrastructure", + "relatedTerms": ["Context Window", "RAG", "Observability"], + "slug": "token-budget" }, { - "id": "multi-agent-system", - "term": "Multi-Agent System", - "definition": "An architecture where multiple specialized agents collaborate to solve complex problems. Multi-agent systems distribute tasks based on agent expertise and coordinate through message passing or shared state.", - "relatedTerms": ["distributed", "orchestration", "coordination"], - "seeAlso": ["Agent", "Queue", "Workflow"] + "term": "Tool Calling", + "definition": "The execution pattern where an agent selects and invokes external tools based on intent, context, and schema constraints.", + "category": "core-concepts", + "relatedTerms": ["Function Calling", "MCP", "Schema Validation"], + "slug": "tool-calling" }, { - "id": "orchestration", - "term": "Orchestration", - "definition": "The coordination and management of multiple agents, tools, or workflows to achieve complex goals. Orchestration involves task scheduling, dependency management, and resource allocation.", - "relatedTerms": ["coordination", "management", "workflow"], - "seeAlso": ["Multi-Agent System", "Workflow", "Queue"] + "term": "Vector Database", + "definition": "A storage engine optimized for high-dimensional similarity search, commonly used to power semantic retrieval for agents.", + "category": "infrastructure", + "relatedTerms": ["Embedding", "RAG", "Memory"], + "slug": "vector-database" }, { - "id": "prompt", - "term": "Prompt", - "definition": "The input text or instructions given to an LLM to guide its behavior and responses. In agent systems, prompts define the agent's role, capabilities, constraints, and decision-making strategies.", - "relatedTerms": ["instruction", "system-message", "llm"], - "seeAlso": ["LLM", "Agent", "Identity"] + "term": "Workflow", + "definition": "A defined sequence of states and operations that coordinates decisions, tool use, retries, and outputs toward a goal.", + "category": "core-concepts", + "relatedTerms": ["Orchestration", "Task Decomposition", "Regression Testing"], + "slug": "workflow" }, { - "id": "session", - "term": "Session", - "definition": "A temporary context or conversation instance that maintains state during a period of interaction. Sessions isolate conversations and track context that doesn't need to persist long-term.", - "relatedTerms": ["context", "instance", "temporary"], - "seeAlso": ["Context", "Memory"] + "term": "Zero Trust", + "definition": "A security model that continuously verifies identity and context rather than assuming trust based on network location.", + "category": "security", + "relatedTerms": ["Identity", "Least Privilege", "Sandboxing"], + "slug": "zero-trust" } ] diff --git a/src/app/api/glossary/route.ts b/src/app/api/glossary/route.ts index 7e8a2800..54d42a41 100644 --- a/src/app/api/glossary/route.ts +++ b/src/app/api/glossary/route.ts @@ -2,95 +2,231 @@ import { NextRequest, NextResponse } from "next/server"; import { promises as fs } from "node:fs"; import path from "node:path"; +type GlossaryCategory = + | "core-concepts" + | "protocols" + | "infrastructure" + | "security" + | "patterns"; + type GlossaryEntry = { - id: string; term: string; definition: string; + category: GlossaryCategory; relatedTerms: string[]; - seeAlso: string[]; + slug: string; +}; + +type GlossarySuggestion = { + id: string; + term: string; + definition: string; + category: GlossaryCategory; + slug: string; + createdAt: string; + status: "pending"; }; +const GLOSSARY_PATH = path.join(process.cwd(), "data", "glossary.json"); +const SUGGESTIONS_PATH = path.join(process.cwd(), "data", "glossary-suggestions.json"); + +const VALID_CATEGORIES: GlossaryCategory[] = [ + "core-concepts", + "protocols", + "infrastructure", + "security", + "patterns", +]; + +function isGlossaryCategory(value: unknown): value is GlossaryCategory { + return typeof value === "string" && VALID_CATEGORIES.includes(value as GlossaryCategory); +} + function isGlossaryEntry(value: unknown): value is GlossaryEntry { - if (!value || typeof value !== "object") { - return false; - } + if (!value || typeof value !== "object") return false; - const candidate = value as Partial; + const item = value as Partial; return ( - typeof candidate.id === "string" && - typeof candidate.term === "string" && - typeof candidate.definition === "string" && - Array.isArray(candidate.relatedTerms) && - Array.isArray(candidate.seeAlso) && - candidate.relatedTerms.every((term) => typeof term === "string") && - candidate.seeAlso.every((term) => typeof term === "string") + typeof item.term === "string" && + typeof item.definition === "string" && + isGlossaryCategory(item.category) && + typeof item.slug === "string" && + Array.isArray(item.relatedTerms) && + item.relatedTerms.every((term) => typeof term === "string") ); } +function slugify(value: string): string { + return value + .toLowerCase() + .trim() + .replace(/[^a-z0-9\s-]/g, "") + .replace(/\s+/g, "-") + .replace(/-+/g, "-"); +} + async function readGlossaryFile(): Promise { - const glossaryPath = path.join(process.cwd(), "data", "glossary.json"); - const raw = await fs.readFile(glossaryPath, "utf8"); - const parsed = JSON.parse(raw) as unknown; + try { + const raw = await fs.readFile(GLOSSARY_PATH, "utf8"); + const parsed = JSON.parse(raw) as unknown; + if (!Array.isArray(parsed)) return []; + return parsed.filter(isGlossaryEntry); + } catch { + return []; + } +} - if (!Array.isArray(parsed)) { +async function readSuggestionFile(): Promise { + try { + const raw = await fs.readFile(SUGGESTIONS_PATH, "utf8"); + const parsed = JSON.parse(raw) as unknown; + if (!Array.isArray(parsed)) return []; + + return parsed.filter((item) => { + if (!item || typeof item !== "object") return false; + const candidate = item as Partial; + return ( + typeof candidate.id === "string" && + typeof candidate.term === "string" && + typeof candidate.definition === "string" && + isGlossaryCategory(candidate.category) && + typeof candidate.slug === "string" && + typeof candidate.createdAt === "string" && + candidate.status === "pending" + ); + }); + } catch { return []; } +} - return parsed.filter(isGlossaryEntry); +async function writeSuggestionFile(suggestions: GlossarySuggestion[]): Promise { + await fs.writeFile(SUGGESTIONS_PATH, `${JSON.stringify(suggestions, null, 2)}\n`, "utf8"); } export async function GET(request: NextRequest) { - try { - const allTerms = await readGlossaryFile(); - - const search = request.nextUrl.searchParams.get("search")?.trim().toLowerCase() ?? ""; - const letterParam = request.nextUrl.searchParams.get("letter")?.trim().toUpperCase() ?? ""; - const letter = /^[A-Z]$/.test(letterParam) ? letterParam : ""; - - const letters = Array.from( - new Set(allTerms.map((entry) => entry.term.charAt(0).toUpperCase()).filter((char) => /^[A-Z]$/.test(char))) - ).sort(); - - const filteredTerms = allTerms - .filter((entry) => { - if (search) { - const matchesSearch = - entry.term.toLowerCase().includes(search) || - entry.definition.toLowerCase().includes(search); - if (!matchesSearch) { - return false; - } - } - - if (letter) { - return entry.term.charAt(0).toUpperCase() === letter; - } - - return true; - }) - .sort((a, b) => a.term.localeCompare(b.term)); + const allTerms = await readGlossaryFile(); - return NextResponse.json( - { - terms: filteredTerms, - total: filteredTerms.length, - letters, - }, - { - headers: { - "Cache-Control": "no-store", - }, + const search = request.nextUrl.searchParams.get("search")?.trim().toLowerCase() ?? ""; + const letterParam = request.nextUrl.searchParams.get("letter")?.trim().toUpperCase() ?? ""; + const letter = /^[A-Z]$/.test(letterParam) ? letterParam : ""; + + const letters = Array.from( + new Set( + allTerms + .map((entry) => entry.term.charAt(0).toUpperCase()) + .filter((char) => /^[A-Z]$/.test(char)) + ) + ).sort(); + + const filteredTerms = allTerms + .filter((entry) => { + if (search) { + const matchesSearch = + entry.term.toLowerCase().includes(search) || + entry.definition.toLowerCase().includes(search) || + entry.category.toLowerCase().includes(search); + + if (!matchesSearch) return false; + } + + if (letter) { + return entry.term.charAt(0).toUpperCase() === letter; } + + return true; + }) + .sort((a, b) => a.term.localeCompare(b.term)); + + return NextResponse.json( + { + terms: filteredTerms, + total: filteredTerms.length, + letters, + categories: VALID_CATEGORIES, + }, + { + headers: { + "Cache-Control": "no-store", + }, + } + ); +} + +export async function POST(request: NextRequest) { + try { + const body = (await request.json()) as Record; + + const term = typeof body.term === "string" ? body.term.trim() : ""; + const definition = typeof body.definition === "string" ? body.definition.trim() : ""; + const category = body.category; + + const errors: string[] = []; + + if (!term) errors.push("term is required"); + if (term.length > 100) errors.push("term must be 100 characters or less"); + + if (!definition) errors.push("definition is required"); + if (definition.length > 1200) errors.push("definition must be 1200 characters or less"); + + if (!isGlossaryCategory(category)) { + errors.push(`category must be one of: ${VALID_CATEGORIES.join(", ")}`); + } + + if (errors.length > 0) { + return NextResponse.json({ error: "Validation failed", details: errors }, { status: 400 }); + } + + const slug = slugify(term); + if (!slug) { + return NextResponse.json({ error: "Invalid term. Could not generate slug." }, { status: 400 }); + } + + const validatedCategory = category as GlossaryCategory; + + const [allTerms, suggestions] = await Promise.all([readGlossaryFile(), readSuggestionFile()]); + + const termExists = allTerms.some( + (entry) => entry.slug === slug || entry.term.toLowerCase() === term.toLowerCase() ); - } catch { + + if (termExists) { + return NextResponse.json({ error: "This term already exists in the glossary." }, { status: 409 }); + } + + const pendingExists = suggestions.some( + (entry) => entry.slug === slug || entry.term.toLowerCase() === term.toLowerCase() + ); + + if (pendingExists) { + return NextResponse.json( + { error: "A suggestion for this term is already pending review." }, + { status: 409 } + ); + } + + const suggestion: GlossarySuggestion = { + id: `glossary_suggestion_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`, + term, + definition, + category: validatedCategory, + slug, + createdAt: new Date().toISOString(), + status: "pending", + }; + + await writeSuggestionFile([...suggestions, suggestion]); + return NextResponse.json( { - terms: [], - total: 0, - letters: [], + success: true, + message: "Thanks! Your term suggestion has been submitted for review.", + suggestion, }, - { status: 200 } + { status: 201 } ); + } catch { + return NextResponse.json({ error: "Invalid request body. Expected JSON." }, { status: 400 }); } } diff --git a/src/app/glossary/page.tsx b/src/app/glossary/page.tsx index e7480b3d..f698328f 100644 --- a/src/app/glossary/page.tsx +++ b/src/app/glossary/page.tsx @@ -1,22 +1,53 @@ +/* eslint-disable react/no-unescaped-entities */ "use client"; -import { useEffect, useMemo, useState } from "react"; +import { FormEvent, useEffect, useMemo, useState } from "react"; import Link from "next/link"; +type GlossaryCategory = + | "core-concepts" + | "protocols" + | "infrastructure" + | "security" + | "patterns"; + interface GlossaryEntry { - id: string; term: string; definition: string; + category: GlossaryCategory; relatedTerms: string[]; - seeAlso: string[]; + slug: string; } interface GlossaryResponse { terms: GlossaryEntry[]; total: number; letters: string[]; + categories: GlossaryCategory[]; } +const CATEGORY_LABELS: Record = { + "core-concepts": "Core Concepts", + protocols: "Protocols", + infrastructure: "Infrastructure", + security: "Security", + patterns: "Patterns", +}; + +const CATEGORY_BADGE_STYLES: Record = { + "core-concepts": "bg-sky-500/10 border-sky-500/30 text-sky-300", + protocols: "bg-violet-500/10 border-violet-500/30 text-violet-300", + infrastructure: "bg-amber-500/10 border-amber-500/30 text-amber-300", + security: "bg-rose-500/10 border-rose-500/30 text-rose-300", + patterns: "bg-emerald-500/10 border-emerald-500/30 text-emerald-300", +}; + +const EMPTY_FORM = { + term: "", + definition: "", + category: "core-concepts" as GlossaryCategory, +}; + export default function GlossaryPage() { const [searchInput, setSearchInput] = useState(""); const [debouncedSearch, setDebouncedSearch] = useState(""); @@ -25,13 +56,20 @@ export default function GlossaryPage() { const [total, setTotal] = useState(0); const [availableLetters, setAvailableLetters] = useState([]); const [isLoading, setIsLoading] = useState(false); + const [loadError, setLoadError] = useState(null); + const [refreshNonce, setRefreshNonce] = useState(0); + + const [formData, setFormData] = useState(EMPTY_FORM); + const [isSubmitting, setIsSubmitting] = useState(false); + const [submitError, setSubmitError] = useState(null); + const [submitSuccess, setSubmitSuccess] = useState(null); const webPageJsonLd = { "@context": "https://schema.org", "@type": "WebPage", name: "Agent Terminology Glossary — forAgents.dev", description: - "Comprehensive glossary of AI agent terms, protocols, and concepts. From Agent to Zero-Trust, learn the language of autonomous AI development.", + "Comprehensive glossary of AI agent terms, protocols, and concepts. From Agent to Zero Trust, learn the language of autonomous AI development.", url: "https://foragents.dev/glossary", }; @@ -40,7 +78,7 @@ export default function GlossaryPage() { useEffect(() => { const timeout = setTimeout(() => { setDebouncedSearch(searchInput.trim()); - }, 300); + }, 250); return () => clearTimeout(timeout); }, [searchInput]); @@ -50,6 +88,7 @@ export default function GlossaryPage() { const fetchGlossary = async () => { setIsLoading(true); + setLoadError(null); try { const params = new URLSearchParams(); @@ -68,10 +107,11 @@ export default function GlossaryPage() { }); if (!response.ok) { - throw new Error("Failed to fetch glossary terms"); + throw new Error("Failed to load glossary terms."); } const data = (await response.json()) as GlossaryResponse; + setTerms(Array.isArray(data.terms) ? data.terms : []); setTotal(typeof data.total === "number" ? data.total : 0); setAvailableLetters(Array.isArray(data.letters) ? data.letters : []); @@ -80,6 +120,7 @@ export default function GlossaryPage() { setTerms([]); setTotal(0); setAvailableLetters([]); + setLoadError("Couldn't load glossary data right now. Please try again."); } } finally { if (!controller.signal.aborted) { @@ -91,7 +132,7 @@ export default function GlossaryPage() { void fetchGlossary(); return () => controller.abort(); - }, [debouncedSearch, selectedLetter]); + }, [debouncedSearch, selectedLetter, refreshNonce]); const groupedEntries = useMemo(() => { const groups: Record = {}; @@ -114,6 +155,7 @@ export default function GlossaryPage() { for (const entry of terms) { map.set(entry.term.toLowerCase(), entry); + map.set(entry.slug.toLowerCase(), entry); } return map; @@ -143,6 +185,46 @@ export default function GlossaryPage() { setSelectedLetter(null); }; + const handleSuggestionSubmit = async (event: FormEvent) => { + event.preventDefault(); + + setSubmitError(null); + setSubmitSuccess(null); + setIsSubmitting(true); + + try { + const response = await fetch("/api/glossary", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + term: formData.term.trim(), + definition: formData.definition.trim(), + category: formData.category, + }), + }); + + const data = (await response.json()) as { + message?: string; + error?: string; + details?: string[]; + }; + + if (!response.ok) { + const details = Array.isArray(data.details) ? data.details.join(" ") : ""; + throw new Error(data.error ? `${data.error}${details ? ` ${details}` : ""}` : "Submit failed."); + } + + setSubmitSuccess(data.message ?? "Suggestion submitted."); + setFormData(EMPTY_FORM); + } catch (error) { + setSubmitError((error as Error).message || "Couldn't submit suggestion."); + } finally { + setIsSubmitting(false); + } + }; + return (