TypeScript V2 session API (removed)
Reference for the experimental unstable_v2 session API removed in TypeScript Agent SDK 0.3.142, and how to migrate code that still uses it.
The V2 session API was an experimental, simpler way to hold multi-turn conversations in the TypeScript Agent SDK. Instead of feeding query() an async generator, you created a session object, called send() for each turn and stream() to read the reply.
Warning: V2 is gone. TypeScript Agent SDK 0.3.142 removed
unstable_v2_createSession,unstable_v2_resumeSession,unstable_v2_promptand theSDKSessionandSDKSessionOptionstypes. New code should usequery()with anAsyncIterable<SDKUserMessage>for multi-turn work, oroptions.resumeto continue a saved session. This page exists for anyone maintaining code pinned to 0.2.x or earlier.
Version boundary
The package went straight from 0.2.x to 0.3.142, so "0.2 is the last with V2" and "0.3.142 removed it" describe the same line. To stay on V2:
npm install @anthropic-ai/claude-agent-sdk@0.2
As with current versions, a native Claude Code binary for your platform ships as an optional dependency, so most installs need nothing else. The quickstart lists the exceptions.
The V2 surface
| Function or type | Signature | Purpose |
|---|---|---|
unstable_v2_prompt | (prompt: string, options: { model: string, ... }) => Promise<SDKResultMessage> | One-shot question, returns the result message |
unstable_v2_createSession | (options: { model: string, ... }) => SDKSession | Start a conversation |
unstable_v2_resumeSession | (sessionId: string, options: { model: string, ... }) => SDKSession | Continue a stored conversation |
SDKSession | interface | sessionId, send(), stream(), close() |
interface SDKSession {
readonly sessionId: string;
send(message: string | SDKUserMessage): Promise<void>;
stream(): AsyncGenerator<SDKMessage, void>;
close(): void;
}
model was required in every options object; other options were also accepted.
How V2 code looked
One-shot
import { unstable_v2_prompt } from "@anthropic-ai/claude-agent-sdk";
const res = await unstable_v2_prompt("Which HTTP status means 'too many requests'?", { model: "claude-sonnet-4-5" });
if (res.subtype === "success") console.log(res.result);
A conversation
Splitting send() from stream() made it easy to run your own logic between turns:
import { unstable_v2_createSession, type SDKMessage } from "@anthropic-ai/claude-agent-sdk";
const textOf = (m: SDKMessage) =>
m.type === "assistant"
? m.message.content.filter(b => b.type === "text").map(b => b.text).join("")
: null;
await using chat = unstable_v2_createSession({ model: "claude-sonnet-4-5" });
await chat.send("Suggest three names for a bookkeeping app.");
for await (const m of chat.stream()) { const t = textOf(m); if (t) console.log(t); }
await chat.send("Make the second one sound less corporate.");
for await (const m of chat.stream()) { const t = textOf(m); if (t) console.log(t); }
await using (TypeScript 5.2+) closed the session automatically at the end of the block. On older compilers you called chat.close() yourself.
Resuming
Every streamed message carried session_id. Store it, close the session, and later:
await using again = unstable_v2_resumeSession(savedId, { model: "claude-sonnet-4-5" });
await again.send("Remind me which name we settled on.");
for await (const m of again.stream()) { /* ... */ }
What V2 never supported
- Session forking (the
forkSessionoption). - Some advanced streaming input patterns.
Both always needed the standard query() API.
Migrating to query()
| V2 | Current equivalent |
|---|---|
unstable_v2_prompt(p, opts) | query({ prompt: p, options: opts }), then read the result message |
createSession + repeated send() | query({ prompt: asyncIterableOfUserMessages, options }) |
resumeSession(id, opts) | query({ prompt, options: { ...opts, resume: id } }) |
session.close() | Finish iterating, or call close() / interrupt() on the query object |
session.sessionId | session_id on any message |
One-shot
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const m of query({ prompt: "Which HTTP status means 'too many requests'?", options: { model: "claude-sonnet-4-5" } })) {
if (m.type === "result" && m.subtype === "success") console.log(m.result);
}
Multi-turn with an input stream
The main change is that turns now come from an async iterable you control. A small queue makes it feel much like V2:
import { query, type SDKUserMessage } from "@anthropic-ai/claude-agent-sdk";
function userTurn(text: string): SDKUserMessage {
return { type: "user", session_id: "", parent_tool_use_id: null,
message: { role: "user", content: [{ type: "text", text }] } };
}
async function* turns() {
yield userTurn("Suggest three names for a bookkeeping app.");
// In a real app, await the next message from your UI here.
yield userTurn("Make the second one sound less corporate.");
}
for await (const m of query({ prompt: turns(), options: { model: "claude-sonnet-4-5" } })) {
if (m.type === "assistant") {
console.log(m.message.content.filter(b => b.type === "text").map(b => b.text).join(""));
}
}
Streaming vs single mode explains input streams in depth, and streamInput() on the query object adds turns to a running query.
Resume
for await (const m of query({ prompt: "Remind me which name we settled on.", options: { resume: savedId } })) { /* ... */ }
See sessions for resume, continue and fork.