aci Documentation

ACI.dev is the open source tool-calling platform that hooks up 600+ tools into any agentic IDE or custom AI agent through direct function calling or a...

4,764 stars Python Python 1 file ยท ~8,801 tokens #agents#ai#ai-agents#api#developer-tools#function-calling#integration#llm
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy aci on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name aci -p 5432:5432 --restart always pgvector/pgvector:pg17
Configured Services & Ports
โš™๏ธ db
image: pgvector/pgvector:pg17
๐Ÿ”Œ Ports: 5432:5432
โš™๏ธ test-db
image: pgvector/pgvector:pg17
โš™๏ธ aws
image: localstack/localstack
๐Ÿ”Œ Ports: 4566:4566
โš™๏ธ propelauth_mock
image: build locally
๐Ÿ”Œ Ports: 12800:12800
โš™๏ธ server
image: build locally
๐Ÿ”Œ Ports: 8000:8000
โš™๏ธ runner
image: build locally
โš™๏ธ test-runner
image: build locally
docker-compose.yml
yaml (docker-compose.yml)
name: aci

services:
  db:
    # Note: we need to use the pgvector/pgvector:pg17 image to use the pgvector extension, instead of the official postgres image
    image: pgvector/pgvector:pg17
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d local_db"]
      interval: 1s
      retries: 5
      start_period: 1s
      timeout: 10s
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: local_db
    ports:
      - "5432:5432"
    restart: no

  test-db:
    image: pgvector/pgvector:pg17
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d local_db"]
      interval: 1s
      retries: 5
      start_period: 1s
      timeout: 10s
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: local_db
    restart: no

  aws:
    image: localstack/localstack
    ports:
      - "4566:4566"
    environment:
      - DEBUG=1
      - DATA_DIR=/var/lib/localstack/data
      - SERVICES=kms
      - LS_LOG=warn
    volumes:
      - ./scripts/create-kms-encryption-key.sh:/etc/localstack/init/ready.d/create-kms-encryption-key.sh

  propelauth_mock:
    build:
      context: .
      dockerfile: Dockerfile.runner
    ports:
      - "12800:12800"
    working_dir: /workdir
    volumes:
      - ./mock/propelauth_mock_server.py:/workdir/propelauth_mock_server.py
    command: uvicorn propelauth_mock_server:app --proxy-headers --forwarded-allow-ips=* --host 0.0.0.0 --port 12800 --reload

  server:
    build:
      context: .
      dockerfile: Dockerfile.server
    healthcheck:
      test: ["CMD-SHELL", "curl localhost:8000/v1/health"]
      interval: 10s
      retries: 5
      start_period: 3s
      timeout: 10s
    env_file:
      - .env.local
    # useful for development, changes take effect in the container without needing to rebuild the image.
    volumes:
      - ./aci/server:/workdir/aci/server
      - ./aci/common:/workdir/aci/common
      # Mocks out the propelauth_fastapi module in server container to bypass token validation in local development
      - ./mock/propelauth_fastapi_mock.py:/workdir/.venv/lib/python3.12/site-packages/propelauth_fastapi/__init__.py
    ports:
      - "8000:8000"
    # this overrides the default CMD specified in the Dockerfile, use this for local development
    command: uvicorn aci.server.main:app --proxy-headers --forwarded-allow-ips=* --host 0.0.0.0 --port 8000 --reload --no-access-log
    depends_on:
      db:
        condition: service_healthy
      aws:
        condition: service_healthy
    restart: no

  # can think of runner as an staging host for executing any commands
  # e.g., run cli commands and scripts such as seed db etc.
  runner:
    build:
      context: .
      dockerfile: Dockerfile.runner
    env_file:
      - .env.local
    # Mount the local code into the container so you can run scripts / Alembic
    volumes:
      - ./aci:/workdir/aci
      - ./apps:/workdir/apps
      - ./scripts:/workdir/scripts
      - ./evals:/workdir/evals
      - ./alembic.ini:/workdir/alembic.ini
      # Mocks out the propelauth_fastapi module in server container to bypass token validation in local development
      - ./mock/propelauth_fastapi_mock.py:/workdir/.venv/lib/python3.12/site-packages/propelauth_fastapi/__init__.py
    command: >
      /bin/sh -c "alembic upgrade head && tail -f /dev/null"
    depends_on:
      db:
        condition: service_healthy
      server:
        condition: service_healthy

  test-runner:
    build:
      context: .
      dockerfile: Dockerfile.runner
    env_file:
      - .env.local
    environment:
      # override the db host to use the test-db service
      - SERVER_DB_HOST=test-db
      - ALEMBIC_DB_HOST=test-db
      - CLI_DB_HOST=test-db
    # Mount the local code into the container so you can run scripts / Alembic
    volumes:
      - ./aci:/workdir/aci
      - ./apps:/workdir/apps
      - ./scripts:/workdir/scripts
      - ./evals:/workdir/evals
      - ./alembic.ini:/workdir/alembic.ini
      # Mocks out the propelauth_fastapi module in server container to bypass token validation in local development
      - ./mock/propelauth_fastapi_mock.py:/workdir/.venv/lib/python3.12/site-packages/propelauth_fastapi/__init__.py
    command: >
      /bin/sh -c "alembic upgrade head && tail -f /dev/null"
    depends_on:
      test-db:
        condition: service_healthy
      aws:
        condition: service_healthy

