Complete guide to using sessions for stateful, multi-call interactions.
Quick Start
CLI
1# Start a new session2infsh app run my-app --session new --input '{"key": "value"}'3# Output includes session_id: sess_abc12345# Continue the session6infsh app run my-app --session sess_abc123 --input '{"key": "value2"}'78# End the session9infsh session end sess_abc123Python SDK
1from inferencesh import Inference23client = Inference(api_key="...")45# Start session6result = client.run({7 "app": "my-app@abc123",8 "input": {"action": "init"},9 "session": "new"10})11session_id = result["session_id"]1213# Continue session14result = client.run({15 "app": "my-app@abc123",16 "input": {"action": "process"},17 "session": session_id18})1920# End session21client.sessions.end(session_id)JavaScript SDK
1import { Inference } from '@anthropic/inference-sdk';23const client = new Inference({ apiKey: '...' });45// Start session6const result = await client.run({7 app: 'my-app@abc123',8 input: { action: 'init' },9 session: 'new'10});11const sessionId = result.session_id;1213// Continue session14await client.run({15 app: 'my-app@abc123',16 input: { action: 'process' },17 session: sessionId18});1920// End session21await client.sessions.end(sessionId);Session Parameters
The session and session_timeout parameters control session behavior:
session
| Value | Behavior |
|---|---|
"new" | Create a new session; returns session_id in response |
"sess_xxx" | Use existing session; must match app and version |
| omitted | Regular stateless call |
session_timeout
Custom idle timeout in seconds. Only valid when session: "new".
| Constraint | Value |
|---|---|
| Minimum | 1 second |
| Maximum | 3600 seconds (1 hour) |
| Default | 60 seconds |
1# Python: 5-minute session timeout2result = client.run({3 "app": "my-app",4 "input": {...},5 "session": "new",6 "session_timeout": 3007})1// JavaScript: 5-minute session timeout2const result = await client.run({3 app: 'my-app',4 input: {...},5 session: 'new',6 session_timeout: 3007});1# CLI: 5-minute session timeout2infsh app run my-app --session new --session-timeout 300 --input '{...}'Session Management
Get Session Info
1# Python2info = client.sessions.get(session_id)3print(info.status) # "active", "ended", or "expired"4print(info.expires_at) # When session will expire5print(info.call_count) # Number of calls made1// JavaScript2const info = await client.sessions.get(sessionId);3console.log(info.status); // "active", "ended", or "expired"4console.log(info.expiresAt); // When session will expire5console.log(info.callCount); // Number of calls madeList Sessions
1# Python2sessions = client.sessions.list()3for s in sessions:4 print(f"{s.id}: {s.status}")1// JavaScript2const sessions = await client.sessions.list();3sessions.forEach(s => console.log(`${s.id}: ${s.status}`));Keep Session Alive
Extend the expiration time without making a task call:
1# Python2info = client.sessions.keepalive(session_id)3print(info.expires_at) # Updated expiration1// JavaScript2const info = await client.sessions.keepalive(sessionId);3console.log(info.expiresAt); // Updated expirationEnd Session
Release the worker immediately:
1# Python2client.sessions.end(session_id)1// JavaScript2await client.sessions.end(sessionId);State Guarantees
What Persists
- In-memory state — Python objects, loaded models, variables
- File system changes — Files written to local storage
- Database connections — Open connections remain open
What Doesn't Persist
- Cross-session state — Each session starts fresh
- After expiration — State is lost when session ends
- Across restarts — Worker restarts clear all state
Example: Stateful App
1class App(BaseApp):2 def __init__(self):3 self.state = {} # Persists within session45 async def set_value(self, input: SetInput) -> SetOutput:6 self.state[input.key] = input.value7 return SetOutput(success=True)89 async def get_value(self, input: GetInput) -> GetOutput:10 value = self.state.get(input.key)11 return GetOutput(value=value, found=value is not None)Timeouts and Expiration
Default Timeout
Sessions expire after 60 seconds of idle time (no calls) by default.
Custom Timeout
Specify session_timeout when creating a session to customize the idle timeout:
1# Create session with 10-minute idle timeout2result = client.run({3 "app": "my-app",4 "input": {...},5 "session": "new",6 "session_timeout": 600 # 10 minutes7})| Timeout Range | Description |
|---|---|
| 1-59 seconds | Short-lived sessions for quick interactions |
| 60 seconds | Default timeout |
| 60-300 seconds | Standard interactive sessions |
| 300-3600 seconds | Long-running workflows, background processing |
Sliding Window
Each call resets the expiration timer to the session's configured timeout:
1# With default 60-second timeout:2Call 1 (t=0) → Expires at t=60s3Call 2 (t=30s) → Expires at t=90s4Call 3 (t=80s) → Expires at t=140s56# With custom 5-minute (300s) timeout:7Call 1 (t=0) → Expires at t=5min8Call 2 (t=2min) → Expires at t=7min9Call 3 (t=6min) → Expires at t=11minMaximum Timeout
The maximum allowed session timeout is 1 hour (3600 seconds).
Keepalive
Use keepalive to extend the session without making a task call. This resets the timer using the session's configured timeout:
1# Extend session periodically2while work_in_progress:3 client.sessions.keepalive(session_id)4 time.sleep(session_timeout * 0.8) # Keep alive at 80% of timeoutError Handling
Session Errors
| Error Code | HTTP Status | Description |
|---|---|---|
SESSION_NOT_FOUND | 404 | Session ID doesn't exist |
SESSION_EXPIRED | 410 | Session timed out |
SESSION_ENDED | 410 | Session was explicitly ended |
WORKER_LEASED | 409 | Worker assigned to different session |
APP_MISMATCH | 400 | Session belongs to different app |
VERSION_MISMATCH | 400 | Session belongs to different version |
Python Error Handling
1from inferencesh import (2 SessionNotFoundError,3 SessionExpiredError,4 SessionEndedError,5)67try:8 result = client.run({9 "app": "my-app",10 "input": {...},11 "session": session_id12 })13except SessionNotFoundError:14 # Session doesn't exist — create new one15 result = client.run({...}, session="new")16except SessionExpiredError:17 # Session timed out — create new one18 result = client.run({...}, session="new")19except SessionEndedError:20 # Session was ended — create new one21 result = client.run({...}, session="new")JavaScript Error Handling
1import {2 SessionNotFoundError,3 SessionExpiredError,4 SessionEndedError5} from '@anthropic/inference-sdk';67try {8 const result = await client.run({9 app: 'my-app',10 input: {...},11 session: sessionId12 });13} catch (error) {14 if (error instanceof SessionNotFoundError ||15 error instanceof SessionExpiredError ||16 error instanceof SessionEndedError) {17 // Create new session18 const result = await client.run({...}, { session: 'new' });19 }20 throw error;21}Best Practices
Always End Sessions
Release workers when done:
1try:2 # Use session3 result = client.run({..., "session": session_id})4finally:5 client.sessions.end(session_id)Handle Expiration Gracefully
Sessions can expire unexpectedly. Always handle SESSION_EXPIRED:
1def call_with_retry(client, params, session_id):2 try:3 return client.run({**params, "session": session_id})4 except SessionExpiredError:5 # Recreate session and retry6 result = client.run({**params, "session": "new"})7 return result, result["session_id"]Use Context Managers (Python)
1with client.session("my-app@abc123") as session:2 session.call({"action": "init"})3 session.call({"action": "process"})4 # Session automatically ended on exitPin Versions
Sessions are bound to a specific app version:
1# Good: Version pinned2client.run({"app": "my-app@abc123", "session": session_id, ...})34# Bad: Version might change5client.run({"app": "my-app", "session": session_id, ...})Next
- Sessions Concept — Overview and use cases
- Stateful Sessions Examples — Practical patterns
- Multi-Function Apps — Combine with multiple entry points