Mix LogoMix

TypeScript SDK

Type-safe TypeScript client for building AI agents with Mix. Full IntelliSense support and streaming capabilities.

Installation

npm add mix-typescript-sdk

For more examples, see the Mix TypeScript cookbook

Quickstart

import { Mix } from 'mix-typescript-sdk';

const mix = new Mix();

async function main() {
  // Create a session
  const session = await mix.sessions.create({
    title: "My First Session"
  });

  // Start streaming for real-time updates
  const stream = await mix.streaming.streamEvents({
    sessionId: session.id
  });

  // Send a message
  await mix.messages.send({
    id: session.id,
    requestBody: { text: "Hello from TypeScript SDK" }
  });

  // Process streaming events
  for await (const event of stream.result) {
    if (event.data?.type === "content") {
      process.stdout.write(event.data.content);
    }
  }
}

main();

API Selection Guide

API TypeUse CaseBundle SizeError HandlingBest For
SDK ClassFull-featured applicationsLargerThrows errorsNode.js, traditional apps
Standalone FunctionsOptimized bundlesSmaller (tree-shakeable)Returns Result<T, E>Browser, serverless

SDK Class:

import { Mix } from 'mix-typescript-sdk';
const mix = new Mix();
const session = await mix.sessions.create({ title: "Chat" });

Standalone Functions:

import { MixCore } from 'mix-typescript-sdk/core.js';
import { sessionsCreate } from 'mix-typescript-sdk/funcs/sessionsCreate.js';

const mix = new MixCore();
const result = await sessionsCreate(mix, { title: "Chat" });
if (result.ok) console.log(result.value);

Functions

Standalone Functions

All SDK operations are available as standalone functions for tree-shaking optimization. Each function follows the pattern:

import { MixCore } from 'mix-typescript-sdk/core.js';
import { functionName } from 'mix-typescript-sdk/funcs/functionName.js';

const mix = new MixCore();
const result = await functionName(mix, params);

Return Type: Result<Value, Error> - Use .ok to check success

Key Functions:

FunctionImport PathDescription
sessionsCreatefuncs/sessionsCreate.jsCreate new session
sessionsListfuncs/sessionsList.jsList all sessions
messagesGetSessionfuncs/messagesGetSession.jsGet session messages
messagesSendfuncs/messagesSend.jsSend message to session
streamingStreamEventsfuncs/streamingStreamEvents.jsEstablish SSE stream
filesUploadfuncs/filesUpload.jsUpload file to session
authenticationStoreApiKeyfuncs/authenticationStoreApiKey.jsStore provider API key

Streaming with Callbacks

Pattern for callback-based streaming:

interface StreamCallbacks {
  onThinking?: (text: string) => void;
  onContent?: (text: string) => void;
  onTool?: (tool: any) => void;
  onToolExecutionStart?: (data: any) => void;
  onToolExecutionComplete?: (data: any) => void;
  onError?: (error: string) => void;
  onPermission?: (data: any) => void;
  onComplete?: () => void;
}

async function sendWithCallbacks(
  mix: Mix,
  sessionId: string,
  message: string,
  callbacks: StreamCallbacks
): Promise<void> {
  // Establish stream
  const stream = await mix.streaming.streamEvents({ sessionId });

  // Allow connection to establish
  await new Promise(resolve => setTimeout(resolve, 500));

  // Send message in parallel
  const sendPromise = mix.messages.send({
    id: sessionId,
    requestBody: { text: message }
  });

  // Process events
  for await (const event of stream.result) {
    switch (event.event) {
      case "content":
        callbacks.onContent?.(event.data.content);
        break;
      case "thinking":
        callbacks.onThinking?.(event.data.content);
        break;
      case "complete":
        callbacks.onComplete?.();
        await sendPromise;
        return;
    }
  }
}

Classes

Mix

Main SDK class with the following namespaces:

NamespaceDescriptionKey Methods
authenticationManage provider credentialsstoreApiKey(), startOAuthFlow(), getAuthStatus()
sessionsSession managementcreate(), list(), fork(), exportSession()
messagesMessage operationssend(), getSession(), cancelProcessing()
streamingReal-time SSE eventsstreamEvents()
filesFile managementupload(), list(), get(), delete()
permissionsPermission grantsgrant(), deny()
preferencesUser preferencesget(), update(), getProviders()
toolsTool statusgetToolsStatus()
systemSystem operationshealthCheck(), listMcpServers(), getSystemInfo()

