Skip to main content
Chat sessions give you an interactive, multi-turn agent that stays alive between messages. Unlike runs (fire-and-forget batch jobs), a chat session keeps its sandbox running so the agent retains full context — files, environment, and conversation history — across every message you send.

Chat session lifecycle

  create ──→ active ──→ idle (snapshot) ──→ resumed ──→ active
                │                                        │
                └──→ ended (delete)    ←─────────────────┘
StatusDescription
activeSandbox is running, ready for messages
idleSandbox snapshotted after idle timeout, restorable on next message
endedSession terminated, sandbox destroyed

Step 1: Create a session

Endpoint
POST /agent/v1/chat
const chat = await client.agents.chat.create({
  title: 'Contract Review Session',
  model: 'anthropic/claude-sonnet-4.6',
  idleTimeoutMs: 300000, // 5 minutes
})

console.log(chat.id) // chat_xxx
console.log(chat.status) // "active"
Response
{
  "id": "chat_abc123",
  "status": "active",
  "idleTimeoutMs": 300000,
  "createdAt": "2026-03-03T21:23:18.434Z"
}

Create parameters

ParameterTypeRequiredDescription
titlestringnoHuman-readable session name
modelstringnoLLM model (default: anthropic/claude-sonnet-4.6)
idleTimeoutMsintegernoIdle time before snapshot eligibility (default: 15 min, min: 1 min, max: 24 hr)

Step 2: Send messages

Endpoint
POST /agent/v1/chat/:id/message
Messages are proxied to the agent running in the sandbox. The agent has the same full tool access as batch runs — vaults, legal research, OCR, web search, and the casedev CLI.
const response = await client.agents.chat.sendMessage(chat.id, {
  parts: [{ type: 'text', text: 'Search vault vault_abc for indemnification clauses.' }],
})
The response contains the agent’s output. Send follow-up messages to the same session — the agent retains full context from prior turns.
If the sandbox was snapshotted due to idle timeout, sending a message automatically restores it. There is a brief resume delay (~5-10s) but no context is lost.

Step 3: Stream events (optional)

Endpoint
GET /agent/v1/chat/:id/stream
Open an SSE connection to receive real-time events as the agent works. Events are buffered server-side, so you can reconnect without missing anything.
const stream = client.agents.chat.stream(chat.id)

for await (const event of stream) {
  console.log(event.type, event.data)
}

Replay from a sequence number

Each SSE event has a numeric id. Pass lastEventId to replay events after a given sequence — useful for reconnecting after a network drop:
# Replay events after sequence 42
curl -N "https://api.case.dev/agent/v1/chat/$CHAT_ID/stream?lastEventId=42" \
  -H "Authorization: Bearer $CASEDEV_API_KEY"
The Last-Event-ID HTTP header is also supported, following the SSE spec.
Events are buffered up to 500 per session. For long-running sessions with high event volume, connect the stream early to avoid gaps.

Cancel generation

Endpoint
POST /agent/v1/chat/:id/cancel
Abort the agent’s current generation without ending the session. The sandbox stays alive and you can send another message immediately.
const result = await client.agents.chat.cancel(chat.id)
console.log(result.ok) // true

End the session

Endpoint
DELETE /agent/v1/chat/:id
Snapshots the sandbox, terminates it, and marks the session as ended. The response includes runtime billing data.
const result = await client.agents.chat.delete(chat.id)
console.log(result.status)    // "ended"
console.log(result.runtimeMs) // 48230
console.log(result.cost)      // 0.00268
Response
{
  "id": "chat_abc123",
  "status": "ended",
  "snapshotImageId": "im-abc123",
  "runtimeMs": 48230,
  "cost": 0.00268
}
FieldTypeDescription
statusstringAlways "ended"
snapshotImageIdstringFinal sandbox snapshot (nullable)
runtimeMsintegerTotal sandbox uptime in milliseconds
costnumberRuntime cost in USD ($0.20/hr)
Sending a message to an ended session returns 409 Conflict. Create a new session to continue.

Idle timeout and snapshots

Chat sessions have a configurable idle timeout (default: 15 minutes). When no messages are sent within the timeout window:
  1. The sandbox is snapshotted (memory + filesystem persisted)
  2. The sandbox is terminated to stop billing
  3. The next message automatically restores the sandbox from the snapshot
This means you only pay for active compute time, not idle wait. A background reaper runs every 5 minutes to clean up idle sessions.

Runs vs. chat

RunsChat
PatternSingle prompt in, result outMulti-turn conversation
Sandbox lifetimeOne executionPersists across messages
StreamingPoll or webhookReal-time SSE
ContextFresh each runRetained across turns
BillingPer-executionPer-second of sandbox uptime
Best forBatch processing, scheduled tasksInteractive workflows, iterative analysis
Use runs for fire-and-forget batch tasks. Use chat when you need back-and-forth interaction with the agent or when the task requires iterative refinement.

Authentication

Chat endpoints require an API key with agent:read (for streaming) and agent:write (for create, message, cancel, delete) permissions. Session-based or OAuth authentication is not supported — all downstream token usage and billing is attributed to the API key’s organization.

Complete example

import Casedev from '@case.dev/sdk'

const client = new Casedev({ apiKey: process.env.CASEDEV_API_KEY })

// 1. Create a session
const chat = await client.agents.chat.create({
  title: 'Deposition Analysis',
  model: 'anthropic/claude-sonnet-4.6',
})

// 2. First message
await client.agents.chat.sendMessage(chat.id, {
  parts: [{ type: 'text', text: 'Search vault vault_depo for all witness testimony about the accident timeline.' }],
})

// 3. Follow-up based on results
await client.agents.chat.sendMessage(chat.id, {
  parts: [{ type: 'text', text: 'Now cross-reference that with the police report in vault vault_evidence.' }],
})

// 4. End session when done
const result = await client.agents.chat.delete(chat.id)
console.log(`Session cost: $${result.cost.toFixed(4)}`)