Skip to main content

Overview

The CopilotKit endpoint is a Next.js App Router API route that bridges the frontend chat interface with the MABQ BigQuery Agent backend using the HttpAgent.

Endpoint Details

/api/copilotkit
POST
CopilotKit runtime endpoint for agent communication

Implementation

The endpoint is implemented in app/api/copilotkit/route.ts:
import {
  CopilotRuntime,
  copilotRuntimeNextJSAppRouterEndpoint,
} from "@copilotkit/runtime";
import { HttpAgent } from "@ag-ui/client";
import { NextRequest } from "next/server";

const BACKEND_URL = process.env.NEXT_PUBLIC_API_URL || 
  "https://mabq-backend-1093163678323.us-east4.run.app";

export const POST = async (req: NextRequest) => {
  const authHeader = req.headers.get("authorization") || "";
  
  const runtime = new CopilotRuntime({
    agents: {
      default_agent: new HttpAgent({ 
        url: BACKEND_URL,
        headers: {
          "Authorization": authHeader
        }
      }),
    },
  });

  const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
    runtime,
    serviceAdapter: new EmptyAdapter() as any, 
    endpoint: "/api/copilotkit",
  });

  return handleRequest(req);
};

CopilotRuntime Configuration

The CopilotRuntime manages the connection between the UI and the agent backend.

Runtime Setup

const runtime = new CopilotRuntime({
  agents: {
    default_agent: new HttpAgent({ 
      url: BACKEND_URL,
      headers: {
        "Authorization": authHeader
      }
    }),
  },
});
agents
object
required
Dictionary of available agents keyed by agent name
agents.default_agent
HttpAgent
required
The primary agent instance connected to the MABQ backend

HttpAgent Configuration

The HttpAgent proxies requests to the FastAPI backend:
new HttpAgent({ 
  url: BACKEND_URL,
  headers: {
    "Authorization": authHeader
  }
})
url
string
required
Backend URL from NEXT_PUBLIC_API_URL environment variable
headers
object
HTTP headers forwarded to the backend on every request
headers.Authorization
string
required
Azure AD Bearer token from the frontend request

Request Flow

Required Headers

Clients must include an Authorization header when calling this endpoint:
Authorization
string
required
Azure AD access token in Bearer format
Content-Type
string
default:"application/json"
Request content type

Example Request

const response = await fetch('/api/copilotkit', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    message: 'Show me the top 10 assets by value'
  })
});

const data = await response.json();

Request Body

The request body follows the CopilotKit protocol:
message
string
required
User’s natural language query for the agent
threadId
string
Conversation thread identifier for multi-turn conversations
runId
string
Unique run identifier for this request

Response Format

The endpoint returns a CopilotKit-formatted response:
message
string
Agent’s response message
data
object
Structured data from the agent (SQL query, results, etc.)
threadId
string
Conversation thread identifier

Example Response

{
  "message": "```sql\nSELECT asset_id, asset_name, value\nFROM `datawarehouse-des.STG_ACTIVOS.assets`\nORDER BY value DESC\nLIMIT 10\n```",
  "data": {
    "sql": "SELECT asset_id, asset_name, value FROM `datawarehouse-des.STG_ACTIVOS.assets` ORDER BY value DESC LIMIT 10",
    "results": [...]
  },
  "threadId": "thread_abc123"
}

Service Adapter

The endpoint uses an empty adapter as a placeholder:
class EmptyAdapter {
  async process(request: any) { return; }
}

const serviceAdapter = new EmptyAdapter() as any;
The EmptyAdapter is used because agent logic is handled entirely by the backend. Future implementations may add frontend-side processing.

Environment Variables

NEXT_PUBLIC_API_URL
string
required
Backend API URL (e.g., https://mabq-backend-1093163678323.us-east4.run.app)

Example Configuration

.env.local
NEXT_PUBLIC_API_URL=https://mabq-backend-1093163678323.us-east4.run.app

Error Handling

The endpoint will return errors from the backend or CopilotKit runtime:

403 Forbidden (Authentication Failed)

{
  "error": "Acceso Denegado. El token ha expirado."
}

500 Internal Server Error (Backend Failure)

{
  "error": "Agent execution failed",
  "details": "..."
}

422 Unprocessable Entity (Invalid Request)

{
  "error": "Invalid message format"
}

Authorization Header Forwarding

The key security feature is forwarding the Authorization header:
const authHeader = req.headers.get("authorization") || "";

// ...

headers: {
  "Authorization": authHeader
}
This ensures:
  • Each backend request is authenticated with the user’s token
  • The backend can validate user permissions
  • User identity is preserved throughout the request chain
Never hardcode authentication tokens in the frontend. Always forward the user’s token from the original request.

Integration with CopilotKit UI

The frontend uses this endpoint via the CopilotKit provider:
import { CopilotKit } from "@copilotkit/react-core";

<CopilotKit 
  runtimeUrl="/api/copilotkit"
  headers={() => ({
    Authorization: `Bearer ${accessToken}`
  })}
>
  {/* Your UI components */}
</CopilotKit>

Build docs developers (and LLMs) love