diff --git a/.env.example b/.env.example index 9f9c8c15..065cfeca 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,9 @@ API_URL="http://localhost:8000" ORGANIZATION_NAME="Evo AI" ORGANIZATION_URL="https://evoai.evoapicloud.com" +# AI Engine configuration: "adk" or "crewai" +AI_ENGINE="adk" + # Database settings POSTGRES_CONNECTION_STRING="postgresql://postgres:root@localhost:5432/evo_ai" diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml new file mode 100644 index 00000000..71424f1f --- /dev/null +++ b/.github/workflows/build-and-deploy.yml @@ -0,0 +1,149 @@ +name: Build and Deploy Docker Images + +on: + push: + branches: + - main + tags: + - "*.*.*" + pull_request: + branches: + - main + +jobs: + detect-changes: + name: Detect Changes + runs-on: ubuntu-latest + outputs: + backend-changed: ${{ steps.changes.outputs.backend }} + frontend-changed: ${{ steps.changes.outputs.frontend }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Detect changes + id: changes + uses: dorny/paths-filter@v2 + with: + filters: | + backend: + - 'src/**' + - 'migrations/**' + - 'scripts/**' + - 'Dockerfile' + - 'pyproject.toml' + - 'alembic.ini' + - 'conftest.py' + - 'setup.py' + - 'Makefile' + - '.dockerignore' + frontend: + - 'frontend/**' + + build-backend: + name: Build Backend Image + runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.backend-changed == 'true' || github.event_name == 'push' + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: evoapicloud/evo-ai + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} + + build-frontend: + name: Build Frontend Image + runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.frontend-changed == 'true' || github.event_name == 'push' + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: evoapicloud/evo-ai-frontend + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + context: ./frontend + file: ./frontend/Dockerfile + platforms: linux/amd64,linux/arm64 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL || 'https://api-evoai.evoapicloud.com' }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/.github/workflows/build-homolog.yml b/.github/workflows/build-homolog.yml new file mode 100644 index 00000000..09398c7c --- /dev/null +++ b/.github/workflows/build-homolog.yml @@ -0,0 +1,139 @@ +name: Build Homolog Images + +on: + push: + branches: + - develop + - homolog + +jobs: + detect-changes: + name: Detect Changes + runs-on: ubuntu-latest + outputs: + backend-changed: ${{ steps.changes.outputs.backend }} + frontend-changed: ${{ steps.changes.outputs.frontend }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Detect changes + id: changes + uses: dorny/paths-filter@v2 + with: + filters: | + backend: + - 'src/**' + - 'migrations/**' + - 'scripts/**' + - 'Dockerfile' + - 'pyproject.toml' + - 'alembic.ini' + - 'conftest.py' + - 'setup.py' + - 'Makefile' + - '.dockerignore' + frontend: + - 'frontend/**' + + build-backend-homolog: + name: Build Backend Homolog + runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.backend-changed == 'true' || github.event_name == 'push' + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: evoapicloud/evo-ai + tags: | + type=raw,value=homolog + type=raw,value=homolog-{{sha}} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} + + build-frontend-homolog: + name: Build Frontend Homolog + runs-on: ubuntu-latest + needs: detect-changes + if: needs.detect-changes.outputs.frontend-changed == 'true' || github.event_name == 'push' + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: evoapicloud/evo-ai-frontend + tags: | + type=raw,value=homolog + type=raw,value=homolog-{{sha}} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + context: ./frontend + file: ./frontend/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + NEXT_PUBLIC_API_URL=${{ vars.NEXT_PUBLIC_API_URL_HOMOLOG || 'https://api-homolog-evoai.evoapicloud.com' }} + + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml deleted file mode 100644 index 3aeaf723..00000000 --- a/.github/workflows/docker-image.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Build Docker image - -on: - push: - tags: - - "*.*.*" - -jobs: - build_deploy: - name: Build and Deploy - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: evoapicloud/evo-ai - tags: type=semver,pattern=v{{version}} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Build and push - id: docker_build - uses: docker/build-push-action@v5 - with: - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/.github/workflows/publish_docker_image_homolog.yml b/.github/workflows/publish_docker_image_homolog.yml deleted file mode 100644 index c67dbb8a..00000000 --- a/.github/workflows/publish_docker_image_homolog.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Build Docker image - -on: - push: - branches: - - develop - -jobs: - build_deploy: - name: Build and Deploy - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: evoapicloud/evo-ai - tags: homolog - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Build and push - id: docker_build - uses: docker/build-push-action@v5 - with: - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/.github/workflows/publish_docker_image_latest.yml b/.github/workflows/publish_docker_image_latest.yml deleted file mode 100644 index 12875f0d..00000000 --- a/.github/workflows/publish_docker_image_latest.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Build Docker image - -on: - push: - branches: - - main - -jobs: - build_deploy: - name: Build and Deploy - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Docker meta - id: meta - uses: docker/metadata-action@v5 - with: - images: evoapicloud/evo-ai - tags: latest - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Login to Docker Hub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - - - name: Build and push - id: docker_build - uses: docker/build-push-action@v5 - with: - platforms: linux/amd64,linux/arm64 - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - - - name: Image digest - run: echo ${{ steps.docker_build.outputs.digest }} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 640d581f..cf0180a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.1.0] - 2025-05-24 + +### Added + +- Export and Import Agents + +### Changed + +- A2A implementation updated to version 0.2.1 (https://google.github.io/A2A/specification/#agent2agent-a2a-protocol-specification) +- Frontend redesign +- Fixed message order + ## [0.0.11] - 2025-05-16 ### Changed -- Fixes on email service and client service +- Fixes in email service and client service ## [0.0.10] - 2025-05-15 diff --git a/Makefile b/Makefile index 506619c4..fc6b1f2c 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ alembic-downgrade: # Command to run the server run: - uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload --env-file .env + uvicorn src.main:app --host 0.0.0.0 --port 8000 --reload --env-file .env --reload-exclude frontend/ --reload-exclude "*.log" --reload-exclude "*.tmp" # Command to run the server in production mode run-prod: diff --git a/README.md b/README.md index 87bac869..2f8a16a6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,18 @@ -# Evo AI - AI Agents Platform +

Evo AI - AI Agents Platform

