AI / Copilot Integration

Integrate the Coherence Copilot AI assistant into your application

The Coherence Copilot is an AI-powered assistant that enables natural language interactions with your CRM data. Built on CopilotKit, it provides chat-based commands, intelligent record management, and AI-generated content.

Overview

The Copilot integration enables:

  • Natural Language Commands - Create, update, and query records using conversational language
  • Context-Aware Assistance - AI understands your current page, selected records, and conversation history
  • Custom Actions - Register application-specific actions the AI can execute
  • AI-Generated Content - Draft emails, create record summaries, and suggest field values
  • Generative UI - Actions render interactive components directly in the chat

Chat Completions

Endpoint

POST https://api.getcoherence.io/v1/copilot

The Copilot endpoint processes natural language messages and returns AI responses with optional tool calls.

Authentication

All requests require authentication:

curl -X POST "https://api.getcoherence.io/v1/copilot" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{...}'

Request Format

The Copilot uses the CopilotKit runtime protocol. Messages follow a standard chat format:

interface CopilotRequest {
  messages: Message[];
  threadId?: string;
  runId?: string;
}
 
interface Message {
  role: "user" | "assistant" | "system";
  content: string;
}

Example Request

{
  "messages": [
    {
      "role": "user",
      "content": "Show me my overdue tasks"
    }
  ],
  "threadId": "thread_abc123"
}

Streaming Responses

The Copilot endpoint returns Server-Sent Events (SSE) for real-time streaming:

const response = await fetch("https://api.getcoherence.io/v1/copilot", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    messages: [{ role: "user", content: "Create a task called Review Q4 Report" }],
  }),
});
 
const reader = response.body.getReader();
const decoder = new TextDecoder();
 
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
 
  const chunk = decoder.decode(value);
  // Process SSE events
  console.log(chunk);
}

Context Passing

Provide context about the current record or module to enhance AI understanding:

// Using CopilotKit's useCopilotReadable hook
useCopilotReadable({
  description: "Current page context",
  value: {
    pageType: "moduleRecord",
    moduleSlug: "tasks",
    recordId: "rec_abc123",
    recordName: "Review Q4 Report",
  },
});

The AI uses this context to:

  • Reference "this record" or "the current task"
  • Suggest relevant actions based on page type
  • Pre-fill fields when creating related records

Custom Actions

Register custom actions that the AI can invoke on behalf of users. Actions enable the Copilot to perform application-specific operations.

Action Schema

{
  "name": "create_task",
  "description": "Create a follow-up task for the current record",
  "parameters": [
    {
      "name": "title",
      "type": "string",
      "description": "The task title",
      "required": true
    },
    {
      "name": "dueDate",
      "type": "string",
      "description": "Due date in ISO format (YYYY-MM-DD)",
      "required": false
    },
    {
      "name": "priority",
      "type": "string",
      "description": "Priority level",
      "enum": ["low", "medium", "high"],
      "required": false
    }
  ]
}

Registering Actions (React)

Use the useCopilotAction hook to register actions:

import { useCopilotAction } from "@copilotkit/react-core";
 
useCopilotAction({
  name: "createTask",
  description: "Create a new task in the Tasks module",
  parameters: [
    {
      name: "title",
      type: "string",
      description: "The task title",
      required: true,
    },
    {
      name: "priority",
      type: "string",
      description: "Priority: low, medium, or high",
      enum: ["low", "medium", "high"],
    },
    {
      name: "dueDate",
      type: "string",
      description: "Due date in YYYY-MM-DD format",
    },
  ],
  handler: async ({ title, priority, dueDate }) => {
    const result = await createTask({ title, priority, dueDate });
    return {
      success: true,
      recordId: result.id,
      message: `Created task: ${title}`,
    };
  },
});

Built-in Actions

Coherence provides several built-in actions:

ActionDescription
queryRecordsSearch and filter module records
createRecordCreate a new record with field values
createMultipleRecordsBatch create multiple records
updateRecordsUpdate fields on one or more records
getModuleInfoGet module schema including fields and options
goToModuleNavigate to a module's list view
navigateToNavigate to any application route
searchRecordsFull-text search across records
createReminderSet a reminder for a future date
createCalendarEventCreate an event on connected calendars

Action Execution

When the AI decides to call an action, it returns a tool call in the response stream. The client library handles execution automatically.

Execution Flow

  1. User sends message - "Create 3 sample tasks for the project"
  2. AI analyzes intent - Determines createMultipleRecords is appropriate
  3. AI calls getModuleInfo - Discovers available fields and valid options
  4. AI executes action - Calls createMultipleRecords with proper field values
  5. Result returned - Action handler returns success/failure
  6. AI responds - Summarizes what was created with clickable links

Handling Action Results

Actions should return structured results:

// Success response
{
  success: true,
  recordId: "rec_xyz789",
  data: { /* created/updated record */ },
  message: "Task created successfully"
}
 