File: README.md

ACI: Open-Source Infra to Power Unified MCP Servers and VibeOps

[!NOTE]
This repo is for the ACI.dev platform. If you're looking for the Unified MCP server built with ACI.dev, see aci-mcp.

ACI.dev is the open-source tool-calling platform that hooks up 600+ tools into any agentic IDE or custom AI agent. It gives agents intent-aware access to tools with multi-tenant auth, granular permissions, and dynamic tool discoveryโ€”exposed as either direct function calls or through a Unified Model-Context-Protocol (MCP) server.

Examples: Instead of writing separate OAuth flows and API clients for Google Calendar, Slack, and more, use ACI.dev to manage authentication and provide AI agents with unified, secure function calls. Access these capabilities through our Unified MCP server or via our lightweight Python SDK, compatible with any LLM framework.

Supercharge vibe coding and automate devOps by adding a single unified MCP server to your favourite agentic IDE. Configure the MCP with Vercel, Supabase, Cloudflare, and other platforms. Let AI handle provisioning, deployment, database configs, and debugging to turn a vibe coded prototype into a live product.

๐Ÿ“บ Demo Video

ACI.dev Unified MCP Server Demo

ACI.dev VibeOps Demo

โœจ Key Features

  • 600+ Pre-built Integrations: Connect to popular services and apps in minutes.
  • Flexible Access Methods: Use our unified MCP server or our lightweight SDK for direct function calling.
  • Multi-tenant Authentication: Built-in OAuth flows and secrets management for both developers and end-users.
  • Enhanced Agent Reliability: Natural language permission boundaries and dynamic tool discovery.
  • Framework & Model Agnostic: Works with any LLM framework and agent architecture.
  • 100% Open Source: Everything released under Apache 2.0 (backend, dev portal, integrations).

๐Ÿ’ก Why Use ACI.dev?

ACI.dev improves tool-calling reliability and accountability:

  • Authentication at Scale: Connect multiple users to multiple services securely.
  • Discovery Without Overload: Find and use the right tools without overwhelming LLM context windows.
  • Natural Language Permissions: Control agent capabilities with human-readable boundaries.
  • Tool-use Logging: See how your agent called tools and the issues it ran into.
  • Build Once, Run Anywhere: No vendor lock-in with our open source, framework-agnostic approach.

๐Ÿงฐ Common Use Cases

  • VibeOps: Automate devOps by letting your agentic IDE access Vercel, Supabase, Cloudflare, Sentry and more to ship live products.
  • Personal Assistant Chatbots: Build chatbots that can search the web, manage calendars, send emails, interact with SaaS tools, etc.
  • Research Agent: Conducts research on specific topics and syncs results to other apps (e.g., Notion, Google Sheets).
  • Outbound Sales Agent: Automates lead generation, email outreach, and CRM updates.
  • Customer Support Agent: Provides answers, manages tickets, and performs actions based on customer queries.

๐Ÿ’ป Getting Started: Local Development

To run the full ACI.dev platform (backend server and frontend portal) locally, follow the individual README files for each component:

๐Ÿ‘‹ Contributing

We welcome contributions! Please see our CONTRIBUTING.md for more information.

Integration Requests

Missing any integrations (apps or functions) you need? Please see our Integration Request Template and submit an integration request! Or, if you're feeling adventurous, you can submit a PR to add the integration yourself!

Star History


