248 lines
7.8 KiB
Markdown
248 lines
7.8 KiB
Markdown
# Session Management
|
|
|
|
> Understanding how the Claude Agent SDK handles sessions and session resumption
|
|
|
|
## Session Management
|
|
|
|
The Claude Agent SDK provides session management capabilities for handling conversation state and resumption. Sessions allow you to continue conversations across multiple interactions while maintaining full context.
|
|
|
|
## How Sessions Work
|
|
|
|
When you start a new query, the SDK automatically creates a session and returns a session ID in the initial system message. You can capture this ID to resume the session later.
|
|
|
|
### Getting the Session ID
|
|
|
|
options: { options: {
|
|
model: "claude-sonnet-4-5"
|
|
}
|
|
})
|
|
|
|
for await (const message of response) {
|
|
// The first message is a system init message with the session ID
|
|
|
|
```python
|
|
if (message.type === 'system' && message.subtype === 'init') { if (message.type === 'system' && message.subtype === 'init') {
|
|
sessionId = message.session_id
|
|
console.log(`Session started with ID: ${sessionId}`)
|
|
// You can save this ID for later resumption
|
|
}
|
|
|
|
```
|
|
|
|
// Process other messages... // Process other messages...
|
|
console.log(message)
|
|
}
|
|
|
|
// Later, you can use the saved sessionId to resume
|
|
if (sessionId) {
|
|
const resumedResponse = query({
|
|
|
|
```python
|
|
prompt: "Continue where we left off",
|
|
options: {
|
|
resume: sessionId
|
|
}
|
|
})
|
|
}
|
|
```
|
|
|
|
```python Python theme={null}
|
|
from claude_agent_sdk import query, ClaudeAgentOptions
|
|
|
|
session_id = None
|
|
|
|
async for message in query(
|
|
prompt="Help me build a web application",
|
|
```
|
|
|
|
```python
|
|
options=ClaudeAgentOptions( options=ClaudeAgentOptions(
|
|
model="claude-sonnet-4-5"
|
|
)
|
|
):
|
|
|
|
## The first message is a system init message with the session ID
|
|
```
|
|
|
|
```python
|
|
if hasattr(message, 'subtype') and message.subtype == 'init': if hasattr(message, 'subtype') and message.subtype == 'init':
|
|
session_id = message.data.get('session_id')
|
|
print(f"Session started with ID: {session_id}")
|
|
|
|
# You can save this ID for later resumption
|
|
|
|
```
|
|
|
|
## Process other messages... # Process other messages
|
|
|
|
print(message)
|
|
|
|
## Later, you can use the saved session_id to resume
|
|
|
|
if session_id:
|
|
async for message in query(
|
|
|
|
```python
|
|
prompt="Continue where we left off", prompt="Continue where we left off",
|
|
options=ClaudeAgentOptions(
|
|
resume=session_id
|
|
)
|
|
):
|
|
print(message)
|
|
```
|
|
|
|
## Resuming Sessions
|
|
|
|
The SDK supports resuming sessions from previous conversation states, enabling continuous development workflows. Use the `resume` option with a session ID to continue a previous conversation.
|
|
|
|
options: { options: {
|
|
resume: "session-xyz", // Session ID from previous conversation
|
|
model: "claude-sonnet-4-5",
|
|
allowedTools: ["Read", "Edit", "Write", "Glob", "Grep", "Bash"]
|
|
}
|
|
})
|
|
|
|
// The conversation continues with full context from the previous session
|
|
for await (const message of response) {
|
|
console.log(message)
|
|
}
|
|
|
|
```
|
|
|
|
```python Python theme={null}
|
|
from claude_agent_sdk import query, ClaudeAgentOptions
|
|
|
|
## Resume a previous session using its ID
|
|
|
|
async for message in query(
|
|
prompt="Continue implementing the authentication system from where we left off",
|
|
```
|
|
|
|
```python
|
|
options=ClaudeAgentOptions( options=ClaudeAgentOptions(
|
|
resume="session-xyz", # Session ID from previous conversation
|
|
model="claude-sonnet-4-5",
|
|
allowed_tools=["Read", "Edit", "Write", "Glob", "Grep", "Bash"]
|
|
)
|
|
):
|
|
print(message)
|
|
|
|
## The conversation continues with full context from the previous session
|
|
```
|
|
|
|
The SDK automatically handles loading the conversation history and context when you resume a session, allowing Claude to continue exactly where it left off.
|
|
|
|
## Forking Sessions
|
|
|
|
When resuming a session, you can choose to either continue the original session or fork it into a new branch. By default, resuming continues the original session. Use the `forkSession` option (TypeScript) or `fork_session` option (Python) to create a new session ID that starts from the resumed state.
|
|
|
|
### When to Fork a Session
|
|
|
|
Forking is useful when you want to:
|
|
|
|
* Explore different approaches from the same starting point
|
|
* Create multiple conversation branches without modifying the original
|
|
* Test changes without affecting the original session history
|
|
* Maintain separate conversation paths for different experiments
|
|
|
|
### Forking vs Continuing
|
|
|
|
| Behavior | `forkSession: false` (default) | `forkSession: true` |
|
|
| -------------------- | ------------------------------ | ------------------------------------ |
|
|
| **Session ID** | Same as original | New session ID generated |
|
|
| **History** | Appends to original session | Creates new branch from resume point |
|
|
| **Original Session** | Modified | Preserved unchanged |
|
|
| **Use Case** | Continue linear conversation | Branch to explore alternatives |
|
|
|
|
### Example: Forking a Session
|
|
|
|
options: { model: "claude-sonnet-4-5" } options: { model: "claude-sonnet-4-5" }
|
|
})
|
|
|
|
for await (const message of response) {
|
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
|
|
```python
|
|
sessionId = message.session_id sessionId = message.session_id
|
|
console.log(`Original session: ${sessionId}`)
|
|
}
|
|
|
|
// Fork the session to try a different approach
|
|
const forkedResponse = query({
|
|
prompt: "Now let's redesign this as a GraphQL API instead",
|
|
```python
|
|
options: { options: {
|
|
resume: sessionId,
|
|
forkSession: true, // Creates a new session ID
|
|
model: "claude-sonnet-4-5"
|
|
}
|
|
})
|
|
|
|
for await (const message of forkedResponse) {
|
|
if (message.type === 'system' && message.subtype === 'init') {
|
|
```python
|
|
console.log(`Forked session: ${message.session_id}`) console.log(`Forked session: ${message.session_id}`)
|
|
// This will be a different session ID
|
|
}
|
|
|
|
// The original session remains unchanged and can still be resumed
|
|
const originalContinued = query({
|
|
prompt: "Add authentication to the REST API",
|
|
```python
|
|
options: { options: {
|
|
resume: sessionId,
|
|
forkSession: false, // Continue original session (default)
|
|
model: "claude-sonnet-4-5"
|
|
}
|
|
})
|
|
```
|
|
|
|
```python Python theme={null}
|
|
from claude_agent_sdk import query, ClaudeAgentOptions
|
|
|
|
## First, capture the session ID
|
|
|
|
session_id = None
|
|
|
|
async for message in query(
|
|
prompt="Help me design a REST API",
|
|
```python
|
|
options=ClaudeAgentOptions(model="claude-sonnet-4-5") options=ClaudeAgentOptions(model="claude-sonnet-4-5")
|
|
):
|
|
if hasattr(message, 'subtype') and message.subtype == 'init':
|
|
```python
|
|
session_id = message.data.get('session_id') session_id = message.data.get('session_id')
|
|
print(f"Original session: {session_id}")
|
|
|
|
## Fork the session to try a different approach
|
|
|
|
async for message in query(
|
|
prompt="Now let's redesign this as a GraphQL API instead",
|
|
```python
|
|
options=ClaudeAgentOptions( options=ClaudeAgentOptions(
|
|
resume=session_id,
|
|
fork_session=True, # Creates a new session ID
|
|
model="claude-sonnet-4-5"
|
|
)
|
|
):
|
|
if hasattr(message, 'subtype') and message.subtype == 'init':
|
|
```python
|
|
forked_id = message.data.get('session_id') forked_id = message.data.get('session_id')
|
|
print(f"Forked session: {forked_id}")
|
|
|
|
## This will be a different session ID
|
|
|
|
## The original session remains unchanged and can still be resumed
|
|
|
|
async for message in query(
|
|
prompt="Add authentication to the REST API",
|
|
```python
|
|
options=ClaudeAgentOptions( options=ClaudeAgentOptions(
|
|
resume=session_id,
|
|
fork_session=False, # Continue original session (default)
|
|
model="claude-sonnet-4-5"
|
|
)
|
|
):
|
|
print(message)
|
|
```
|