ColineColineColineDocs

API & SDK

Build custom integrations and extend Coline with the Kairo SDK. Authenticate with OAuth 2.0, stream AI responses, and integrate Kairo into your applications.

Overview

The Kairo SDK provides:

  • OAuth 2.0 authentication with PKCE and device flow support
  • Streaming API for AI agent responses
  • TypeScript SDKs for Node.js and browser environments
  • Token management with automatic refresh

SDKs

Install the official SDK packages from npm:

# Core types and utilities
npm install @colineapp/kairo-core

# OAuth authentication helpers
npm install @colineapp/kairo-auth

# AI agent streaming client
npm install @colineapp/kairo-agent

# Kairo Code client with ACP/A2A adapter helpers
npm install @colineapp/kairo-code

# ACP CLI bridge for editors
npm install @colineapp/kairo-code-acp

All packages require Node.js 20 or later and are published under the Apache-2.0 license.

PackageDescription
@colineapp/kairo-coreCore types, SSE streaming utilities, error handling
@colineapp/kairo-authOAuth helpers for PKCE, token exchange, device flow, token management
@colineapp/kairo-agentAgent client for streaming AI responses
@colineapp/kairo-codeKairo Code client with native ACP/A2A adapter helpers
@colineapp/kairo-code-acpACP-compatible kairo-code-acp CLI bridge for editor integrations

Authentication

The Kairo API uses OAuth 2.0 with PKCE (required). Two authentication flows are supported:

Authorization code flow

For web applications with a redirect URI:

import {
  createAuthorizationRequest,
  exchangeAuthorizationCode,
  createTokenManager,
  MemoryTokenStorage,
} from '@colineapp/kairo-auth';

// 1. Create authorization request with PKCE
const authRequest = await createAuthorizationRequest({
  clientId: 'your-client-id',
  redirectUri: 'https://yourapp.com/callback',
  scope: ['kairo.agent:stream', 'kairo.models:read'],
});

// 2. Redirect user to authRequest.url
// User authorizes and is redirected back with ?code=...

// 3. Exchange code for tokens
const result = await exchangeAuthorizationCode({
  clientId: 'your-client-id',
  redirectUri: 'https://yourapp.com/callback',
  code: authorizationCode,
  codeVerifier: authRequest.pkce.codeVerifier,
});

// 4. Use token manager for automatic refresh
const tokenManager = createTokenManager({
  storage: new MemoryTokenStorage(),
  clientId: 'your-client-id',
});

await tokenManager.setTokens(result.tokens);

Device flow

For CLI tools, desktop apps, and environments without a browser redirect:

import {
  startDeviceAuthorization,
  pollDeviceAuthorization,
} from '@colineapp/kairo-auth';

// 1. Start device authorization
const device = await startDeviceAuthorization({
  clientId: 'your-client-id',
  scope: ['kairo.agent:stream', 'kairo.models:read'],
});

// 2. Display instructions to user
console.log(`Go to: ${device.verification_uri}`);
console.log(`Enter code: ${device.user_code}`);

// 3. Poll for authorization (blocks until user completes flow)
const result = await pollDeviceAuthorization({
  clientId: 'your-client-id',
  deviceCode: device.device_code,
  intervalSeconds: device.interval,
  expiresInSeconds: device.expires_in,
  onPending: ({ attempt }) => {
    console.log(`Waiting for authorization... (attempt ${attempt})`);
  },
});

console.log('Authorized! Access token:', result.tokens.accessToken);

Scopes

Request only the scopes your application needs:

ScopeDescription
kairo.agent:streamStream AI agent responses
kairo.code:streamStream code execution responses
kairo.models:readList available AI models

Default scopes: kairo.agent:stream kairo.models:read

Streaming AI responses

Use the agent client to stream responses from Kairo:

import { createKairoAgent } from '@colineapp/kairo-agent';

const agent = createKairoAgent({
  auth: tokenManager, // or access token string
});

// Stream with full control
const { events } = await agent.stream({
  contents: [
    {
      role: 'user',
      parts: [{ text: 'Explain how OAuth 2.0 works' }],
    },
  ],
  modelType: 'claude-opus-4.6', // optional, defaults to gpt-5.2
  reasoningLevel: 1, // 0 disables thinking, >0 enables it
  thinkingEffort: 'high', // Opus 4.6 only: low | medium | high | max
});

for await (const event of events) {
  if (event.parsed && event.data?.candidate_content?.parts) {
    for (const part of event.data.candidate_content.parts) {
      if (part.text) {
        process.stdout.write(part.text);
      }
    }
  }
}

// Or use streamText for simple text accumulation
const text = await agent.streamText({
  contents: [
    {
      role: 'user',
      parts: [{ text: 'Write a haiku about APIs' }],
    },
  ],
});