File: backend/deployment/README.md

Welcome to your CDK Python project!

This is a blank project for CDK development with Python.

The cdk.json file tells the CDK Toolkit how to execute your app.

This project is set up like a standard Python project. The initialization
process also creates a virtualenv within this project, stored under the .venv
directory. To create the virtualenv it assumes that there is a python3
(or python for Windows) executable in your path with access to the venv
package. If for any reason the automatic creation of the virtualenv fails,
you can create the virtualenv manually.

To manually create a virtualenv on MacOS and Linux:

text
$ python3 -m venv .venv

After the init process completes and the virtualenv is created, you can use the following
step to activate your virtualenv.

text
$ source .venv/bin/activate

If you are a Windows platform, you would activate the virtualenv like this:

text
% .venv\Scripts\activate.bat

Once the virtualenv is activated, you can install the required dependencies.

text
$ pip install -r requirements.txt

At this point you can now synthesize the CloudFormation template for this code.

text
$ cdk synth

To add additional dependencies, for example other CDK libraries, just add
them to your setup.py file and rerun the pip install -r requirements.txt
command.

Useful commands

  • cdk ls list all stacks in the app
  • cdk synth emits the synthesized CloudFormation template
  • cdk deploy deploy this stack to your default AWS account/region
  • cdk diff compare deployed stack with current state
  • cdk docs open CDK documentation

Enjoy!


File: backend/README.md

ACI.dev Backend


Overview

The backend component of ACI.dev provides the server infrastructure, API endpoints, database models, and integration libraries that enable over 600+ tool integrations with multi-tenant authentication and granular permissions.

Code Structure

The backend consists of several main components:

  • Server: FastAPI application handling API requests, authentication, and tool executions
  • Database: PostgreSQL with pgvector for vector similarity search
  • CLI: Command-line interface for local testing and development
  • Common: Shared code and utilities used across components

Development Setup

Prerequisites

  • Python 3.12+
  • Docker and Docker Compose
  • uv package manager

Code Style

We follow strict code quality standards:

  • Formatting & Linting: We use ruff for code formatting and linting
  • Type Checking: We use mypy for static type checking
  • Pre-commit Hooks: Install with pre-commit install

IDE Configuration

For VS Code users, configure Ruff formatter:

json
{
    "[python]": {
      "editor.formatOnSave": true,
      "editor.defaultFormatter": "charliermarsh.ruff",
      "editor.codeActionsOnSave": {
        "source.organizeImports.ruff": "always"
      }
    }
}

Getting Started

  1. Clone the repository:

    bash
    git clone https://github.com/aipotheosis-labs/aci.git
    cd aci/backend
  2. Install dependencies and activate virtual environment:

    bash
    uv sync
    source .venv/bin/activate
  3. Install pre-commit hooks:

    bash
    pre-commit install
  4. Set up environment variables for local development:

    bash
    cp .env.example .env.local

    Most sensitive variables and dummy values are already defined in .env.example, so you only need to set the following env vars in .env.local:

    • SERVER_OPENAI_API_KEY: Use your own OpenAI API key
    • CLI_OPENAI_API_KEY: Use your own OpenAI API key (can be the same as SERVER_OPENAI_API_KEY)
  5. Start services with Docker Compose:

    bash
    docker compose up --build

    This will start:

    • server: Backend API service
    • db: PostgreSQL database
    • aws: LocalStack for mocking AWS services
    • runner: Container for running commands like pytest, cli commands or scripts
  6. Seed the database with sample data:

    bash
    docker compose exec runner ./scripts/seed_db.sh

    The script will seed the database with below dummy data for local end-to-end development.

    • A default project and agent (with an API key)
    • Sample Apps and their functions
      • Brave Search
      • Hacker News
      • Gmail (with dummy OAuth2 credentials)

    The script will output an API key like below that you can use on the swagger UI, SDK, or
    sending HTTP requests to the local backend server directly.

    text
    {
       'Project Id': '65cf26b9-a919-4008-85de-ecb850c3fc36',
       'Agent Id': '74273ac1-f68e-4314-b8be-fee4a5855d8a',
       'API Key': '88c55e31e817bd2d48aa455e94b61e766fb6e6610c97abe6f724733bf222e3e0'
    }

    [!NOTE]
    If you want to seed the database with all available apps, run the script with the --all flag.
    But you'll have to manually create a secrets file .app.secrets.json
    for each app that has OAuth2 scheme and put the OAuth2 credentials in that file, and the
    insertion process might take a while.
    See the example secrets file below for the GMAIL app.

    Alternatively, you can use the --all --mock flags together to seed all apps with mock OAuth2 credentials.
    This is useful for development and testing when you don't need real OAuth2 authentication.
    The mock values will be used instead of requiring .app.secrets.json files.

    bash
    # put this in a file called .app.secrets.json under ./apps/gmail/
    {
       "AIPOLABS_GMAIL_CLIENT_ID": "<your_google_oauth2_client_id>",
       "AIPOLABS_GMAIL_CLIENT_SECRET": "<your_google_oauth2_client_secret>"
    }
  7. (Optional) If you want to seed the database with specific Apps and Functions, use the cli command directly.

    [!NOTE]
    Add the --skip-dry-run flag to the commands below to actually insert the data into the database.

    bash
    # create app (--secrets-file is only needed for apps that have OAuth2 scheme)
    docker compose exec runner python -m aci.cli upsert-app --app-file ./apps/gmail/app.json --secrets-file ./apps/gmail/.app.secrets.json
    # create functions
    docker compose exec runner python -m aci.cli upsert-functions --functions-file ./apps/gmail/functions.json
  8. (Optional) Connect to the database using a GUI client (e.g., DBeaver)

    • Parameters for the db connection can be found in the .env.local file you created in step 4.
  9. Access the API documentation at:

    bash
    http://localhost:8000/v1/notforhuman-docs
  10. (Optional) If you are developing the dev portal, follow the instructions on frontend README to start the dev portal.

  11. (Optional) If you are developing Stripe related billing features, follow the
    Stripe Webhooks section.