// Error response
{
  success: false,
  error: "validation_error",
  message: "The 'priority' field must be one of: low, medium, high"
}

Generative UI

Actions can render interactive UI components in the chat:

useCopilotAction({
  name: "showTasks",
  description: "Display tasks in an interactive list",
  handler: async ({ filter }) => {
    const tasks = await fetchTasks(filter);
    return tasks;
  },
  render: ({ status, result }) => {
    if (status === "executing") {
      return <LoadingSpinner />;
    }
    return <TaskList tasks={result} onTaskClick={handleClick} />;
  },
});

Context Providers

Give the AI access to relevant application data through readable context.

Registering Context

import { useCopilotReadable } from "@copilotkit/react-core";
 
// Current page context
useCopilotReadable({
  description: "Current page and navigation context",
  value: {
    pageType: "moduleList",
    moduleSlug: "deals",
    moduleName: "Deals",
    filters: { status: "open" },
  },
});
 
// User context
useCopilotReadable({
  description: "Current user information",
  value: {
    userId: user.id,
    name: user.fullName,
    email: user.email,
    role: user.role,
  },
});
 
// Available modules
useCopilotReadable({
  description: "Modules available in this workspace",
  value: modules.map(m => ({
    slug: m.slug,
    name: m.name,
    pluralName: m.pluralName,
  })),
});

Date/Time Context

Always provide current date/time for relative date handling:

const now = new Date();
const tomorrow = new Date(now);
tomorrow.setDate(tomorrow.getDate() + 1);
 
useCopilotReadable({
  description: "Current date and time for relative date calculations",
  value: {
    currentDate: now.toISOString().split("T")[0],
    tomorrow: tomorrow.toISOString().split("T")[0],
    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
    dayOfWeek: now.toLocaleDateString("en-US", { weekday: "long" }),
  },
});

Suggested Prompts

Provide prompt templates to help users get started:

import { useCopilotSuggestions } from "@copilotkit/react-ui";
 
useCopilotSuggestions({
  instructions: "Suggest helpful actions based on the current page",
  suggestions: [
    "Show my overdue tasks",
    "Create a follow-up task for this deal",
    "What should I focus on today?",
    "Summarize recent activity",
  ],
});

Dynamic Suggestions

Generate suggestions based on context:

const getSuggestions = (pageContext) => {
  if (pageContext.pageType === "moduleRecord") {
    return [
      `Show related ${pageContext.moduleName} records`,
      "Add a note to this record",
      "Create a follow-up task",
    ];
  }
 
  if (pageContext.pageType === "dashboard") {
    return [
      "Add a chart widget",
      "Show my pipeline metrics",
      "What needs attention today?",
    ];
  }
 
  return ["What can you help me with?"];
};

AI-Generated Content

Email Drafts

Generate contextual email drafts:

useCopilotAction({
  name: "draftEmail",
  description: "Generate an email draft based on context",
  parameters: [
    { name: "type", type: "string", enum: ["follow_up", "introduction", "proposal"] },
    { name: "recipientName", type: "string" },
    { name: "context", type: "string", description: "Additional context for the email" },
  ],
  handler: async ({ type, recipientName, context }) => {
    const response = await generateEmail({ type, recipientName, context });
    return {
      subject: response.subject,
      body: response.body,
    };
  },
  render: ({ result }) => (
    <EmailPreview
      subject={result.subject}
      body={result.body}
      onSend={handleSend}
      onEdit={handleEdit}
    />
  ),
});

Record Summaries

Generate natural language summaries of records:

// Request summary for a deal record
const summary = await copilot.summarize({
  moduleSlug: "deals",
  recordId: "rec_abc123",
  format: "brief", // or "detailed"
});
 
// Returns:
{
  summary: "High-priority deal with Acme Corp worth $50K. Last contacted 3 days ago. Next step: Schedule demo call.",
  highlights: [
    { label: "Value", value: "$50,000" },
    { label: "Stage", value: "Proposal" },
    { label: "Close Date", value: "Feb 15, 2026" },
  ],
}

Field Suggestions

AI-powered field value suggestions:

// Get suggestions for a field based on record context
const suggestions = await copilot.suggestFieldValue({
  moduleSlug: "tasks",
  recordId: "rec_xyz789",
  fieldSlug: "priority",
  context: {
    title: "Urgent client escalation",
    description: "Client reported critical bug in production",
  },
});
 
// Returns:
{
  suggested: "high",
  confidence: 0.95,
  reasoning: "Contains 'urgent' and 'critical' indicating high priority",
}

Embedding Copilot

Using CopilotKit

Wrap your application with the CopilotKit provider:

import { CopilotKit } from "@copilotkit/react-core";
import { CopilotSidebar } from "@copilotkit/react-ui";
 