Constructor:

const mix = new Mix({
  serverURL?: string;           // Default: http://localhost:8088
  retryConfig?: RetryConfig;    // SDK-wide retry configuration
  httpClient?: HTTPClient;      // Custom HTTP client
  debugLogger?: Logger;         // Debug logging
});

Types

Configuration Types

type Provider = "anthropic" | "openai" | "openrouter" | "google";

type UpdatePreferencesRequest = {
  preferred_provider?: Provider;
  main_agent_model?: string;
  sub_agent_model?: string;
}

Session Types

type CreateSessionRequest = {
  title: string;
  systemPrompt?: string;  // Custom system prompt
}

type Session = {
  id: string;
  title: string;
  createdAt: string;
  updatedAt: string;
}

Message Types

type SendMessageRequest = {
  text: string;
}

type Message = {
  id: string;
  sessionId: string;
  role: 'user' | 'assistant';
  content: string;
  createdAt: string;
}

Message and Content Types

type FileInfo = {
  url: string;
  filename: string;
  size: number;
  mimeType: string;
  createdAt: string;
}

type SessionExportResponse = {
  session: Session;
  messages: Message[];
  files: FileInfo[];
}

type ForkSessionRequest = {
  messageIndex: number;  // Fork at this message index
}

type RewindSessionRequest = {
  messageIndex: number;  // Rewind to this message index
  cleanMedia?: boolean;  // Delete orphaned media files
}

Server-Sent Events (SSE) Types

SSEEventStream Structure:

type SSEEventStream = AsyncIterable<ServerSentEvent>;

type ServerSentEvent = {
  event: string;       // Event type
  data: EventData;     // Event-specific data
  id?: string;         // Event ID for reconnection
}

Event Types:

Event TypeDescriptionKey Fields
SSEConnectedEventConnection establishedtype: "connected"
SSEContentEventAI response chunkstype: "content", content: string
SSEThinkingEventAI reasoningtype: "thinking", content: string
SSEToolEventTool usagetype: "tool", name: string, input: any
SSEToolExecutionStartEventTool startedtype: "tool_execution_start", toolName: string
SSEToolExecutionCompleteEventTool completedtype: "tool_execution_complete", toolName: string, result: any
SSEPermissionEventPermission requesttype: "permission", id: string, action: string
SSECompleteEventProcessing donetype: "complete"
SSEHeartbeatEventKeep-alive heartbeattype: "heartbeat"
SSEErrorEventError occurredtype: "error", error: string

Error Types

class MixError extends Error {
  statusCode: number;
  body: string;
}

class ErrorResponse extends Error {
  error: string;
}

// Network errors
class ConnectionError extends Error {}
class RequestTimeoutError extends Error {}

// Validation errors
class ResponseValidationError extends Error {}

Retry Configuration

type RetryConfig = {
  strategy: "backoff" | "none";
  backoff?: {
    initialInterval: number;    // ms
    maxInterval: number;        // ms
    exponent: number;           // multiplier
    maxElapsedTime: number;     // ms
  };
  retryConnectionErrors: boolean;
}

Tool Input/Output Types

Media Tools

MediaType: Image, Video, Audio, GsapAnimation, Pdf, Csv

type MediaOutput = {
  path?: string;              // File path or URL
  type: MediaType;
  title: string;
  description?: string;
  config?: Record<string, any>;  // For gsap_animation
  startTime?: number;         // Seconds (video/audio)
  duration?: number;          // Seconds (video/audio)
}

type MediaShowcaseParams = {
  outputs: MediaOutput[];
}

Read Media Tool

MediaAnalysisType: Image, Audio, Video, Pdf

type ReadMediaParams = {
  filePath: string;
  mediaType: MediaAnalysisType;
  prompt: string;
  pdfPages?: string;          // e.g., "1-5,10"
  videoInterval?: string;     // e.g., "00:02:30-00:05:00"
}

type ReadMediaResult = {
  filePath: string;
  mediaType: string;
  analysis: string;
  error?: string;
}

Todo Tool

TodoStatus: Pending, InProgress, Completed TodoPriority: Low, Medium, High

type Todo = {
  id: string;
  content: string;
  status: TodoStatus;
  priority: TodoPriority;
}

type TodoWriteParams = {
  todos: Todo[];
}