+ +
+ +[![Whatsapp Group](https://img.shields.io/badge/Group-WhatsApp-%2322BC18)](https://evolution-api.com/whatsapp) +[![Discord Community](https://img.shields.io/badge/Discord-Community-blue)](https://evolution-api.com/discord) +[![Postman Collection](https://img.shields.io/badge/Postman-Collection-orange)](https://evolution-api.com/postman) +[![Documentation](https://img.shields.io/badge/Documentation-Official-green)](https://doc.evolution-api.com) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](./LICENSE) +[![Support](https://img.shields.io/badge/Donation-picpay-green)](https://app.picpay.com/user/davidsongomes1998) +[![Sponsors](https://img.shields.io/badge/Github-sponsor-orange)](https://github.com/sponsors/EvolutionAPI) + +
+ +## Evo AI - AI Agents Platform Evo AI is an open-source platform for creating and managing AI agents, enabling integration with different AI models and services. @@ -8,321 +22,51 @@ The Evo AI platform allows: - Creation and management of AI agents - Integration with different language models -- Client management -- MCP server configuration +- Client management and MCP server configuration - Custom tools management -- **[Google Agent Development Kit (ADK)](https://google.github.io/adk-docs/)**: Base framework for agent development, providing support for LLM Agents, Sequential Agents, Loop Agents, Parallel Agents and Custom Agents +- **[Google Agent Development Kit (ADK)](https://google.github.io/adk-docs/)**: Base framework for agent development +- **[CrewAI Support](https://github.com/crewAI/crewAI)**: Alternative framework for agent development (in development) - JWT authentication with email verification -- **[Agent 2 Agent (A2A) Protocol Support](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/)**: Interoperability between AI agents following Google's A2A specification -- **[Workflow Agent with LangGraph](https://www.langchain.com/langgraph)**: Building complex agent workflows with LangGraph and ReactFlow -- **Secure API Key Management**: Encrypted storage of API keys with Fernet encryption +- **[Agent 2 Agent (A2A) Protocol Support](https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/)**: Interoperability between AI agents +- **[Workflow Agent with LangGraph](https://www.langchain.com/langgraph)**: Building complex agent workflows +- **Secure API Key Management**: Encrypted storage of API keys - **Agent Organization**: Folder structure for organizing agents by categories -## πŸ€– Agent Types and Creation +## πŸ€– Agent Types -Evo AI supports different types of agents that can be flexibly combined to create complex solutions: +Evo AI supports different types of agents that can be flexibly combined: ### 1. LLM Agent (Language Model) Agent based on language models like GPT-4, Claude, etc. Can be configured with tools, MCP servers, and sub-agents. -```json -{ - "client_id": "{{client_id}}", - "name": "personal_assistant", - "description": "Specialized personal assistant", - "role": "Personal Assistant", - "goal": "Help users with daily tasks and provide relevant information", - "type": "llm", - "model": "gpt-4", - "api_key_id": "stored-api-key-uuid", - "folder_id": "folder_id (optional)", - "instruction": "Detailed instructions for agent behavior", - "config": { - "tools": [ - { - "id": "tool-uuid", - "envs": { - "API_KEY": "tool-api-key", - "ENDPOINT": "http://localhost:8000" - } - } - ], - "mcp_servers": [ - { - "id": "server-uuid", - "envs": { - "API_KEY": "server-api-key", - "ENDPOINT": "http://localhost:8001" - }, - "tools": ["tool_name1", "tool_name2"] - } - ], - "custom_tools": { - "http_tools": [] - }, - "sub_agents": ["sub-agent-uuid"] - } -} -``` - ### 2. A2A Agent (Agent-to-Agent) Agent that implements Google's A2A protocol for agent interoperability. -```json -{ - "client_id": "{{client_id}}", - "type": "a2a", - "agent_card_url": "http://localhost:8001/api/v1/a2a/your-agent/.well-known/agent.json", - "folder_id": "folder_id (optional)", - "config": { - "sub_agents": ["sub-agent-uuid"] - } -} -``` - ### 3. Sequential Agent Executes a sequence of sub-agents in a specific order. -```json -{ - "client_id": "{{client_id}}", - "name": "processing_flow", - "type": "sequential", - "folder_id": "folder_id (optional)", - "config": { - "sub_agents": ["agent-uuid-1", "agent-uuid-2", "agent-uuid-3"] - } -} -``` - ### 4. Parallel Agent Executes multiple sub-agents simultaneously. -```json -{ - "client_id": "{{client_id}}", - "name": "parallel_processing", - "type": "parallel", - "folder_id": "folder_id (optional)", - "config": { - "sub_agents": ["agent-uuid-1", "agent-uuid-2"] - } -} -``` - ### 5. Loop Agent Executes sub-agents in a loop with a defined maximum number of iterations. -```json -{ - "client_id": "{{client_id}}", - "name": "loop_processing", - "type": "loop", - "folder_id": "folder_id (optional)", - "config": { - "sub_agents": ["sub-agent-uuid"], - "max_iterations": 5 - } -} -``` - ### 6. Workflow Agent -Executes sub-agents in a custom workflow defined by a graph structure. This agent type uses LangGraph for implementing complex agent workflows with conditional execution paths. - -```json -{ - "client_id": "{{client_id}}", - "name": "workflow_agent", - "type": "workflow", - "folder_id": "folder_id (optional)", - "config": { - "sub_agents": ["agent-uuid-1", "agent-uuid-2", "agent-uuid-3"], - "workflow": { - "nodes": [], - "edges": [] - } - } -} -``` - -The workflow structure is built using ReactFlow in the frontend, allowing visual creation and editing of complex agent workflows with nodes (representing agents or decision points) and edges (representing flow connections). +Executes sub-agents in a custom workflow defined by a graph structure using LangGraph. ### 7. Task Agent -Executes a specific task using a target agent. Task Agent provides a streamlined approach for structured task execution, where the agent_id specifies which agent will process the task, and the task description can include dynamic content placeholders. - -```json -{ - "client_id": "{{client_id}}", - "name": "web_search_task", - "type": "task", - "folder_id": "folder_id (optional)", - "config": { - "tasks": [ - { - "agent_id": "search-agent-uuid", - "description": "Search the web for information about {content}", - "expected_output": "Comprehensive search results with relevant information" - } - ], - "sub_agents": ["post-processing-agent-uuid"] - } -} -``` - -Key features of Task Agent: - -- Passes structured task instructions to the designated agent -- Supports variable content using {content} placeholder in the task description -- Provides clear task definition with instructions and expected output format -- Can execute sub-agents after the main task is completed -- Simplifies orchestration for single-focused task execution - -Task Agent is ideal for scenarios where you need to execute a specific, well-defined task with clear instructions and expectations. - -### Common Characteristics - -- All agent types can have sub-agents -- Sub-agents can be of any type -- Agents can be flexibly combined -- Type-specific configurations -- Support for custom tools and MCP servers - -### MCP Server Configuration - -Agents can be integrated with MCP (Model Context Protocol) servers for distributed processing: - -```json -{ - "config": { - "mcp_servers": [ - { - "id": "server-uuid", - "envs": { - "API_KEY": "server-api-key", - "ENDPOINT": "http://localhost:8001", - "MODEL_NAME": "gpt-4", - "TEMPERATURE": 0.7, - "MAX_TOKENS": 2000 - }, - "tools": ["tool_name1", "tool_name2"] - } - ] - } -} -``` - -Available configurations for MCP servers: - -- **id**: Unique MCP server identifier -- **envs**: Environment variables for configuration - - API_KEY: Server authentication key - - ENDPOINT: MCP server URL - - MODEL_NAME: Model name to be used - - TEMPERATURE: Text generation temperature (0.0 to 1.0) - - MAX_TOKENS: Maximum token limit per request - - Other server-specific variables -- **tools**: MCP server tool names for agent use - -### Agent Composition Examples - -Different types of agents can be combined to create complex processing flows: - -#### 1. Sequential Processing Pipeline - -```json -{ - "client_id": "{{client_id}}", - "name": "processing_pipeline", - "type": "sequential", - "config": { - "sub_agents": [ - "llm-analysis-agent-uuid", // LLM Agent for initial analysis - "a2a-translation-agent-uuid", // A2A Agent for translation - "llm-formatting-agent-uuid" // LLM Agent for final formatting - ] - } -} -``` - -#### 2. Parallel Processing with Aggregation - -```json -{ - "client_id": "{{client_id}}", - "name": "parallel_analysis", - "type": "sequential", - "config": { - "sub_agents": [ - { - "type": "parallel", - "config": { - "sub_agents": [ - "analysis-agent-uuid-1", - "analysis-agent-uuid-2", - "analysis-agent-uuid-3" - ] - } - }, - "aggregation-agent-uuid" // Agent for aggregating results - ] - } -} -``` - -#### 3. Multi-Agent Conversation System - -```json -{ - "client_id": "{{client_id}}", - "name": "conversation_system", - "type": "parallel", - "config": { - "sub_agents": [ - { - "type": "llm", - "name": "context_agent", - "model": "gpt-4", - "instruction": "Maintain conversation context" - }, - { - "type": "a2a", - "agent_card_url": "expert-agent-url" - }, - { - "type": "loop", - "config": { - "sub_agents": ["memory-agent-uuid"], - "max_iterations": 1 - } - } - ] - } -} -``` - -### API Creation - -For creating a new agent, use the endpoint: - -```http -POST /api/v1/agents -Content-Type: application/json -Authorization: Bearer your-token-jwt - -{ - // Configuration of the agent as per the examples above -} -``` +Executes a specific task using a target agent with structured task instructions. ## πŸ› οΈ Technologies +### Backend - **FastAPI**: Web framework for building the API - **SQLAlchemy**: ORM for database interaction - **PostgreSQL**: Main database @@ -335,223 +79,259 @@ Authorization: Bearer your-token-jwt - **Jinja2**: Template engine for email rendering - **Bcrypt**: Password hashing and security - **LangGraph**: Framework for building stateful, multi-agent workflows -- **ReactFlow**: Library for building node-based visual workflows + +### Frontend +- **Next.js 15**: React framework with App Router +- **React 18**: User interface library +- **TypeScript**: Type-safe JavaScript +- **Tailwind CSS**: Utility-first CSS framework +- **shadcn/ui**: Modern component library +- **React Hook Form**: Form management +- **Zod**: Schema validation +- **ReactFlow**: Node-based visual workflows +- **React Query**: Server state management ## πŸ“Š Langfuse Integration (Tracing & Observability) Evo AI platform natively supports integration with [Langfuse](https://langfuse.com/) for detailed tracing of agent executions, prompts, model responses, and tool calls, using the OpenTelemetry (OTel) standard. -### Why use Langfuse? - -- Visual dashboard for agent traces, prompts, and executions -- Detailed analytics for debugging and evaluating LLM apps -- Easy integration with Google ADK and other frameworks - -### How it works - -- Every agent execution (including streaming) is automatically traced via OpenTelemetry spans -- Data is sent to Langfuse, where it can be visualized and analyzed - ### How to configure 1. **Set environment variables in your `.env`:** ```env - LANGFUSE_PUBLIC_KEY="pk-lf-..." # Your Langfuse public key - LANGFUSE_SECRET_KEY="sk-lf-..." # Your Langfuse secret key - OTEL_EXPORTER_OTLP_ENDPOINT="https://cloud.langfuse.com/api/public/otel" # (or us.cloud... for US region) + LANGFUSE_PUBLIC_KEY="pk-lf-..." + LANGFUSE_SECRET_KEY="sk-lf-..." + OTEL_EXPORTER_OTLP_ENDPOINT="https://cloud.langfuse.com/api/public/otel" ``` - > **Attention:** Do not swap the keys! `pk-...` is public, `sk-...` is secret. - -2. **Automatic initialization** - - - Tracing is automatically initialized when the application starts (`src/main.py`). - - Agent execution functions are already instrumented with spans (`src/services/agent_runner.py`). - -3. **View in the Langfuse dashboard** +2. **View in the Langfuse dashboard** - Access your Langfuse dashboard to see real-time traces. -### Troubleshooting - -- **401 Error (Invalid credentials):** - - Check if the keys are correct and not swapped in your `.env`. - - Make sure the endpoint matches your region (EU or US). -- **Context error in async generator:** - - The code is already adjusted to avoid OpenTelemetry context issues in async generators. -- **Questions about integration:** - - See the [official Langfuse documentation - Google ADK](https://langfuse.com/docs/integrations/google-adk) - ## πŸ€– Agent 2 Agent (A2A) Protocol Support -Evo AI implements the Google's Agent 2 Agent (A2A) protocol, enabling seamless communication and interoperability between AI agents. This implementation includes: - -### Key Features - -- **Standardized Communication**: Agents can communicate using a common protocol regardless of their underlying implementation -- **Interoperability**: Support for agents built with different frameworks and technologies -- **Well-Known Endpoints**: Standardized endpoints for agent discovery and interaction -- **Task Management**: Support for task creation, execution, and status tracking -- **State Management**: Tracking of agent states and conversation history -- **Authentication**: Secure API key-based authentication for agent interactions - -### Implementation Details - -- **Agent Card**: Each agent exposes a `.well-known/agent.json` endpoint with its capabilities and configuration -- **Task Handling**: Support for task creation, execution, and status tracking -- **Message Format**: Standardized message format for agent communication -- **History Tracking**: Maintains conversation history between agents -- **Artifact Management**: Support for handling different types of artifacts (text, files, etc.) - -### Example Usage - -```json -// Agent Card Example -{ - "name": "My Agent", - "description": "A helpful AI assistant", - "url": "https://api.example.com/agents/123", - "capabilities": { - "streaming": false, - "pushNotifications": false, - "stateTransitionHistory": true - }, - "authentication": { - "schemes": ["apiKey"], - "credentials": { - "in": "header", - "name": "x-api-key" - } - }, - "skills": [ - { - "id": "search", - "name": "Web Search", - "description": "Search the web for information" - } - ] -} -``` +Evo AI implements the Google's Agent 2 Agent (A2A) protocol, enabling seamless communication and interoperability between AI agents. For more information about the A2A protocol, visit [Google's A2A Protocol Documentation](https://google.github.io/A2A/). -## πŸ“ Project Structure - -``` -src/ -β”œβ”€β”€ api/ # API endpoints -β”œβ”€β”€ core/ # Core business logic -β”œβ”€β”€ models/ # Data models -β”œβ”€β”€ schemas/ # Pydantic schemas for validation -β”œβ”€β”€ services/ # Business services -β”œβ”€β”€ templates/ # Email templates -β”‚ └── emails/ # Jinja2 email templates -β”œβ”€β”€ utils/ # Utilities -└── config/ # Configurations -``` - ## πŸ“‹ Prerequisites -Before starting, make sure you have the following installed: - +### Backend - **Python**: 3.10 or higher - **PostgreSQL**: 13.0 or higher - **Redis**: 6.0 or higher - **Git**: For version control -- **Make**: For running Makefile commands (usually pre-installed on Linux/Mac, for Windows use WSL or install via chocolatey) +- **Make**: For running Makefile commands -You'll also need the following accounts/API keys: - -- **SendGrid Account**: For email functionality - -## πŸ“‹ Requirements - -- Python 3.10+ -- PostgreSQL -- Redis -- Email provider: - - SendGrid Account (if using SendGrid email provider) - - SMTP Server (if using SMTP email provider) +### Frontend +- **Node.js**: 18.0 or higher +- **pnpm**: Package manager (recommended) or npm/yarn ## πŸ”§ Installation -1. Clone the repository: +### 1. Clone the Repository ```bash git clone https://github.com/EvolutionAPI/evo-ai.git cd evo-ai ``` -2. Create a virtual environment: +### 2. Backend Setup + +#### Virtual Environment and Dependencies ```bash +# Create and activate virtual environment make venv source venv/bin/activate # Linux/Mac -# or -venv\Scripts\activate # Windows +# or on Windows: venv\Scripts\activate + +# Install development dependencies +make install-dev ``` -3. Install dependencies: - -```bash -pip install -e . # For basic installation -# or -pip install -e ".[dev]" # For development dependencies -``` - -Or using the Makefile: - -```bash -make install # For basic installation -# or -make install-dev # For development dependencies -``` - -4. Set up environment variables: +#### Environment Configuration ```bash +# Copy and configure backend environment cp .env.example .env -# Edit the .env file with your settings +# Edit the .env file with your database, Redis, and other settings ``` -5. Initialize the database and run migrations: +#### Database Setup ```bash +# Initialize database and apply migrations make alembic-upgrade -``` -6. Seed the database with initial data: - -```bash +# Seed initial data (admin user, sample clients, etc.) make seed-all ``` -## πŸ–₯️ Frontend Installation +### 3. Frontend Setup -After installing Evo AI (the backend), you need to install the frontend to access the web interface: - -1. Clone the frontend repository: +#### Install Dependencies ```bash -git clone https://github.com/EvolutionAPI/evo-ai-frontend.git -cd evo-ai-frontend +# Navigate to frontend directory +cd frontend + +# Install dependencies using pnpm (recommended) +pnpm install + +# Or using npm +# npm install + +# Or using yarn +# yarn install ``` -2. Follow the installation instructions in the frontend repository's README to set up and run the web interface. +#### Frontend Environment Configuration -> The backend (API) and frontend are separate projects. Make sure both are running for full platform functionality. +```bash +# Copy and configure frontend environment +cp .env.example .env +# Edit .env with your API URL (default: http://localhost:8000) +``` -## πŸš€ Getting Started +The frontend `.env.local` should contain: -After installation, follow these steps to set up your first agent: +```env +NEXT_PUBLIC_API_URL=http://localhost:8000 +``` -1. **Configure MCP Server**: Set up your Model Context Protocol server configuration first -2. **Create Client or Register**: Create a new client or register a user account -3. **Create Agents**: Set up the agents according to your needs (LLM, A2A, Sequential, Parallel, Loop, or Workflow) +## πŸš€ Running the Application -### Configuration (.env file) +### Development Mode -Configure your environment using the following key settings: +#### Start Backend (Terminal 1) +```bash +# From project root +make run +# Backend will be available at http://localhost:8000 +``` + +#### Start Frontend (Terminal 2) +```bash +# From frontend directory +cd frontend +pnpm dev + +# Or using npm/yarn +# npm run dev +# yarn dev + +# Frontend will be available at http://localhost:3000 +``` + +### Production Mode + +#### Backend +```bash +make run-prod # Production with multiple workers +``` + +#### Frontend +```bash +cd frontend +pnpm build && pnpm start + +# Or using npm/yarn +# npm run build && npm start +# yarn build && yarn start +``` + +## 🐳 Docker Installation + +### Full Stack with Docker Compose + +```bash +# Build and start all services (backend + database + redis) +make docker-build +make docker-up + +# Initialize database with seed data +make docker-seed +``` + +### Frontend with Docker + +```bash +# From frontend directory +cd frontend + +# Build frontend image +docker build -t evo-ai-frontend . + +# Run frontend container +docker run -p 3000:3000 -e NEXT_PUBLIC_API_URL=http://localhost:8000 evo-ai-frontend +``` + +Or using the provided docker-compose: + +```bash +# From frontend directory +cd frontend +docker-compose up -d +``` + +## 🎯 Getting Started + +After installation, follow these steps: + +1. **Access the Frontend**: Open `http://localhost:3000` +2. **Create Admin Account**: Use the seeded admin credentials or register a new account +3. **Configure MCP Server**: Set up your first MCP server connection +4. **Create Client**: Add a client to organize your agents +5. **Build Your First Agent**: Create and configure your AI agent +6. **Test Agent**: Use the chat interface to interact with your agent + +### Default Admin Credentials + +After running the seeders, you can login with: +- **Email**: Check the seeder output for the generated admin email +- **Password**: Check the seeder output for the generated password + +## πŸ–₯️ API Documentation + +The interactive API documentation is available at: + +- Swagger UI: `http://localhost:8000/docs` +- ReDoc: `http://localhost:8000/redoc` + +## πŸ‘¨β€πŸ’» Development Commands + +### Backend Commands +```bash +# Database migrations +make alembic-upgrade # Update database to latest version +make alembic-revision message="description" # Create new migration + +# Seeders +make seed-all # Run all seeders + +# Code verification +make lint # Verify code with flake8 +make format # Format code with black +``` + +### Frontend Commands +```bash +# From frontend directory +cd frontend + +# Development +pnpm dev # Start development server +pnpm build # Build for production +pnpm start # Start production server +pnpm lint # Run ESLint +``` + +## πŸš€ Configuration + +### Backend Configuration (.env file) + +Key settings include: ```bash # Database settings @@ -560,447 +340,48 @@ POSTGRES_CONNECTION_STRING="postgresql://postgres:root@localhost:5432/evo_ai" # Redis settings REDIS_HOST="localhost" REDIS_PORT=6379 -REDIS_DB=0 -REDIS_PASSWORD="your-redis-password" + +# AI Engine configuration +AI_ENGINE="adk" # Options: "adk" (Google Agent Development Kit) or "crewai" (CrewAI framework) # JWT settings JWT_SECRET_KEY="your-jwt-secret-key" -JWT_ALGORITHM="HS256" -JWT_EXPIRATION_TIME=30 # In seconds # Email provider configuration EMAIL_PROVIDER="sendgrid" # Options: "sendgrid" or "smtp" -# SendGrid (if EMAIL_PROVIDER=sendgrid) -SENDGRID_API_KEY="your-sendgrid-api-key" -EMAIL_FROM="noreply@yourdomain.com" -APP_URL="https://yourdomain.com" - -# SMTP (if EMAIL_PROVIDER=smtp) -SMTP_FROM="noreply-smtp@yourdomain.com" -SMTP_USER="your-smtp-username" -SMTP_PASSWORD="your-smtp-password" -SMTP_HOST="your-smtp-host" -SMTP_PORT=587 -SMTP_USE_TLS=true -SMTP_USE_SSL=false - # Encryption for API keys ENCRYPTION_KEY="your-encryption-key" ``` -### Project Dependencies - -The project uses modern Python packaging standards with `pyproject.toml`. Key dependencies include: - -```toml -dependencies = [ - "fastapi==0.115.12", - "uvicorn==0.34.2", - "pydantic==2.11.3", - "sqlalchemy==2.0.40", - "psycopg2==2.9.10", - "alembic==1.15.2", - "redis==5.3.0", - "langgraph==0.4.1", - # ... other dependencies -] -``` - -For development, additional packages can be installed with: +### Frontend Configuration (.env.local file) ```bash -pip install -e ".[dev]" +# API Configuration +NEXT_PUBLIC_API_URL="http://localhost:8000" # Backend API URL ``` -This includes development tools like black, flake8, pytest, and more. +> **Note**: While Google ADK is fully supported, the CrewAI engine option is still under active development. For production environments, it's recommended to use the default "adk" engine. ## πŸ” Authentication -The API uses JWT (JSON Web Token) authentication. To access the endpoints, you need to: +The API uses JWT (JSON Web Token) authentication with: -1. Register a user or log in to obtain a JWT token -2. Include the JWT token in the `Authorization` header of all requests in the format `Bearer ` -3. Tokens expire after a configured period (default: 30 minutes) +- User registration and email verification +- Login to obtain JWT tokens +- Password recovery flow +- Account lockout after multiple failed login attempts -### Authentication Flow +## πŸš€ Star Us on GitHub -1. **User Registration**: +If you find EvoAI useful, please consider giving us a star! Your support helps us grow our community and continue improving the product. -```http -POST /api/v1/auth/register -``` - -2. **Email Verification**: - An email will be sent containing a verification link. - -3. **Login**: - -```http -POST /api/v1/auth/login -``` - -Returns a JWT token to be used in requests. - -4. **Password Recovery (if needed)**: - -```http -POST /api/v1/auth/forgot-password -POST /api/v1/auth/reset-password -``` - -5. **Recover logged user data**: - -```http -POST /api/v1/auth/me -``` - -### Example Usage with curl: - -```bash -# Login -curl -X POST "http://localhost:8000/api/v1/auth/login" \ - -H "Content-Type: application/json" \ - -d '{"email": "your-email@example.com", "password": "your-password"}' - -# Use received token -curl -X GET "http://localhost:8000/api/v1/clients/" \ - -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." -``` - -### Access Control - -- Regular users (associated with a client) only have access to their client's resources -- Admin users have access to all resources -- Certain operations (such as creating MCP servers) are restricted to administrators only -- Account lockout mechanism after multiple failed login attempts for enhanced security - -## πŸ“§ Email Templates - -The platform uses Jinja2 templates for email rendering with a unified design system: - -- **Base Template**: All emails extend a common base template for consistent styling -- **Verification Email**: Sent when users register to verify their email address -- **Password Reset**: Sent when users request a password reset -- **Welcome Email**: Sent after email verification to guide new users -- **Account Locked**: Security alert when an account is locked due to multiple failed login attempts - -All email templates feature responsive design, clear call-to-action buttons, and fallback mechanisms. - -## πŸš€ Running the Project - -```bash -make run # For development with automatic reload -# or -make run-prod # For production with multiple workers -``` - -The API will be available at `http://localhost:8000` - -## πŸ‘¨β€πŸ’» Development Commands - -```bash -# Database migrations -make init # Initialize Alembic -make alembic-revision message="description" # Create new migration -make alembic-upgrade # Update database to latest version (use to execute existing migrations) -make alembic-downgrade # Revert latest migration -make alembic-migrate message="description" # Create and apply migration -make alembic-reset # Reset database - -# Seeders -make seed-admin # Create default admin -make seed-client # Create default client -make seed-mcp-servers # Create example MCP servers -make seed-tools # Create example tools -make seed-all # Run all seeders - -# Code verification -make lint # Verify code with flake8 -make format # Format code with black -make clear-cache # Clear project cache -``` - -## 🐳 Running with Docker - -For quick setup and deployment, we provide Docker and Docker Compose configurations. - -### Prerequisites - -- Docker installed -- Docker Compose installed - -### Configuration - -1. Create and configure the `.env` file: - -```bash -cp .env.example .env -# Edit the .env file with your settings, especially: -# - POSTGRES_CONNECTION_STRING -# - REDIS_HOST (should be "redis" when using Docker) -# - JWT_SECRET_KEY -# - SENDGRID_API_KEY -``` - -2. Build the Docker image: - -```bash -make docker-build -``` - -3. Start the services (API, PostgreSQL, and Redis): - -```bash -make docker-up -``` - -4. Apply migrations (first time only): - -```bash -docker-compose exec api python -m alembic upgrade head -``` - -5. Populate the database with initial data: - -```bash -make docker-seed -``` - -6. To check application logs: - -```bash -make docker-logs -``` - -7. To stop the services: - -```bash -make docker-down -``` - -### Available Services - -- **API**: http://localhost:8000 -- **API Documentation**: http://localhost:8000/docs -- **PostgreSQL**: localhost:5432 -- **Redis**: localhost:6379 - -### Persistent Volumes - -Docker Compose sets up persistent volumes for: - -- PostgreSQL data -- Redis data -- Application logs directory - -### Environment Variables - -The main environment variables used by the API container: - -- `POSTGRES_CONNECTION_STRING`: PostgreSQL connection string -- `REDIS_HOST`: Redis host (use "redis" when running with Docker) -- `JWT_SECRET_KEY`: Secret key for JWT token generation -- `EMAIL_PROVIDER`: Email provider to use ("sendgrid" or "smtp") -- `SENDGRID_API_KEY`: SendGrid API key (if using SendGrid) -- `EMAIL_FROM`: Email used as sender (for SendGrid) -- `SMTP_FROM`: Email used as sender (for SMTP) -- `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`: SMTP server configuration -- `SMTP_USE_TLS`, `SMTP_USE_SSL`: SMTP security settings -- `APP_URL`: Base URL of the application - -## πŸ”’ Secure API Key Management - -Evo AI implements a secure API key management system that protects sensitive credentials: - -- **Encrypted Storage**: API keys are encrypted using Fernet symmetric encryption before storage -- **Secure References**: Agents reference API keys by UUID (api_key_id) instead of storing raw keys -- **Centralized Management**: API keys can be created, updated, and rotated without changing agent configurations -- **Client Isolation**: API keys are scoped to specific clients for better security isolation - -### Encryption Configuration - -The encryption system uses a secure key defined in the `.env` file: - -```env -ENCRYPTION_KEY="your-secure-encryption-key" -``` - -If not provided, a secure key will be generated automatically at startup. - -### API Key Management - -API keys can be managed through dedicated endpoints: - -```http -# Create a new API key -POST /api/v1/agents/apikeys -Content-Type: application/json -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -{ - "client_id": "client-uuid", - "name": "My OpenAI Key", - "provider": "openai", - "key_value": "sk-actual-api-key-value" -} - -# List all API keys for a client -GET /api/v1/agents/apikeys -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -# Get a specific API key -GET /api/v1/agents/apikeys/{key_id} -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -# Update an API key -PUT /api/v1/agents/apikeys/{key_id} -Content-Type: application/json -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -{ - "name": "Updated Key Name", - "provider": "anthropic", - "key_value": "new-key-value", - "is_active": true -} - -# Delete an API key (soft delete) -DELETE /api/v1/agents/apikeys/{key_id} -Authorization: Bearer your-token-jwt -x-client-id: client-uuid -``` - -## πŸ€– Agent Organization - -Agents can be organized into folders for better management: - -### Creating and Managing Folders - -```http -# Create a new folder -POST /api/v1/agents/folders -Content-Type: application/json -Authorization: Bearer your-token-jwt - -{ - "client_id": "client-uuid", - "name": "Marketing Agents", - "description": "Agents for content marketing tasks" -} - -# List all folders -GET /api/v1/agents/folders -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -# Get a specific folder -GET /api/v1/agents/folders/{folder_id} -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -# Update a folder -PUT /api/v1/agents/folders/{folder_id} -Content-Type: application/json -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -{ - "name": "Updated Folder Name", - "description": "Updated folder description" -} - -# Delete a folder -DELETE /api/v1/agents/folders/{folder_id} -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -# List agents in a folder -GET /api/v1/agents/folders/{folder_id}/agents -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -# Assign an agent to a folder -PUT /api/v1/agents/{agent_id}/folder -Content-Type: application/json -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -{ - "folder_id": "folder-uuid" -} - -# Remove an agent from any folder -PUT /api/v1/agents/{agent_id}/folder -Content-Type: application/json -Authorization: Bearer your-token-jwt -x-client-id: client-uuid - -{ - "folder_id": null -} -``` - -### Filtering Agents by Folder - -When listing agents, you can filter by folder: - -```http -GET /api/v1/agents?folder_id=folder-uuid -Authorization: Bearer your-token-jwt -x-client-id: client-uuid -``` - -## πŸ“š API Documentation - -The interactive API documentation is available at: - -- Swagger UI: `http://localhost:8000/docs` -- ReDoc: `http://localhost:8000/redoc` - -## πŸ“Š Logs and Audit - -- Logs are stored in the `logs/` directory with the following format: - - `{logger_name}_{date}.log` -- The system maintains audit logs for important administrative actions -- Each action is recorded with information such as user, IP, date/time, and details +[![Star History Chart](https://api.star-history.com/svg?repos=EvolutionAPI/evo-ai&type=Date)](https://www.star-history.com/#EvolutionAPI/evo-ai&Date) ## 🀝 Contributing -We welcome contributions from the community! Here's how you can help: - -1. Fork the project -2. Create a feature branch (`git checkout -b feature/AmazingFeature`) -3. Make your changes and add tests if possible -4. Run tests and make sure they pass -5. Commit your changes following conventional commits format (`feat: add amazing feature`) -6. Push to the branch (`git push origin feature/AmazingFeature`) -7. Open a Pull Request - -Please read our [Contributing Guidelines](CONTRIBUTING.md) for more details. +We welcome contributions from the community! Please read our [Contributing Guidelines](CONTRIBUTING.md) for more details. ## πŸ“„ License This project is licensed under the [Apache License 2.0](./LICENSE). - -The use of the name, logo, or trademark "Evolution API" is protected and not automatically granted by the license. See section 6 (Trademarks) of the license for details about trademark usage. - -## πŸ“Š Stargazers - -[![Stargazers repo roster for @EvolutionAPI/evo-ai](https://reporoster.com/stars/EvolutionAPI/evo-ai)](https://github.com/EvolutionAPI/evo-ai/stargazers) - -## πŸ”„ Forks - -[![Forkers repo roster for @EvolutionAPI/evo-ai](https://reporoster.com/forks/EvolutionAPI/evo-ai)](https://github.com/EvolutionAPI/evo-ai/network/members) - -## πŸ™ Acknowledgments - -- [FastAPI](https://fastapi.tiangolo.com/) -- [SQLAlchemy](https://www.sqlalchemy.org/) -- [Google ADK](https://github.com/google/adk) -- [LangGraph](https://github.com/langchain-ai/langgraph) -- [ReactFlow](https://reactflow.dev/) diff --git a/docker-compose.yml b/docker-compose.yml index 07334f1b..8dd9a27b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: "3.8" services: api: - image: evo-ai-api:latest + image: evoapicloud/evo-ai:latest depends_on: - postgres - redis diff --git a/frontend/.cursorrules b/frontend/.cursorrules new file mode 100644 index 00000000..5d384dd9 --- /dev/null +++ b/frontend/.cursorrules @@ -0,0 +1,120 @@ +# Next.js Project Rules + +## Language +- All code, comments, documentation, commits, and PRs MUST be written in English. + +## Architecture + +### Folder Structure +- `/app`: App router pages and API routes + - Route-specific components should be placed in their respective route folders +- `/components`: Reusable UI components + - `/ui`: Shadcn UI components and their derivatives +- `/contexts`: React Context providers +- `/hooks`: Custom React hooks +- `/lib`: Utility functions and configuration +- `/public`: Static assets +- `/services`: API service functions +- `/styles`: Global styles +- `/types`: TypeScript type definitions + +### Component Guidelines +- Use functional components with TypeScript +- Use the `.tsx` extension for React components +- Follow a logical naming convention: + - Complex components: Use PascalCase and create folders with an index.tsx file + - Simple components: Single PascalCase named files + +### State Management +- Use React Context for global state +- Use React hooks for local state +- Avoid prop drilling more than 2 levels deep + +### API & Data Fetching +- Use API service modules in `/services` directory +- Implement proper error handling and loading states +- Use React Query or SWR for complex data fetching where appropriate + +## Development Patterns + +### Code Quality +- Maintain type safety - avoid using `any` type +- Write self-documenting code with descriptive names +- Keep components focused on a single responsibility +- Extract complex logic into custom hooks +- Follow DRY (Don't Repeat Yourself) principle + +### CSS & Styling +- Use Tailwind CSS for styling +- Use Shadcn UI components as base building blocks +- Maintain consistent spacing and sizing + +### Performance +- Avoid unnecessary re-renders +- Optimize images and assets +- Implement code splitting where appropriate +- Use dynamic imports for large components/pages + +### Testing +- Write tests for critical business logic +- Test components in isolation +- Implement end-to-end tests for critical user flows + +## Git Workflow + +### Branch Naming +- Features: `feature/short-description` +- Bugfixes: `fix/short-description` +- Hotfixes: `hotfix/short-description` +- Releases: `release/version` + +## Conventions +- Variable and function names in English +- Log and error messages in English +- Documentation in English +- User-facing content (emails, responses) in English +- Indentation with 4 spaces +- Maximum of 79 characters per line + +## Commit Rules +- Use Conventional Commits format for all commit messages +- Format: `(): ` +- Types: + - `feat`: A new feature + - `fix`: A bug fix + - `docs`: Documentation changes + - `style`: Changes that do not affect code meaning (formatting, etc.) + - `refactor`: Code changes that neither fix a bug nor add a feature + - `perf`: Performance improvements + - `test`: Adding or modifying tests + - `chore`: Changes to build process or auxiliary tools +- Scope is optional and should be the module or component affected +- Description should be concise, in the imperative mood, and not capitalized +- Use body for more detailed explanations if needed +- Reference issues in the footer with `Fixes #123` or `Relates to #123` +- Examples: + - `feat(auth): add password reset functionality` + - `fix(api): correct validation error in client registration` + - `docs: update API documentation for new endpoints` + - `refactor(services): improve error handling in authentication` + +Format: `type(scope): subject` + +Examples: +- `feat(auth): add login form validation` +- `fix(api): resolve user data fetching issue` +- `docs(readme): update installation instructions` +- `style(components): format according to style guide` + +### Pull Requests +- Keep PRs focused on a single feature or fix +- Include descriptive titles and descriptions +- Reference related issues +- Request code reviews from appropriate team members +- Ensure CI checks pass before merging + +## Code Review Guidelines +- Focus on code quality, architecture, and maintainability +- Provide constructive feedback +- Address all review comments before merging +- Maintain a respectful and collaborative tone \ No newline at end of file diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 00000000..f9feddb3 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1 @@ +NEXT_PUBLIC_API_URL=http://localhost:8000 \ No newline at end of file diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..400e48ed --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,31 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules + +# next.js +/.next/ +/out/ + +# production +/build + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# Lock files +package-lock.json +yarn.lock + +# env files +.env + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts \ No newline at end of file diff --git a/frontend/CHANGELOG.md b/frontend/CHANGELOG.md new file mode 100644 index 00000000..7a1f9205 --- /dev/null +++ b/frontend/CHANGELOG.md @@ -0,0 +1,67 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.0.7] - 2025-05-15 + +### Added + +- Add Task agents +- Add file support for A2A protocol (Agent-to-Agent) endpoints +- Add entrypoint script for dynamic environment variable handling +- Add agent card URL input and copy functionality + +## [0.0.6] - 2025-05-13 + +### Added + +- Agent sharing functionality with third parties via API keys +- Dedicated shared-chat page for accessing shared agents +- Local storage mechanism to save recently used shared agents +- Public access to shared agents without full authentication + +### Changed + +- Add example environment file and update .gitignore +- Add clientId prop to agent-related components and improve agent data processing +- Refactor middleware to handle shared agent routes as public paths +- Update API interceptors to prevent forced logout on shared chat pages + +### security + +- Implement force logout functionality on 401 Unauthorized responses + +## [0.0.5] - 2025-05-13 + +### Changed + +- Update author information in multiple files + +## [0.0.4] - 2025-05-13 + +### Added +- Initial public release +- User-friendly interface for creating and managing AI agents +- Integration with multiple language models (e.g., GPT-4, Claude) +- Client management interface +- Visual configuration for MCP servers +- Custom tools management +- JWT authentication with email verification +- Agent 2 Agent (A2A) protocol support (Google's A2A spec) +- Workflow Agent with ReactFlow for visual workflow creation +- Secure API key management (encrypted storage) +- Agent organization with folders and categories +- Dashboard with agent overview, usage stats, and recent activities +- Agent editor for creating, editing, and configuring agents +- Workflow editor for building and visualizing agent flows +- API key manager for adding, encrypting, and rotating keys +- RESTful API and WebSocket backend integration +- Docker support for containerized deployment +- Complete documentation and contribution guidelines + +--- + +Older versions and future releases will be listed here. diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 00000000..1560e70b --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,63 @@ +# Build stage +FROM node:20.15.1-alpine AS builder + +WORKDIR /app + +# Define build arguments with default values +ARG NEXT_PUBLIC_API_URL=https://api-evoai.evoapicloud.com + +# Instalar pnpm globalmente +RUN npm install -g pnpm + +# Install dependencies first (caching) +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --frozen-lockfile + +# Instalar explicitamente o next-runtime-env +RUN pnpm add next-runtime-env + +# Copy source code +COPY . . + +# Set environment variables from build arguments +ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} + +RUN pnpm run build + +# Production stage +FROM node:20.15.1-alpine AS runner + +WORKDIR /app + +# Define build arguments again for the runner stage +ARG NEXT_PUBLIC_API_URL=https://api-evoai.evoapicloud.com + +# Instalar pnpm globalmente +RUN npm install -g pnpm + +# Install production dependencies only +COPY package.json pnpm-lock.yaml ./ +RUN pnpm install --prod --frozen-lockfile + +# Instalar explicitamente o next-runtime-env na produΓ§Γ£o +RUN pnpm add next-runtime-env + +# Copy built assets from builder +COPY --from=builder /app/.next ./.next +COPY --from=builder /app/public ./public +COPY --from=builder /app/next.config.mjs ./ + +# Set environment variables +ENV NODE_ENV=production +ENV PORT=3000 +ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} + +# Script to replace environment variables at runtime - create it diretamente no container +COPY docker-entrypoint.sh ./ +RUN chmod +x ./docker-entrypoint.sh + +# Expose port +EXPOSE 3000 + +# Use entrypoint script to initialize environment variables before starting the app +ENTRYPOINT ["sh", "./docker-entrypoint.sh"] \ No newline at end of file diff --git a/frontend/LICENSE b/frontend/LICENSE new file mode 100644 index 00000000..727e6b0a --- /dev/null +++ b/frontend/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2025 Evolution API + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 00000000..baf04986 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,237 @@ +# Evo AI - AI Agents Platform (Frontend) + +Evo AI is an open-source platform for creating and managing AI agents, enabling integration with different AI models and services. + +## πŸš€ Overview + +The Evo AI frontend platform enables: + +- User-friendly interface for creating and managing AI agents +- Integration with different language models +- Client management +- Visual configuration of MCP servers +- Custom tools management +- JWT authentication with email verification +- **Agent 2 Agent (A2A) Protocol Support**: Interface for interoperability between AI agents following Google's A2A specification +- **Workflow Agent with ReactFlow**: Visual interface for building complex agent workflows +- **Secure API Key Management**: Interface for encrypted storage of API keys +- **Agent Organization**: Folder structure for organizing agents by categories + +## 🧩 Agent Creation Interface + +The frontend offers intuitive interfaces for creating different types of agents: + +### 1. LLM Agent (Language Model) + +Interface for configuring agents based on models like GPT-4, Claude, etc. with tools, MCP servers, and sub-agents. + +### 2. A2A Agent (Agent-to-Agent) + +Interface for implementing Google's A2A protocol for agent interoperability. + +### 3. Sequential Agent + +Interface for executing sub-agents in a specific order. + +### 4. Parallel Agent + +Interface for executing multiple sub-agents simultaneously. + +### 5. Loop Agent + +Interface for executing sub-agents in a loop with a defined number of iterations. + +### 6. Workflow Agent + +Visual interface based on ReactFlow for creating complex workflows between agents. + +## πŸ› οΈ Technologies + +- [Next.js](https://nextjs.org/) - React framework for production +- [React](https://reactjs.org/) - JavaScript library for building user interfaces +- [Tailwind CSS](https://tailwindcss.com/) - Utility-first CSS framework +- [Shadcn UI](https://ui.shadcn.com/) - UI component library +- [Radix UI](https://www.radix-ui.com/) - Unstyled, accessible components +- [TypeScript](https://www.typescriptlang.org/) - Typed JavaScript +- [React Query](https://tanstack.com/query/latest) - Data fetching and state management +- [Zustand](https://zustand-demo.pmnd.rs/) - Global state management +- [React Flow](https://reactflow.dev/) - Library for building node-based visual workflows +- [Axios](https://axios-http.com/) - HTTP client for API communication + +## πŸ“‹ Requirements + +- Node.js 18+ (LTS recommended) +- npm, yarn, or pnpm package manager +- Evo AI backend running + +## πŸ”§ Installation + +1. Clone the repository: + +```bash +git clone https://github.com/EvolutionAPI/evo-ai-frontend.git +cd evo-ai-frontend +``` + +2. Install dependencies: + +```bash +npm install +# or +yarn install +# or +pnpm install +``` + +3. Configure environment variables: + +```bash +cp .env.example .env +# Edit the .env file with your settings +``` + +## πŸš€ Running the Project + +```bash +# Development mode +npm run dev +# or +yarn dev +# or +pnpm dev + +# Production build +npm run build +# or +yarn build +# or +pnpm build + +# Start production server +npm run start +# or +yarn start +# or +pnpm start +``` + +The project will be available at [http://localhost:3000](http://localhost:3000) + +## πŸ” Authentication + +The frontend implements JWT authentication integrated with the backend: + +- **User Registration**: Form for creating new accounts +- **Email Verification**: Process for verifying via email +- **Login**: Authentication of existing users +- **Password Recovery**: Complete password recovery flow +- **Secure Storage**: Tokens stored in HttpOnly cookies + +## πŸ–₯️ Main Interface Features + +### Dashboard + +Main dashboard showing: +- Agent overview +- Usage statistics +- Recent activities +- Quick links for agent creation + +### Agent Editor + +Complete interface for: +- Creating new agents +- Editing existing agents +- Configuring instructions +- Selecting models +- Setting up API keys + +### Workflow Editor + +Visual editor based on ReactFlow for: +- Creating complex workflows +- Connecting different agents +- Defining conditionals and decision flows +- Visualizing data flow + +### API Key Manager + +Interface for: +- Adding new API keys +- Securely encrypting keys +- Managing existing keys +- Rotating and updating keys + +### Agent Organization + +System for: +- Creating folders and categories +- Organizing agents by type or use case +- Searching and filtering agents + +## πŸ”„ Backend Integration + +The frontend communicates with the backend through: + +- **RESTful API**: Endpoints for resource management +- **WebSockets**: Real-time communication for agent messages +- **Response Streaming**: Support for streaming model responses + +## 🐳 Docker Support + +The project includes Docker configuration for containerized deployment: + +```bash +# Build the Docker image +./docker_build.sh +# or +docker build -t nextjs-frontend . + +# Run the container +docker run -p 3000:3000 nextjs-frontend +``` + +# 🐳 Docker Compose +```bash +# Copy the .env file +cp .env.example .env + +# Build and deploy + docker-compose up -d --build +``` + +## 🀝 Contributing + +We welcome contributions from the community! Here's how you can help: + +1. Fork the project +2. Create a feature branch (`git checkout -b feature/AmazingFeature`) +3. Make your changes and add tests if possible +4. Run tests and make sure they pass +5. Commit your changes following conventional commits format (`feat: add amazing feature`) +6. Push to the branch (`git push origin feature/AmazingFeature`) +7. Open a Pull Request + +Please read our [Contributing Guidelines](CONTRIBUTING.md) for more details. + +## πŸ“„ License + +This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE) file for details. + +**Trademark Notice:** The name "Evo AI" and related branding are protected trademarks. Unauthorized use is prohibited. + +## πŸ‘¨β€πŸ’» Development Commands + +- `npm run dev` - Start the development server +- `npm run build` - Build the application for production +- `npm run start` - Start the production server +- `npm run lint` - Run ESLint to check code quality +- `npm run format` - Format code with Prettier + +## πŸ™ Acknowledgments + +- [Next.js](https://nextjs.org/) +- [React](https://reactjs.org/) +- [Tailwind CSS](https://tailwindcss.com/) +- [Shadcn UI](https://ui.shadcn.com/) +- [ReactFlow](https://reactflow.dev/) diff --git a/frontend/app/agents/AgentCard.tsx b/frontend/app/agents/AgentCard.tsx new file mode 100644 index 00000000..75a25cb3 --- /dev/null +++ b/frontend/app/agents/AgentCard.tsx @@ -0,0 +1,506 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/AgentCard.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent } from "@/components/ui/card"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Folder } from "@/services/agentService"; +import { Agent, AgentType } from "@/types/agent"; +import { MCPServer } from "@/types/mcpServer"; +import { + ArrowRight, + Bot, + BookOpenCheck, + ChevronDown, + ChevronUp, + Code, + ExternalLink, + GitBranch, + MoveRight, + Pencil, + RefreshCw, + Settings, + Share2, + Trash2, + Workflow, + TextSelect, + Download, + FlaskConical, +} from "lucide-react"; +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { cn } from "@/lib/utils"; +import { exportAsJson } from "@/lib/utils"; + +interface AgentCardProps { + agent: Agent; + onEdit: (agent: Agent) => void; + onDelete: (agent: Agent) => void; + onMove: (agent: Agent) => void; + onShare?: (agent: Agent) => void; + onWorkflow?: (agentId: string) => void; + availableMCPs?: MCPServer[]; + getApiKeyNameById?: (id: string | undefined) => string | null; + getAgentNameById?: (id: string) => string; + folders?: Folder[]; + agents: Agent[]; +} + +export function AgentCard({ + agent, + onEdit, + onDelete, + onMove, + onShare, + onWorkflow, + availableMCPs = [], + getApiKeyNameById = () => null, + getAgentNameById = (id) => id, + folders = [], + agents, +}: AgentCardProps) { + const [expanded, setExpanded] = useState(false); + const router = useRouter(); + + const getAgentTypeInfo = (type: AgentType) => { + const types: Record< + string, + { + label: string; + icon: React.ElementType; + color: string; + bgColor: string; + badgeClass: string; + } + > = { + llm: { + label: "LLM Agent", + icon: Code, + color: "#00cc7d", + bgColor: "bg-green-500/10", + badgeClass: + "bg-green-900/30 text-green-400 border-green-600/30 hover:bg-green-900/40", + }, + a2a: { + label: "A2A Agent", + icon: ExternalLink, + color: "#6366f1", + bgColor: "bg-indigo-500/10", + badgeClass: + "bg-indigo-900/30 text-indigo-400 border-indigo-600/30 hover:bg-indigo-900/40", + }, + sequential: { + label: "Sequential Agent", + icon: ArrowRight, + color: "#f59e0b", + bgColor: "bg-yellow-500/10", + badgeClass: + "bg-yellow-900/30 text-yellow-400 border-yellow-600/30 hover:bg-yellow-900/40", + }, + parallel: { + label: "Parallel Agent", + icon: GitBranch, + color: "#8b5cf6", + bgColor: "bg-purple-500/10", + badgeClass: + "bg-purple-900/30 text-purple-400 border-purple-600/30 hover:bg-purple-900/40", + }, + loop: { + label: "Loop Agent", + icon: RefreshCw, + color: "#ec4899", + bgColor: "bg-pink-500/10", + badgeClass: + "bg-orange-900/30 text-orange-400 border-orange-600/30 hover:bg-orange-900/40", + }, + workflow: { + label: "Workflow Agent", + icon: Workflow, + color: "#3b82f6", + bgColor: "bg-blue-500/10", + badgeClass: + "bg-blue-900/30 text-blue-400 border-blue-700/40 hover:bg-blue-900/40", + }, + task: { + label: "Task Agent", + icon: BookOpenCheck, + color: "#ef4444", + bgColor: "bg-red-500/10", + badgeClass: + "bg-red-900/30 text-red-400 border-red-600/30 hover:bg-red-900/40", + }, + }; + + return ( + types[type] || { + label: type, + icon: Bot, + color: "#94a3b8", + bgColor: "bg-slate-500/10", + badgeClass: + "bg-slate-900/30 text-slate-400 border-slate-600/30 hover:bg-slate-900/40", + } + ); + }; + + const getAgentTypeIcon = (type: AgentType) => { + const typeInfo = getAgentTypeInfo(type); + const IconComponent = typeInfo.icon; + return ( + + ); + }; + + const getAgentTypeName = (type: AgentType) => { + return getAgentTypeInfo(type).label; + }; + + const getAgentTypeBgColor = (type: AgentType) => { + return getAgentTypeInfo(type).bgColor; + }; + + const getAgentTypeBadgeClass = (type: AgentType) => { + return getAgentTypeInfo(type).badgeClass; + }; + + const getFolderNameById = (id: string) => { + const folder = folders?.find((f) => f.id === id); + return folder?.name || id; + }; + + const getTotalTools = () => { + if (agent.type === "llm" && agent.config?.mcp_servers) { + return agent.config.mcp_servers.reduce( + (total, mcp) => total + (mcp.tools?.length || 0), + 0 + ); + } + return 0; + }; + + const getCreatedAtFormatted = () => { + return new Date(agent.created_at).toLocaleDateString(); + }; + + // Function to export the agent as JSON + const handleExportAgent = () => { + try { + exportAsJson( + agent, + `agent-${agent.name + .replace(/\s+/g, "-") + .toLowerCase()}-${agent.id.substring(0, 8)}`, + true, + agents + ); + } catch (error) { + console.error("Error exporting agent:", error); + } + }; + + // Function to test the A2A agent in the lab + const handleTestA2A = () => { + // Use the agent card URL as base for A2A tests + const agentUrl = agent.agent_card_url?.replace( + "/.well-known/agent.json", + "" + ); + + // Use the API key directly from the agent config + const apiKey = agent.config?.api_key; + + // Build the URL with parameters for the lab tests + const params = new URLSearchParams(); + + if (agentUrl) { + params.set("agent_url", agentUrl); + } + + if (apiKey) { + params.set("api_key", apiKey); + } + + // Redirect to the lab tests in the "lab" tab + const testUrl = `/documentation?${params.toString()}#lab`; + + router.push(testUrl); + }; + + return ( + +
+
+ {getAgentTypeIcon(agent.type)} +

{agent.name}

+
+ + {getAgentTypeName(agent.type)} + +
+ + +
+

+ {agent.description && agent.description.length > 100 + ? `${agent.description.substring(0, 100)}...` + : agent.description} +

+
+ +
+
+ Model: + + {agent.type === "llm" ? agent.model : "N/A"} + +
+ +
+ + {expanded && ( +
+ {agent.folder_id && ( +
+ Folder: + + {getFolderNameById(agent.folder_id)} + +
+ )} + + {agent.type === "llm" && agent.api_key_id && ( +
+ API Key: + + {getApiKeyNameById(agent.api_key_id)} + +
+ )} + + {getTotalTools() > 0 && ( +
+ Tools: + {getTotalTools()} +
+ )} + + {agent.config?.sub_agents && agent.config.sub_agents.length > 0 && ( +
+ Sub-agents: + + {agent.config.sub_agents.length} + +
+ )} + + {agent.type === "workflow" && agent.config?.workflow && ( +
+ Elements: + + {agent.config.workflow.nodes?.length || 0} nodes,{" "} + {agent.config.workflow.edges?.length || 0} connections + +
+ )} + +
+ Created at: + {getCreatedAtFormatted()} +
+ +
+ ID: + {agent.id} +
+
+ )} + +
+ + + + + + + + Test A2A + + onEdit(agent)} + > + + Edit Agent + + onMove(agent)} + > + + Move Agent + + {onWorkflow && agent.type === "workflow" && ( + onWorkflow(agent.id)} + > + + Open Workflow + + )} + + + Export as JSON + + {onShare && ( + onShare(agent)} + > + + Share Agent + + )} + onDelete(agent)} + > + + Delete Agent + + + + + + + ); +} diff --git a/frontend/app/agents/AgentList.tsx b/frontend/app/agents/AgentList.tsx new file mode 100644 index 00000000..6eb55af8 --- /dev/null +++ b/frontend/app/agents/AgentList.tsx @@ -0,0 +1,130 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/AgentList.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { Agent } from "@/types/agent"; +import { MCPServer } from "@/types/mcpServer"; +import { AgentCard } from "./AgentCard"; +import { EmptyState } from "./EmptyState"; +import { ApiKey, Folder } from "@/services/agentService"; + +interface AgentListProps { + agents: Agent[]; + isLoading: boolean; + searchTerm: string; + selectedFolderId: string | null; + availableMCPs: MCPServer[]; + getApiKeyNameById: (id: string | undefined) => string | null; + getAgentNameById: (id: string) => string; + onEdit: (agent: Agent) => void; + onDelete: (agent: Agent) => void; + onMove: (agent: Agent) => void; + onShare?: (agent: Agent) => void; + onWorkflow?: (agentId: string) => void; + onClearSearch?: () => void; + onCreateAgent?: () => void; + apiKeys: ApiKey[]; + folders: Folder[]; +} + +export function AgentList({ + agents, + isLoading, + searchTerm, + selectedFolderId, + availableMCPs, + getApiKeyNameById, + getAgentNameById, + onEdit, + onDelete, + onMove, + onShare, + onWorkflow, + onClearSearch, + onCreateAgent, + apiKeys, + folders, +}: AgentListProps) { + if (isLoading) { + return ( +
+
+
+ ); + } + + if (agents.length === 0) { + if (searchTerm) { + return ( + + ); + } else if (selectedFolderId) { + return ( + + ); + } else { + return ( + + ); + } + } + + return ( +
+ {agents.map((agent) => ( + + ))} +
+ ); +} diff --git a/frontend/app/agents/AgentSidebar.tsx b/frontend/app/agents/AgentSidebar.tsx new file mode 100644 index 00000000..16358107 --- /dev/null +++ b/frontend/app/agents/AgentSidebar.tsx @@ -0,0 +1,186 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/AgentSidebar.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + Folder, + FolderPlus, + Home, + X, + CircleEllipsis, + Edit, + Trash2, +} from "lucide-react"; + +interface AgentFolder { + id: string; + name: string; + description: string; +} + +interface AgentSidebarProps { + visible: boolean; + folders: AgentFolder[]; + selectedFolderId: string | null; + onSelectFolder: (id: string | null) => void; + onAddFolder: () => void; + onEditFolder: (folder: AgentFolder) => void; + onDeleteFolder: (folder: AgentFolder) => void; + onClose: () => void; +} + +export function AgentSidebar({ + visible, + folders, + selectedFolderId, + onSelectFolder, + onAddFolder, + onEditFolder, + onDeleteFolder, + onClose, +}: AgentSidebarProps) { + return ( + <> + {visible && ( + + )} + +
+
+

+ + Folders +

+
+ + +
+
+ +
+ + + {folders.map((folder) => ( +
+ + +
+ + + + + + { + e.stopPropagation(); + onEditFolder(folder); + }} + > + + Edit + + { + e.stopPropagation(); + onDeleteFolder(folder); + }} + > + + Delete + + + +
+
+ ))} +
+
+ + ); +} diff --git a/frontend/app/agents/AgentTypeSelector.tsx b/frontend/app/agents/AgentTypeSelector.tsx new file mode 100644 index 00000000..35db3def --- /dev/null +++ b/frontend/app/agents/AgentTypeSelector.tsx @@ -0,0 +1,96 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/AgentTypeSelector.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { AgentType } from "@/types/agent"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Code, + ExternalLink, + GitBranch, + RefreshCw, + Workflow, + Users, + BookOpenCheck, +} from "lucide-react"; + +interface AgentTypeSelectorProps { + value: AgentType; + onValueChange: (value: AgentType) => void; + className?: string; +} + +export const agentTypes = [ + { value: "llm", label: "LLM Agent", icon: Code }, + { value: "a2a", label: "A2A Agent", icon: ExternalLink }, + { value: "sequential", label: "Sequential Agent", icon: Workflow }, + { value: "parallel", label: "Parallel Agent", icon: GitBranch }, + { value: "loop", label: "Loop Agent", icon: RefreshCw }, + { value: "workflow", label: "Workflow Agent", icon: Workflow }, + { value: "task", label: "Task Agent", icon: BookOpenCheck }, +]; + +export function AgentTypeSelector({ + value, + onValueChange, + className = "", +}: AgentTypeSelectorProps) { + return ( + + ); +} diff --git a/frontend/app/agents/EmptyState.tsx b/frontend/app/agents/EmptyState.tsx new file mode 100644 index 00000000..b084c017 --- /dev/null +++ b/frontend/app/agents/EmptyState.tsx @@ -0,0 +1,107 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/EmptyState.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { Button } from "@/components/ui/button"; +import { Folder, Plus, Search, Server } from "lucide-react"; + +interface EmptyStateProps { + type: "no-agents" | "empty-folder" | "search-no-results"; + searchTerm?: string; + onAction?: () => void; + actionLabel?: string; +} + +export function EmptyState({ + type, + searchTerm = "", + onAction, + actionLabel = "Create Agent", +}: EmptyStateProps) { + const getIcon = () => { + switch (type) { + case "empty-folder": + return ; + case "search-no-results": + return ; + case "no-agents": + default: + return ; + } + }; + + const getTitle = () => { + switch (type) { + case "empty-folder": + return "Empty folder"; + case "search-no-results": + return "No agents found"; + case "no-agents": + default: + return "No agents found"; + } + }; + + const getMessage = () => { + switch (type) { + case "empty-folder": + return "This folder is empty. Add agents or create a new one."; + case "search-no-results": + return `We couldn't find any agents that match your search: "${searchTerm}"`; + case "no-agents": + default: + return "You don't have any agents configured. Create your first agent to start!"; + } + }; + + return ( +
+
+ {getIcon()} +
+

{getTitle()}

+

{getMessage()}

+ {onAction && ( + + )} +
+ ); +} diff --git a/frontend/app/agents/SearchInput.tsx b/frontend/app/agents/SearchInput.tsx new file mode 100644 index 00000000..f8e30739 --- /dev/null +++ b/frontend/app/agents/SearchInput.tsx @@ -0,0 +1,153 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/SearchInput.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { useState } from "react"; +import { Input } from "@/components/ui/input"; +import { Search, X, Filter } from "lucide-react"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Button } from "@/components/ui/button"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; + +interface SearchInputProps { + value: string; + onChange: (value: string) => void; + placeholder?: string; + className?: string; + selectedAgentType?: string | null; + onAgentTypeChange?: (type: string | null) => void; + agentTypes?: string[]; +} + +// Using "all" as a special value to represent no filter +const ANY_TYPE_VALUE = "all"; + +export function SearchInput({ + value, + onChange, + placeholder = "Search agents...", + className = "", + selectedAgentType = null, + onAgentTypeChange, + agentTypes = [], +}: SearchInputProps) { + const [isFilterOpen, setIsFilterOpen] = useState(false); + + const handleTypeChange = (value: string) => { + if (onAgentTypeChange) { + onAgentTypeChange(value === ANY_TYPE_VALUE ? null : value); + } + }; + + return ( +
+
+ + onChange(e.target.value)} + autoComplete="off" + className="pl-10 w-full bg-[#222] border-[#444] text-white focus:border-emerald-400 focus:ring-emerald-400/10" + /> + {value && ( + + )} +
+ + {agentTypes.length > 0 && onAgentTypeChange && ( + + + + + +
+
+ Filter by type +
+ + + {selectedAgentType && ( + + )} +
+
+
+ )} +
+ ); +} diff --git a/frontend/app/agents/config/A2AAgentConfig.tsx b/frontend/app/agents/config/A2AAgentConfig.tsx new file mode 100644 index 00000000..99f6a5dd --- /dev/null +++ b/frontend/app/agents/config/A2AAgentConfig.tsx @@ -0,0 +1,73 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/config/A2AAgentConfig.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; + +interface A2AAgentConfigProps { + values: { + agent_card_url?: string; + }; + onChange: (values: any) => void; +} + +export function A2AAgentConfig({ values, onChange }: A2AAgentConfigProps) { + return ( +
+
+ + + onChange({ + ...values, + agent_card_url: e.target.value, + }) + } + placeholder="https://example.com/.well-known/agent-card.json" + className="col-span-3 bg-[#222] border-[#444] text-white" + /> +
+
+

+ Provide the full URL for the JSON file of the Agent Card that describes + this agent. +

+

+ Agent Cards contain metadata, capabilities descriptions and supported + protocols. +

+
+
+ ); +} diff --git a/frontend/app/agents/config/LLMAgentConfig.tsx b/frontend/app/agents/config/LLMAgentConfig.tsx new file mode 100644 index 00000000..9c3d1449 --- /dev/null +++ b/frontend/app/agents/config/LLMAgentConfig.tsx @@ -0,0 +1,367 @@ +/* +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ @author: Davidson Gomes β”‚ +β”‚ @file: /app/agents/config/LLMAgentConfig.tsx β”‚ +β”‚ Developed by: Davidson Gomes β”‚ +β”‚ Creation date: May 13, 2025 β”‚ +β”‚ Contact: contato@evolution-api.com β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @copyright Β© Evolution API 2025. All rights reserved. β”‚ +β”‚ Licensed under the Apache License, Version 2.0 β”‚ +β”‚ β”‚ +β”‚ You may not use this file except in compliance with the License. β”‚ +β”‚ You may obtain a copy of the License at β”‚ +β”‚ β”‚ +β”‚ http://www.apache.org/licenses/LICENSE-2.0 β”‚ +β”‚ β”‚ +β”‚ Unless required by applicable law or agreed to in writing, software β”‚ +β”‚ distributed under the License is distributed on an "AS IS" BASIS, β”‚ +β”‚ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. β”‚ +β”‚ See the License for the specific language governing permissions and β”‚ +β”‚ limitations under the License. β”‚ +β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ +β”‚ @important β”‚ +β”‚ For any future changes to the code in this file, it is recommended to β”‚ +β”‚ include, together with the modification, the information of the developer β”‚ +β”‚ who changed it and the date of modification. β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +*/ +"use client"; + +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { Textarea } from "@/components/ui/textarea"; +import { ApiKey } from "@/services/agentService"; +import { Plus, Maximize2, Save } from "lucide-react"; +import { useEffect, useState } from "react"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/components/ui/dialog"; + +interface ModelOption { + value: string; + label: string; + provider: string; +} + +interface LLMAgentConfigProps { + apiKeys: ApiKey[]; + availableModels: ModelOption[]; + values: { + model?: string; + api_key_id?: string; + instruction?: string; + role?: string; + goal?: string; + }; + onChange: (values: any) => void; + onOpenApiKeysDialog: () => void; +} + +export function LLMAgentConfig({ + apiKeys, + availableModels, + values, + onChange, + onOpenApiKeysDialog, +}: LLMAgentConfigProps) { + const [instructionText, setInstructionText] = useState(values.instruction || ""); + const [isInstructionModalOpen, setIsInstructionModalOpen] = useState(false); + const [expandedInstructionText, setExpandedInstructionText] = useState(""); + + useEffect(() => { + setInstructionText(values.instruction || ""); + }, [values.instruction]); + + const handleInstructionChange = (e: React.ChangeEvent) => { + const newValue = e.target.value; + setInstructionText(newValue); + + onChange({ + ...values, + instruction: newValue, + }); + }; + + const handleExpandInstruction = () => { + setExpandedInstructionText(instructionText); + setIsInstructionModalOpen(true); + }; + + const handleSaveExpandedInstruction = () => { + setInstructionText(expandedInstructionText); + onChange({ + ...values, + instruction: expandedInstructionText, + }); + setIsInstructionModalOpen(false); + }; + + return ( +
+
+ +
+ + onChange({ + ...values, + role: e.target.value, + }) + } + placeholder="Ex: Research Assistant, Customer Support, etc." + className="bg-[#222] border-[#444] text-white" + /> +
+ ℹ️ + Define the role or persona that the agent will assume +
+
+
+ +
+ +
+ + onChange({ + ...values, + goal: e.target.value, + }) + } + placeholder="Ex: Find and organize information, Assist customers with inquiries, etc." + className="bg-[#222] border-[#444] text-white" + /> +
+ ℹ️ + Define the main objective or purpose of this agent +
+
+
+ +
+ +
+
+ + + +
+ + {apiKeys.length === 0 && ( +
+ i + + You need to{" "} + {" "} + before creating an agent. + +
+ )} +
+
+ +
+ + { + const searchQuery = e.target.value.toLowerCase(); + const items = document.querySelectorAll('[data-model-item="true"]'); + items.forEach((item) => { + const text = item.textContent?.toLowerCase() || ''; + if (text.includes(searchQuery)) { + (item as HTMLElement).style.display = 'flex'; + } else { + (item as HTMLElement).style.display = 'none'; + } + }); + }} + /> +
+
+ {availableModels + .filter((model) => { + if (!values.api_key_id) return true; + + const selectedKey = apiKeys.find( + (key) => key.id === values.api_key_id + ); + + if (!selectedKey) return true; + + return model.provider === selectedKey.provider; + }) + .map((model) => ( + + {model.label} + + ))} +
+ + +
+ +
+ +
+
+