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:
| Action | Description |
|---|---|
queryRecords | Search and filter module records |
createRecord | Create a new record with field values |
createMultipleRecords | Batch create multiple records |
updateRecords | Update fields on one or more records |
getModuleInfo | Get module schema including fields and options |
goToModule | Navigate to a module's list view |
navigateTo | Navigate to any application route |
searchRecords | Full-text search across records |
createReminder | Set a reminder for a future date |
createCalendarEvent | Create 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
- User sends message - "Create 3 sample tasks for the project"
- AI analyzes intent - Determines
createMultipleRecordsis appropriate - AI calls getModuleInfo - Discovers available fields and valid options
- AI executes action - Calls
createMultipleRecordswith proper field values - Result returned - Action handler returns success/failure
- 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:
| Operation | Credits |
|---|---|
| Simple query | 1 |
| Record query with filters | 2 |
| Create single record | 3 |
| Create multiple records | 5 |
| Calendar integration | 3 |
| Content generation | 5-10 |
Plan Limits
| Plan | Included Credits | Overage Rate |
|---|---|---|
| Free | 100/month | Not available |
| Starter | 500/month | $0.01/credit |
| Growth | 2,000/month | $0.008/credit |
| Enterprise | Custom | Custom |
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