Running Tests

bash
docker compose exec test-runner pytest

Database Management

Working with Migrations

When making changes to database models:

  1. Check for detected changes:

    bash
    docker compose exec runner alembic check
  2. Generate a migration:

    bash
    docker compose exec runner alembic revision --autogenerate -m "description of changes"
  3. Manually review and edit the generated file in database/alembic/versions/ if needed to add custom changes, e.g.,:

    • pgvector library imports
    • Index creation/deletion
    • Vector extension setup
    • Other database-specific operations
  4. Apply the migration (to the local db):

    bash
    docker compose exec runner alembic upgrade head
  5. To revert the latest migration:

    bash
    docker compose exec runner alembic downgrade -1

PropelAuth Configuration

[!NOTE]
This section is only required if you need to develop features that integrate with PropelAuth.

When developing the dev portal, you'll need an actual user and organization in PropelAuth's test environment, along with a default project and agent in your local database. This section guides you through setting up these connections.

Values to be filled

You would need to replace a few dummy values with real values in .env.local:

  • SERVER_PROPELAUTH_AUTH_URL - The authentication URL from PropelAuth
  • SERVER_PROPELAUTH_API_KEY - Your PropelAuth API key
  • SERVER_SVIX_SIGNING_SECRET - The signing secret for webhooks

Setup Steps

Follow these steps to configure PropelAuth for local development:

1. Set Up Ngrok