function App() {
  return (
    <CopilotKit
      runtimeUrl="https://api.getcoherence.io/v1/copilot"
      headers={{
        Authorization: `Bearer ${accessToken}`,
      }}
    >
      <CopilotSidebar>
        <YourAppContent />
      </CopilotSidebar>
    </CopilotKit>
  );
}

Customizing Appearance

Style the Copilot UI to match your application:

<CopilotSidebar
  labels={{
    title: "AI Assistant",
    placeholder: "Ask anything about your data...",
  }}
  defaultOpen={false}
  className="your-custom-class"
/>

Custom Chat Components

Build a fully custom chat interface:

import { useCopilotChat } from "@copilotkit/react-core";
 
function CustomChat() {
  const { messages, sendMessage, isLoading } = useCopilotChat();
 
  return (
    <div className="chat-container">
      {messages.map((msg) => (
        <Message key={msg.id} message={msg} />
      ))}
 
      <ChatInput
        onSubmit={sendMessage}
        disabled={isLoading}
      />
    </div>
  );
}

Handling Responses

Process AI responses and action results:

const { sendMessage, onResponse } = useCopilotChat({
  onResponse: (response) => {
    // Handle streaming response
    console.log("AI response:", response.content);
  },
  onActionResult: (action, result) => {
    // Handle action completion
    if (action.name === "createRecord" && result.success) {
      toast.success(`Created: ${result.data.name}`);
    }
  },
  onError: (error) => {
    toast.error("Something went wrong. Please try again.");
  },
});

Rate Limits and Usage

Credit System

AI operations consume credits based on complexity:

OperationCredits
Simple query1
Record query with filters2
Create single record3
Create multiple records5
Calendar integration3
Content generation5-10

Plan Limits

PlanIncluded CreditsOverage Rate
Free100/monthNot available
Starter500/month$0.01/credit
Growth2,000/month$0.008/credit
EnterpriseCustomCustom

Checking Usage

// Get current usage
const usage = await fetch("/api/v1/module-config/usage/ai", {
  headers: { Authorization: `Bearer ${token}` },
}).then(r => r.json());
 
// Returns:
{
  current: 450,
  included: 500,
  overage: 0,
  percentOfIncluded: 90,
  billingMode: "soft_limit",
  periodEnd: "2026-02-01T00:00:00Z",
}

Model Selection

Choose different AI models based on task complexity:

// Pass model preference in headers
fetch("/api/v1/copilot", {
  headers: {
    "Authorization": `Bearer ${token}`,
    "x-copilot-model": "gpt-4o-mini", // faster, cheaper
    // or "gpt-4o" for complex tasks
  },
});

Higher-capability models like GPT-4o consume more credits per request. Use GPT-4o-mini for simple queries and GPT-4o for complex multi-step operations.

Best Practices

Provide Good Context

Always include relevant context for better AI responses:

// Good - specific context
useCopilotReadable({
  description: "Current deal being viewed",
  value: {
    dealId: deal.id,
    dealName: deal.name,
    stage: deal.stage,
    value: deal.value,
    contacts: deal.contacts.map(c => c.name),
  },
});
 
// Avoid - too generic or missing key details
useCopilotReadable({
  description: "Deal",
  value: deal.id, // Missing context AI needs
});

Handle Errors Gracefully

Implement proper error handling in action handlers:

useCopilotAction({
  name: "updateRecord",
  handler: async ({ recordId, fields }) => {
    try {
      const result = await updateRecord(recordId, fields);
      return {
        success: true,
        data: result,
      };
    } catch (error) {
      if (error.code === "VALIDATION_ERROR") {
        return {
          success: false,
          error: "validation_error",
          message: error.message,
          details: error.fields, // Help AI understand what went wrong
        };
      }
      throw error; // Let unexpected errors bubble up
    }
  },
});

Validate AI-Suggested Actions

For sensitive operations, confirm with users:

useCopilotAction({
  name: "deleteRecords",
  description: "Delete multiple records (requires confirmation)",
  parameters: [
    { name: "recordIds", type: "string[]" },
    { name: "confirmed", type: "boolean", description: "User has confirmed deletion" },
  ],
  handler: async ({ recordIds, confirmed }) => {
    if (!confirmed) {
      return {
        requiresConfirmation: true,
        message: `Are you sure you want to delete ${recordIds.length} records? This cannot be undone.`,
        recordCount: recordIds.length,
      };
    }
 
    await deleteRecords(recordIds);
    return { success: true, deleted: recordIds.length };
  },
});

Optimize for Token Efficiency

Keep context data lean to reduce costs and improve response quality:

// Sanitize large fields before providing as context
function sanitizeRecordForAI(record) {
  const { notes, description, htmlContent, ...safeFields } = record;
 
  return {
    ...safeFields,
    // Truncate long text fields
    notes: notes?.slice(0, 200),
    // Omit HTML entirely
  };
}

Register the discoverSystem action to let the AI explore your application's capabilities dynamically rather than hardcoding everything in context.


Related: API Overview | Authentication | Webhooks