console.log(text);

Claude thinking behavior

  • claude-opus-4.6 uses adaptive thinking. Set thinkingEffort to low, medium, high, or max.
  • Opus 4.6 at thinkingEffort: "max" has a higher usage multiplier (6x).
  • claude-sonnet-4.5 and claude-opus-4.5 use reasoningLevel as on/off (0 off, 1-3 on) with a fixed 32k budget when enabled.
  • thinkingBudget is deprecated for Claude models.

Kairo Code tool behavior

  • POST /api/kairo/code/stream defaults enableTools to false so editor-native tools remain primary.
  • Set enableTools: true only when you explicitly want Coline-managed tool execution for that request.

ACP / A2A adapter support

Use @colineapp/kairo-code when your host runtime is ACP/A2A-oriented:

import { createKairoCode } from '@colineapp/kairo-code';

const code = createKairoCode({ auth: tokenManager });

const { events } = await code.streamAcp({
  modelId: 'claude-opus-4.6',
  enableTools: false,
  reasoningEnabled: true,
  thinkingEffort: 'high',
  messages: [
    { role: 'user', content: 'Create a README for this repo.' },
  ],
});

for await (const event of events) {
  if (event.type === 'message_delta') {
    process.stdout.write(event.text);
  }
  if (event.type === 'workspace_unavailable') {
    console.error(event.message);
  }
}

streamAcp emits adapter-friendly events (message_delta, tool_call, tool_result, tool_error, workspace_unavailable, done) so integrations do not need to hand-roll bridge glue.

Use the ACP CLI bridge package when your editor expects a spawnable ACP binary:

bun add -g --no-cache @colineapp/kairo-code-acp

Required runtime env var: KAIRO_ACCESS_TOKEN

Available models

Query available models at runtime:

import { listKairoModels } from '@colineapp/kairo-core';

const { models, defaultModel } = await listKairoModels();
console.log('Default:', defaultModel);
console.log('Available:', models);

Current models include: gpt-5-nano, gpt-5-mini, gpt-5, gpt-5.1, gpt-5.2, claude-opus-4.5, claude-sonnet-4.5, deepseek-v3.2, and more.

API endpoints

EndpointMethodDescription
/api/kairo/oauth/authorizeGETOAuth authorization
/api/kairo/oauth/tokenPOSTToken exchange and refresh
/api/kairo/oauth/device/authorizePOSTStart device flow
/api/kairo/oauth/revokePOSTRevoke tokens
/api/kairo/agent/streamPOSTStream AI agent responses
/api/kairo/code/streamPOSTStream code execution
/api/kairo/modelsGETList available models

Base URL: https://coline.app

Token management

The SDK includes a token manager that handles refresh automatically:

import {
  createTokenManager,
  MemoryTokenStorage,
} from '@colineapp/kairo-auth';

const tokenManager = createTokenManager({
  storage: new MemoryTokenStorage(), // or implement KairoTokenStorage
  clientId: 'your-client-id',
  minValidityMs: 30000, // refresh 30s before expiry
});

// Get a valid access token (refreshes automatically if needed)
const accessToken = await tokenManager.getAccessToken();

// Manually refresh
await tokenManager.refresh();

// Clear stored tokens
await tokenManager.clear();

Implement KairoTokenStorage interface for persistent storage:

interface KairoTokenStorage {
  getTokens(): Promise<KairoTokenSet | null> | KairoTokenSet | null;
  setTokens(tokens: KairoTokenSet | null): Promise<void> | void;
}

Token specifications

TokenLifetime
Access token60 minutes
Refresh token30 days
Authorization code10 minutes
Device code15 minutes

Tokens are automatically rotated on refresh.

Error handling

The SDK throws KairoError for API and authentication errors:

import { KairoError } from '@colineapp/kairo-core';

try {
  const { events } = await agent.stream({ contents: [...] });
} catch (error) {
  if (error instanceof KairoError) {
    console.error('Code:', error.code);
    console.error('Message:', error.message);
    console.error('Status:', error.status);
    console.error('Details:', error.details);
  }
}

Common error codes:

CodeDescription
missing_access_tokenNo token provided
expired_tokenToken has expired
invalid_grantInvalid or revoked refresh token
missing_refresh_tokenRefresh token not available
authorization_pendingDevice flow waiting for user

Resources

Tips

  • Use the token manager instead of handling tokens manually. It refreshes automatically before expiry.
  • Start with device flow for CLI tools and scripts. It is simpler than setting up redirect URIs.
  • Request minimal scopes. Only request what your application needs.
  • Handle streaming errors gracefully. Network interruptions can occur during long-running streams.
  • Cache the model list if you display model options. It does not change frequently.