Skip to main content

Session

The Session class manages multi-turn conversations with Claude. It matches the official Claude Agent SDK V2 interface.

Creating Sessions

Sessions are created via the client. Connection happens automatically on first send().
import { ChuckyClient, getAssistantText } from '@chucky.cloud/sdk';

const client = new ChuckyClient({ token });

const session = client.createSession({
  model: 'claude-sonnet-4-5-20250929',
  systemPrompt: 'You are a helpful assistant.',
});

Methods

send()

Send a message to Claude. Returns a Promise that resolves when the message is sent. Use stream() to receive the response. Supports both text-only messages and multimodal content (text + images + documents).
async send(message: string | ContentBlock[]): Promise<void>

Text Message

await session.send('What is the capital of France?');

for await (const msg of session.stream()) {
  if (msg.type === 'assistant') {
    console.log(getAssistantText(msg));
  }
  if (msg.type === 'result') {
    console.log('Done:', msg.result);
  }
}

With Image

// Send an image with a question
await session.send([
  { type: 'text', text: 'What is in this image?' },
  {
    type: 'image',
    source: {
      type: 'base64',
      media_type: 'image/png',
      data: 'iVBORw0KGgoAAAANSUhEUgAA...' // base64-encoded image
    }
  }
]);

for await (const msg of session.stream()) {
  if (msg.type === 'assistant') {
    console.log(getAssistantText(msg));
  }
}

With Document (PDF)

// Send a PDF for analysis
await session.send([
  { type: 'text', text: 'Summarize this document' },
  {
    type: 'document',
    source: {
      type: 'base64',
      media_type: 'application/pdf',
      data: 'JVBERi0xLjQKJeLj...' // base64-encoded PDF
    }
  }
]);

for await (const msg of session.stream()) {
  if (msg.type === 'assistant') {
    console.log(getAssistantText(msg));
  }
}

Multiple Attachments

// Combine text, images, and documents
await session.send([
  { type: 'text', text: 'Compare these two documents and explain the differences' },
  { type: 'document', source: { type: 'base64', media_type: 'application/pdf', data: doc1Base64 } },
  { type: 'document', source: { type: 'base64', media_type: 'application/pdf', data: doc2Base64 } }
]);

stream()

Stream the response after sending a message. Returns an async generator that yields SDK messages.
async *stream(): AsyncGenerator<SDKMessage, void, unknown>

SDKMessage Types

TypeDescription
systemSystem initialization message with session info
assistantClaude’s response with content blocks
resultFinal result with cost and usage info
stream_eventPartial streaming events

Example

await session.send('Tell me a story');

for await (const msg of session.stream()) {
  switch (msg.type) {
    case 'system':
      console.log('Session:', msg.session_id);
      console.log('Model:', msg.model);
      break;
    case 'assistant':
      const text = getAssistantText(msg);
      if (text) process.stdout.write(text);
      break;
    case 'result':
      if (msg.subtype === 'success') {
        console.log('\n\nFinal:', msg.result);
        console.log('Cost:', msg.total_cost_usd);
      }
      break;
  }
}

receive()

Alias for stream() for V2 compatibility.
receive(): AsyncGenerator<SDKMessage, void, unknown>

close()

Close the session and release resources.
close(): void

Example

try {
  await session.send('Hello');
  for await (const msg of session.stream()) {
    // handle messages
  }
} finally {
  session.close();
}

on()

Register event handlers.
on(handlers: SessionEventHandlers): this

SessionEventHandlers

HandlerParametersDescription
onSessionInfo(info: SessionInfo)Session initialized
onError(error: Error)Error occurred

Example

session.on({
  onSessionInfo: (info) => {
    console.log('Session started:', info.sessionId);
    console.log('Model:', info.model);
  },
  onError: (error) => {
    showError(error.message);
  },
});

Properties

state

Current session state.
get state(): SessionState
type SessionState =
  | 'idle'           // Created, not connected
  | 'initializing'   // Connecting
  | 'ready'          // Ready for messages
  | 'processing'     // Waiting for response
  | 'waiting_tool'   // Waiting for tool result
  | 'completed'      // Session finished
  | 'error';         // Error state

sessionId

The session’s unique identifier.
get sessionId(): string

Helper Functions

getAssistantText()

Extract text content from an assistant message.
import { getAssistantText } from '@chucky.cloud/sdk';

function getAssistantText(msg: SDKMessage): string | null

Example

for await (const msg of session.stream()) {
  if (msg.type === 'assistant') {
    const text = getAssistantText(msg);
    console.log(text);
  }
}

getResultText()

Extract the result text from a result message.
import { getResultText } from '@chucky.cloud/sdk';

function getResultText(msg: SDKMessage): string | null

SDK Message Types

SDKAssistantMessage

interface SDKAssistantMessage {
  type: 'assistant';
  uuid: string;
  session_id: string;
  message: {
    role: 'assistant';
    content: ContentBlock[];
  };
  parent_tool_use_id: string | null;
}

SDKResultMessage

interface SDKResultMessageSuccess {
  type: 'result';
  subtype: 'success';
  uuid: string;
  session_id: string;
  duration_ms: number;
  duration_api_ms: number;
  is_error: boolean;
  num_turns: number;
  result: string;
  total_cost_usd: number;
  usage: {
    input_tokens: number;
    output_tokens: number;
    cache_creation_input_tokens: number;
    cache_read_input_tokens: number;
  };
}

SDKSystemMessage

interface SDKSystemMessageInit {
  type: 'system';
  subtype: 'init';
  uuid: string;
  session_id: string;
  cwd: string;
  tools: string[];
  mcp_servers: Array<{ name: string; status: string }>;
  model: string;
  permissionMode: string;
}

Usage Patterns

Basic Conversation

const client = new ChuckyClient({ token });
const session = client.createSession();

// First turn
await session.send('Hi, my name is Alice');
for await (const msg of session.stream()) {
  if (msg.type === 'assistant') {
    console.log(getAssistantText(msg));
  }
}

// Second turn (Claude remembers context)
await session.send('What is my name?');
for await (const msg of session.stream()) {
  if (msg.type === 'assistant') {
    console.log(getAssistantText(msg)); // "Your name is Alice."
  }
}

session.close();

Resuming Sessions

// Get session ID from previous session
const savedSessionId = localStorage.getItem('sessionId');

if (savedSessionId) {
  const session = client.resumeSession(savedSessionId);
  await session.send('Continue our conversation');
  for await (const msg of session.stream()) {
    // handle messages
  }
} else {
  const session = client.createSession();
  // Save session ID after first message
  await session.send('Hello');
  for await (const msg of session.stream()) {
    if (msg.type === 'system') {
      localStorage.setItem('sessionId', msg.session_id);
    }
  }
}

Error Handling

const session = client.createSession();

try {
  await session.send('Complex query...');

  for await (const msg of session.stream()) {
    if (msg.type === 'result') {
      if (msg.subtype === 'success') {
        console.log('Result:', msg.result);
      } else {
        console.error('Error:', msg.errors);
      }
    }
  }
} catch (error) {
  if (error instanceof BudgetExceededError) {
    showUpgradePrompt();
  } else {
    showGenericError(error);
  }
} finally {
  session.close();
}

Using await using (TypeScript 5.2+)

{
  await using session = client.createSession();

  await session.send('Hello');
  for await (const msg of session.stream()) {
    // handle messages
  }
} // session.close() called automatically