Ngrok creates a public URL for your local server, allowing PropelAuth webhooks to reach your machine:

  • Install ngrok from the getting started guide
  • Start a tunnel to your local server:
    bash
    ngrok http http://localhost:8000
  • Copy the generated public endpoint (e.g., https://7c4c-2a06-5904-1e06-6a00-ddc6-68ce-ffae-8783.ngrok-free.app)
  • Optional: View traffic logs in the ngrok dashboard

2. Configure PropelAuth Settings

  • Navigate to the PropelAuth dashboard

  • If needed, switch to the aipolabs local organization by clicking your account name and selecting Switch to aipolabs local

  • In the Users and Organizations tabs:

    • Remove any previously created test users and organizations
  • In the Frontend Integrations tab:

    • Locate and copy the Auth URL
    • Use this URL for both:
      • SERVER_PROPELAUTH_AUTH_URL in backend's .env.local
      • NEXT_PUBLIC_AUTH_URL in frontend's .env
  • In the Backend Integration tab (if you need a new API key):

    1. Click Create New API Key
    2. Name it <Your name> Local Testing
    3. Copy the key and set it as SERVER_PROPELAUTH_API_KEY in .env.local

3. Set Up Webhooks

  • Navigate to Integrations โ†’ Webhooks in the dashboard
  • Click Set Up Webhooks for the TEST ENV
  • On the Svix endpoints page:
    1. Click Add Endpoint
    2. For the endpoint URL, enter your ngrok URL followed by the path:
      text
      <your-ngrok-url>/v1/webhooks/auth/user-created
    3. Subscribe to the user.created event
    4. Click Create
  • After creation:
    • Find and copy the Signing Secret
    • Set it as SERVER_SVIX_SIGNING_SECRET in .env.local

4. Update Docker Configuration

  • Edit backend/compose.yml to comment out the PropelAuth mock service:
    • In the server service section, comment out:
      yaml
      # - ./mock/propelauth_fastapi_mock.py:/workdir/.venv/lib/python3.12/site-packages/propelauth_fastapi/__init__.py
    • In the runner service section, comment out:
      yaml
      # - ./mock/propelauth_fastapi_mock.py:/workdir/.venv/lib/python3.12/site-packages/propelauth_fastapi/__init__.py

5. Restart the Docker container

6. Verify Your Setup

Test your configuration by:

  • Visiting your frontend application (typically at http://localhost:3000)
  • Creating a new account or logging in
  • When successful, the webhook should trigger and automatically create the organization and project

Stripe Webhooks

[!NOTE]
This is only needed if you need to develop the stripe billing features.

  1. Download the Stripe CLI

  2. Log into our Stripe Sandbox with the CLI

    shell
    stripe login
  3. Set up webhooks with the Stripe CLI and get the webhook signing secret. By default,
    all events in the Sandbox will be forwarded to the local webhook endpoint. You can also
    use --event flag to filter the set of events you want to listen to.

    shell
    stripe listen --forward-to localhost:8000/v1/billing/webhook
    > Ready! You are using Stripe API Version [2025-02-24.acacia]. Your webhook signing secret is whsec_3b397734bb0362eac34a9611cc842f4a8cfb8f0e38eccf7ee666b09ac3aeec52
  4. Set the following two env vars in .env.local:

    • SERVER_STRIPE_SECRET_KEY: get it from the Stripe dashboard
    • SERVER_STRIPE_WEBHOOK_SIGNING_SECRET: get it from the output of the stripe listen command you just executed

Admin CLI

The CLI module is an internal admin tool for ACI to manage apps, functions, users, etc.
For local development, the commands can be executed via the runner container.

To see all available commands and their usage, run:

bash
docker compose exec runner python -m aci.cli --help

Example output:

bash
Usage: python -m aci.cli [OPTIONS] COMMAND [ARGS]...

  AIPO CLI Tool

Options:
  -h, --help  Show this message and exit.

Commands:
  create-agent                   Create an agent in db.
  create-project                 Create a project in db.
  create-random-api-key          Create a random test api key for local...
  delete-app                     Delete an app and all its references...
  fuzzy-test-function-execution  Test function execution with...
  get-app                        Get an app by name from the database.
  rename-app                     Rename an app and update all related...
  update-agent                   Update an existing agent in db.
  upsert-app                     Insert or update an App in the DB from a...
  upsert-functions               Upsert functions in the DB from a JSON...

To create a new app, run:

bash
docker compose exec runner python -m aci.cli create-app --app-file ./apps/brave_search/app.json --secrets-file ./apps/brave_search/.app.secrets.json

Running Evaluations

You will need to set up the following environment variables:

bash
EVALS_SERVER_URL=<your_server_url_typically_http://localhost:8000>
EVALS_ACI_API_KEY=<your_api_key_for_the_server_returned_from_seed_db_script>
EVALS_OPENAI_KEY=<your_openai_api_key>
EVALS_WANDB_KEY=<your_wandb_api_key>

The evaluation results will be logged to Weights & Biases where you can track metrics, view experiment configurations, and analyze the results.

Then, seed the database with all apps and mock credentials:

bash
docker compose exec runner ./scripts/seed_db.sh --all --mock

Running the Evaluation Pipeline

To run the complete evaluation pipeline with different modes:

bash
# Generate synthetic intents and evaluate them
docker compose exec runner python -m evals.evaluation_pipeline --mode generate-and-evaluate

# Only generate synthetic intent data
docker compose exec runner python -m evals.evaluation_pipeline --mode generate-only

# Only evaluate using existing dataset
docker compose exec runner python -m evals.evaluation_pipeline --mode evaluate-only

Additional flags:

bash
# Specify a custom dataset artifact name (default: "synthetic_intent_dataset")
docker compose exec runner python -m evals.evaluation_pipeline --mode evaluate-only --dataset-artifact my_custom_artifact

# Specify the filename saved on the dataset artifact
docker compose exec runner python -m evals.evaluation_pipeline --mode evaluate-only --dataset-filename my_custom_dataset.csv

# Limit the number of samples to generate
docker compose exec runner python -m evals.evaluation_pipeline --mode generate-only --generation-limit 50

# Limit the number of samples to evaluate
docker compose exec runner python -m evals.evaluation_pipeline --mode evaluate-only --evaluation-samples 25

[!NOTE]
If you use the generate-and-evaluate mode, the pipeline will use the freshly generated dataset directly
without having to reload it from Weights & Biases, which is more efficient.

Contributing

Please refer to the Contributing Guide for details on making contributions to this project.

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.


File: frontend/src/components/ui-extensions/enhanced-data-table/README.md

EnhancedDataTable Component Documentation

The EnhancedDataTable is a data table component built on TanStack Table (React Table), providing advanced features such as sorting, filtering, searching, and row selection. This documentation will help you quickly understand and effectively use this component.

Table of Contents

Basic Usage

To use the EnhancedDataTable, you need to provide two basic parameters: columns (column definitions) and data (data source).

tsx
import { EnhancedDataTable } from "@/components/ui-extensions/enhanced-data-table/data-table";
import { useMyTableColumns } from "./useMyTableColumns";

export function MyTable({ data }) {
  // Use custom hook to get column definitions
  const columns = useMyTableColumns();

  return (
    <EnhancedDataTable
      columns={columns}
      data={data}
      searchBarProps={{ placeholder: "Search..." }}
    />
  );
}

Column Definitions

It's recommended to create column definition hooks in separate files using createColumnHelper to get better type support.

Creating Basic Column Definition Files

tsx
// useMyTableColumns.tsx
import { useMemo } from "react";
import { createColumnHelper, type ColumnDef } from "@tanstack/react-table";
import { MyDataType } from "@/lib/types/myDataType";

const columnHelper = createColumnHelper<MyDataType>();

export const useMyTableColumns = (): ColumnDef<MyDataType>[] => {
  return useMemo(
    () => [
      columnHelper.accessor("name", {
        header: "Name",
        cell: (info) => info.getValue(),
        enableGlobalFilter: true,
      }),
      columnHelper.accessor("description", {
        header: "Description",
        cell: (info) => info.getValue(),
        enableGlobalFilter: true,
      }),
    ],
    [],
  );
};

Column Properties Explained

  • header: Column title, can be a string or React component
  • cell: Cell rendering function
  • enableGlobalFilter: Whether to include this column in global search
  • enableColumnFilter: Whether to enable column filtering
  • filterFn: Filter function type, e.g., "arrIncludes" for array fields
  • id: Custom column ID, required when using accessor function
  • meta: Used to set default sorting and other metadata

Creating Sortable Columns

tsx
columnHelper.accessor("name", {
  header: ({ column }) => (
     column.toggleSorting(column.getIsSorted() === "asc")}
      className="w-full justify-start px-0"
    >
      Name
      <ArrowUpDown className="h-4 w-4" />
    
  ),
  cell: (info) => info.getValue(),
  enableGlobalFilter: true,
  // Set as default sort column
  meta: {
    defaultSort: true,
    defaultSortDesc: false,
  },
});

Search and Filtering

Provide the searchBarProps parameter and ensure relevant columns have enableGlobalFilter: true:

tsx
<EnhancedDataTable
  columns={columns}
  data={data}
  searchBarProps={{ placeholder: "Search..." }}
/>

Column Filtering Functionality

EnhancedDataTable provides singleโ€‘value dropdown filtering for arrayโ€‘type columns. :

  1. Set enableColumnFilter: true
  2. Set filterFn: "arrIncludes"

Enabling Dropdown Filtering for Array Type Columns

tsx
// Using dropdown filtering for tag arrays
columnHelper.accessor("tags", {
  header: "Tags",
  cell: (info) => (
    
      {info.getValue().map((tag) => (
        
          {tag}
        
      ))}
    
  ),
  enableGlobalFilter: true,
  enableColumnFilter: true, // Enable column filtering
  filterFn: "arrIncludes", // Specify array filtering function
});

Handling Arrays from Non-Standard Data Sources

For array data not in default fields, you can use custom accessors:

tsx
// Handling nested objects or transforming data
columnHelper.accessor(
  (row) => row.metadata?.categories || [], // Extract array from nested object
  {
    id: "categoriesDisplay", // Must provide unique ID
    header: "Categories",
    cell: (info) => (
      
        {info.getValue().map((category) => (
          
            {category}
          
        ))}
      
    ),
    enableColumnFilter: true,
    filterFn: "arrIncludes",
  },
);

Automatic Filter UI Generation

When the following conditions are met, the table will automatically generate dropdown filter menus for columns:

  1. Column has enableColumnFilter: true
  2. Column uses filterFn: "arrIncludes"

Filters will be displayed in the top toolbar of the table, allowing users to select multiple values for filtering.

Sorting Functionality

Setting Default Sorting

You can set default sorting in two ways:

  1. Using the meta property in column definition:
tsx
columnHelper.accessor("createdAt", {
  header: "Created At",
  cell: (info) => new Date(info.getValue()).toLocaleString(),
  id: "createdAt",
  meta: {
    defaultSort: true,
    defaultSortDesc: true, // Default descending order
  },
});
  1. Through the component's defaultSorting property:
tsx
<EnhancedDataTable
  columns={columns}
  data={data}
  defaultSorting={[
    {
      id: "createdAt",
      desc: true,
    },
  ]}
/>

Row Selection

To enable row selection functionality, you need to provide rowSelectionProps:

tsx
const [rowSelection, setRowSelection] = useState({});

<EnhancedDataTable
  columns={columns}
  data={data}
  rowSelectionProps={{
    rowSelection,
    onRowSelectionChange: setRowSelection,
    getRowId: (row) => row.id,
  }}
/>;

This will add a selection checkbox column to the left of the table, allowing users to select multiple rows of data.

Custom Column Styling and Actions

Image and Text Combination Column

tsx
columnHelper.accessor("app_name", {
  header: "App Name",
  cell: (info) => {
    const appName = info.getValue();
    return (
      
        
          {appsMap[appName]?.logo && (
            
          )}
        
        
      
    );
  },
  enableGlobalFilter: true,
});

Tag Rendering

tsx
columnHelper.accessor("tags", {
  header: "Tags",
  cell: (info) => (
    
      {(info.getValue() || []).map((tag) => (
        
          {tag}
        
      ))}
    
  ),
  enableGlobalFilter: true,
  enableColumnFilter: true,
  filterFn: "arrIncludes",
});

Custom Action Buttons Column

tsx
columnHelper.accessor(
  (row) => row, // Get entire row data
  {
    id: "actions",
    header: "",
    cell: (info) => {
      const item = info.getValue();
      return (
        
          <Link href={`/items/${item.id}`}>
            
              Open
            
          </Link>
          
            <GoTrash />
          
        
      );
    },
    enableGlobalFilter: false,
  },
);

Editable Cells

tsx
columnHelper.accessor("name", {
  header: "Name",
  cell: (ctx) => {
    const item = ctx.row.original;
    return (
      <EditableCell
        initialValue={item.name}
        fieldName="name"
        itemId={item.id}
        onUpdate={handleUpdate}
      />
    );
  },
  enableGlobalFilter: true,
});

Pagination

EnhancedDataTable supports client-side pagination using TanStack Tableโ€™s built-in getPaginationRowModel().

To enable pagination, pass the paginationOptions prop:

tsx
<EnhancedDataTable
  columns={columns}
  data={data}
  paginationOptions={{
    initialPageIndex: 0, // Default to first page (0-based)
    initialPageSize: 10, // Number of entries per page
  }}
/>

Practical Application Examples

App Configuration Table (with Icons, Category Filtering, and Toggle Switch)

tsx
// In page component
import { EnhancedDataTable } from "@/components/ui-extensions/enhanced-data-table/data-table";
import { useAppConfigsTableColumns } from "./useAppConfigsTableColumns";

export function AppConfigsPage() {
  const [appConfigs, setAppConfigs] = useState<AppConfig[]>([]);
  // ...other states and logic

  const appConfigsColumns = useAppConfigsTableColumns({
    linkedAccountsCountMap,
    appsMap,
    updateAppConfigs: loadAllData,
  });

  return (
    
      <EnhancedDataTable
        data={appConfigs}
        columns={appConfigsColumns}
        searchBarProps={{ placeholder: "Search apps..." }}
      />
    
  );
}

Agents Table (with Editable Cells and Custom Actions)

tsx
// In page component
import { EnhancedDataTable } from "@/components/ui-extensions/enhanced-data-table/data-table";
import { useAgentsTableColumns } from "./useAgentsTableColumns";

export function AgentsPage() {
  const [agents, setAgents] = useState<Agent[]>([]);
  // ...other states and logic

  const columns = useAgentsTableColumns(
    projectId,
    handleDeleteAgent,
    reloadAgents,
    handleInstructionsSave,
  );

  return (
    
      <EnhancedDataTable
        data={agents}
        columns={columns}
        searchBarProps={{ placeholder: "Search agents..." }}
      />
    
  );
}

File: frontend/README.md

Aipolabs Developer Portal

The developer portal for Aipolabs, a platform for developers to manage and configure the apps and functions used by their agents.

Table of Contents

Description

The Dev Portal enables developers to create and manage their projects efficiently. It provides the following key pages for comprehensive project management:

  • Projects Settings
  • Home Page
  • App Store Page
  • App Configurations Page
  • Linked Accounts Page
  • Agent Playground Page
  • Account Settings

Development Setup

  1. Bring up backend in docker compose:
    Refer to the backend README to set it up. Make sure you
    complete the Webhooks section of the setup.

  2. Make sure you are in the frontend directory

  3. Install dependencies:
    If you're using npm:

    bash
    npm install --legacy-peer-deps

    (Note: This repo uses Next.js 15, which requires React 19 that is
    stabilized in Dec 05, 2024.
    Some libraries are still upgrading to React 19, so we need to use the
    --legacy-peer-deps flag in the mean time.)

  4. Configure Environment Variables: Copy .env.example to .env

    bash
    cp .env.example .env
  5. Start the application:

    bash
    npm run dev
  6. Sign up on the local dev portal:
    After signup, a new user will be created in the PropelAuth local dev org's test
    environment. PropelAuth will also call the user-created webhook, which will create a
    test project and agent in your local DB for you to use.

Linting & Testing

This repo uses prettier for formatting, next lint for linting, and vitest for unit tests.

  • Format code:

    bash
    npm run format
  • Run linters:

    bash
    npm run lint
  • Run vitest in watch mode:

    bash
    npm run test
  • Get test coverage:

    bash
    npm run test:coverage

You can also setup pre-commit hook to run format, lint, and tests when you
commit your code by running (make sure you have pre-commit installed):

bash
pre-commit install

Directory Structure

text
src
โ”œโ”€โ”€ app (Next.js App Router folder)
โ”‚   โ”œโ”€โ”€ ... (different pages of the dev portal)
โ”œโ”€โ”€ components
โ”‚   โ”œโ”€โ”€ ... (components we created for use in the pages of dev portal)
โ”‚   โ””โ”€โ”€ ui  (shadcn/ui components we installed)
โ”œโ”€โ”€ hooks
โ”‚   โ””โ”€โ”€ use-mobile.tsx
โ””โ”€โ”€ lib
โ”‚   โ”œโ”€โ”€ api          (functions for interacting with the Aipolabs backend API)
โ”‚   โ”œโ”€โ”€ types        (types of the Aipolabs backend API response)
โ”‚   โ””โ”€โ”€ utils.ts
โ””โ”€โ”€ __test__ (test files, the structure of this folder should be the same as the structure of the src/app folder)
    โ”œโ”€โ”€ apps
    โ”œโ”€โ”€ linked-accounts
    โ”œโ”€โ”€ project-setting
    โ””โ”€โ”€ ...

Conventions

  • All functions calling the backend API directly should be put in the src/lib/api folder.

Deployment

The Dev Portal is deployed on Vercel: obnoxiousproxys-projects/aci-dev-portal

The environment variables need to be set correctly on Vercel: https://vercel.com/obnoxiousproxys-projects/aci-dev-portal/settings/environment-variables.

For example, for the Vercel production environment, we set the following environment variables:

sh
NEXT_PUBLIC_API_URL=https://api.aci.dev
NEXT_PUBLIC_DEV_PORTAL_URL=https://platform.aci.dev
NEXT_PUBLIC_ENVIRONMENT=production
NEXT_PUBLIC_AUTH_URL=<actual_production_propelauth_endpoint>