File Operation Tools

Bash Tool:

type BashParams = {
  command: string;
  timeout?: number;  // Max 600000ms (10 min)
}

type BashResponseMetadata = {
  start_time: number;  // Unix timestamp (ms)
  end_time: number;    // Unix timestamp (ms)
}

Edit Tool:

type EditParams = {
  file_path: string;
  old_string: string;
  new_string: string;
}

type EditResponseMetadata = {
  diff: string;        // Unified diff
  additions: number;   // Lines added
  removals: number;    // Lines removed
}

Read Tool:

type ReadTextParams = {
  file_path: string;
  offset?: number;   // Line number (0-based)
  limit?: number;    // Lines to read (default: 2000)
}

type ReadTextResponseMetadata = {
  file_path: string;   // Path that was read
  content: string;     // Raw content without line numbers
}

Write Tool:

type WriteParams = {
  file_path: string;
  content: string;
}

type WriteResponseMetadata = {
  diff: string;        // Unified diff
  additions: number;   // Lines added
  removals: number;    // Lines removed
}

Glob Tool:

type GlobParams = {
  pattern: string;   // e.g., "**/*.ts"
  path?: string;     // Search directory
}

type GlobResponseMetadata = {
  number_of_files: number;  // Files found
  truncated: boolean;       // Results truncated?
}

Grep Tool:

type GrepParams = {
  pattern: string;      // Regex pattern
  path?: string;
  include?: string;     // File pattern
  literal_text?: boolean;
}

type GrepResponseMetadata = {
  number_of_matches: number;  // Total matches
  truncated: boolean;         // Results truncated?
}

Python Execution Tool:

type PythonExecutionParams = {
  code: string;  // Python code to execute
}

type PythonExecutionResult = {
  type: "code_execution_result";
  stdout: string;
  stderr: string;
  return_code: number;
}

Web Tools

WebFetch:

type WebFetchParams = {
  url: string;
  prompt: string;
}

type WebFetchResponseMetadata = {
  url: string;              // Original URL
  fetched_url?: string;     // Final URL after redirects
  content_type?: string;    // Content-Type header
  start_time: number;       // Unix timestamp (ms)
  end_time: number;         // Unix timestamp (ms)
}

WebSearch:

type SearchParams = {
  query: string;              // Min 2 chars
  search_type?: "Web" | "Images" | "Videos";
  allowed_domains?: string[];
  blocked_domains?: string[];
  safesearch?: "Strict" | "Moderate" | "Off";
  spellcheck?: boolean;
}

Other Tools

ExitPlanMode Tool:

type ExitPlanModeParams = {
  plan: string;  // The plan for user approval
}

Task Tool (Sub-Agent Delegation):

type TaskParams = {
  prompt: string;           // Task description for sub-agent
  subagent_type: string;    // Agent type to use
  description: string;      // Short task description
}

Advanced Features

Continuous Conversations

Multi-turn conversations maintain context within a session:

const session = await mix.sessions.create({
  title: "Multi-turn Chat"
});

// Turn 1
await mix.messages.send({
  id: session.id,
  requestBody: { text: "What is TypeScript?" }
});

// Turn 2 - maintains context from Turn 1
await mix.messages.send({
  id: session.id,
  requestBody: { text: "Show me an example" }
});

Session Forking

Create a new session branching from an existing conversation at any message:

// Fork at message index 5
const forkedSession = await mix.sessions.fork({
  id: sessionId,
  requestBody: { messageIndex: 5 }
});

// Forked session contains messages 0-5 from original
// Can now explore alternative conversation paths

Session Rewinding

Delete messages after a specific point in the conversation:

await mix.sessions.rewindSession({
  id: sessionId,
  requestBody: {
    messageIndex: 3,    // Delete messages after index 3
    cleanMedia: true    // Delete orphaned media files
  }
});

File Management with Thumbnails

Upload files and generate thumbnails for images/videos:

// Upload file
const file = await mix.files.upload({
  id: sessionId,
  requestBody: { file: fileBlob }
});

// Get thumbnail (images/videos only)
const thumbnail = await mix.files.get({
  id: sessionId,
  filename: file.filename,
  thumb: true  // Generates thumbnail on-the-fly
});

Dual-Agent Configuration

Configure separate models for main agent and sub-agents:

await mix.preferences.update({
  preferred_provider: "anthropic",
  main_agent_model: "claude-sonnet-4-5",
  sub_agent_model: "claude-3-5-haiku-20241022"  // Faster for subtasks
});

Debug Logging

Enable debug logging for SDK operations:

const mix = new Mix({
  debugLogger: console  // Logs all HTTP requests/responses
});

// Or via environment variable
// MIX_DEBUG=true

Low-Level SSE Streaming (CQRS Pattern)

Separate command (send) and query (stream) for advanced control:

// Establish stream first
const stream = await mix.streaming.streamEvents({
  sessionId: session.id
});

// Allow connection to establish
await new Promise(resolve => setTimeout(resolve, 500));

// Send command in parallel with query
const sendPromise = mix.messages.send({
  id: session.id,
  requestBody: { text: "Your message" }
});

// Process query stream
for await (const event of stream.result) {
  if (event.event === "complete") {
    await sendPromise;  // Wait for command to complete
    break;
  }
}

Streaming Events

const stream = await mix.streaming.streamEvents({
  sessionId: session.id
});

for await (const event of stream.result) {
  switch (event.event) {
    case "content":
      process.stdout.write(event.data.content);
      break;
    case "tool_execution_start":
      console.log(`🔧 ${event.data.toolName}`);
      break;
    case "complete":
      console.log("\n✓ Done");
      break;
  }
}

Error Handling

import * as errors from "mix-typescript-sdk/models/errors";

try {
  await mix.sessions.create({ title: "Test" });
} catch (error) {
  if (error instanceof errors.MixError) {
    console.log(`HTTP ${error.statusCode}: ${error.message}`);
  } else if (error instanceof errors.ConnectionError) {
    console.log("Network error");
  }
}

Retry Configuration

Per-Operation:

await mix.sessions.list({}, {
  retries: {
    strategy: "backoff",
    backoff: {
      initialInterval: 1000,
      maxInterval: 50000,
      exponent: 1.5,
      maxElapsedTime: 100000
    }
  }
});

SDK-Wide:

const mix = new Mix({
  retryConfig: {
    strategy: "backoff",
    backoff: { /* config */ }
  }
});

Custom HTTP Client

import { HTTPClient } from "mix-typescript-sdk/lib/http";

const httpClient = new HTTPClient();

httpClient.addHook("beforeRequest", (request) => {
  const nextRequest = new Request(request);
  nextRequest.headers.set("Authorization", `Bearer ${token}`);
  return nextRequest;
});

const mix = new Mix({ httpClient });

Example Usage

Complete Session Flow

import { Mix } from 'mix-typescript-sdk';

const mix = new Mix({ serverURL: 'http://localhost:8088' });

// Create session
const session = await mix.sessions.create({
  title: "Data Analysis"
});

// Stream events
const stream = await mix.streaming.streamEvents({
  sessionId: session.id
});

// Send message
await mix.messages.send({
  id: session.id,
  requestBody: { text: "Analyze this dataset" }
});

// Process events
for await (const event of stream) {
  if (event.data.type === "content") {
    console.log(event.data.content);
  }
}

File Upload & Analysis

import { openAsBlob } from "node:fs";

// Upload file
const file = await mix.files.upload({
  id: sessionId,
  requestBody: {
    file: await openAsBlob("data.csv")
  }
});

// Analyze with message
await mix.messages.send({
  id: sessionId,
  requestBody: {
    text: "Analyze the uploaded CSV file"
  }
});

Authentication Flow

// API Key
await mix.authentication.storeApiKey({
  apiKey: process.env.OPENAI_API_KEY,
  provider: "openai"
});

// OAuth
const url = await mix.authentication.startOAuthFlow({
  provider: "anthropic"
});
console.log("Visit:", url);

// After callback
await mix.authentication.handleOAuthCallback({
  code: callbackCode,
  state: callbackState,
  provider: "anthropic"
});

// Check status
const status = await mix.authentication.getAuthStatus();

Session Management

// List sessions
const sessions = await mix.sessions.list();

// Fork at message index
const forked = await mix.sessions.fork({
  id: sessionId,
  requestBody: { messageIndex: 5 }
});

// Rewind session
await mix.sessions.rewindSession({
  id: sessionId,
  requestBody: {
    messageIndex: 3,
    cleanMedia: true
  }
});

// Export session
const transcript = await mix.sessions.exportSession({
  id: sessionId
});