drop docs and bump version
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
## Added List Run Steps API
|
||||
|
||||
We've introduced a new API endpoint that allows you to list all steps associated with a specific run. This feature makes it easier to track and analyze the sequence of steps performed during a run.
|
||||
|
||||
<CodeBlocks>
|
||||
```python title="python"
|
||||
from letta_client import Letta
|
||||
client = Letta(
|
||||
token="YOUR_API_KEY",
|
||||
)
|
||||
steps = client.runs.list_run_steps(
|
||||
run_id="RUN_ID",
|
||||
)
|
||||
for step in steps:
|
||||
print(f"Step ID: {step.id}, Tokens: {step.total_tokens}")
|
||||
```
|
||||
```typescript title="node.js"
|
||||
import { LettaClient } from '@letta-ai/letta-client';
|
||||
const client = new LettaClient({
|
||||
token: "YOUR_API_KEY",
|
||||
});
|
||||
const steps = await client.runs.steps.list({
|
||||
run_id: "RUN_ID",
|
||||
});
|
||||
steps.forEach(step => {
|
||||
console.log(`Step ID: ${step.id}, Tokens: ${step.total_tokens}`);
|
||||
});
|
||||
```
|
||||
</CodeBlocks>
|
||||
@@ -1,602 +0,0 @@
|
||||
---
|
||||
title: Long-Running Executions
|
||||
slug: guides/agents/long-running
|
||||
subtitle: How to handle long-running agent executions
|
||||
---
|
||||
|
||||
When agents need to execute multiple tool calls or perform complex operations (like deep research, data analysis, or multi-step workflows), processing time can vary significantly.
|
||||
|
||||
Letta supports various ways to handle long-running agents, so you can choose the approach that best fits your use case:
|
||||
|
||||
| Use Case | Duration | Recommendedation | Key Benefits |
|
||||
|----------|----------|---------------------|-------------|
|
||||
| Few-step invocations | < 1 minute | [Standard streaming](/guides/agents/streaming) | Simplest approach |
|
||||
| Variable length runs | 1-10 minutes | **Background mode** (Keepalive + Timeout as a second choice) | Easy way to reduce timeouts |
|
||||
| Deep research | 10+ minutes | **Background mode**, or async polling | Survives disconnects, resumable streams |
|
||||
| Batch jobs | Any | **Async polling** | Fire-and-forget, check results later |
|
||||
|
||||
## Option 1: Background Mode with Resumable Streaming
|
||||
|
||||
<Note>
|
||||
**Best for:** Operations exceeding 10 minutes, unreliable network connections, or critical workflows that must complete regardless of client connectivity.
|
||||
|
||||
**Trade-off:** Slightly higher latency to first token due to background task initialization.
|
||||
</Note>
|
||||
|
||||
Background mode decouples agent execution from your client connection. The agent processes your request on the server while streaming results to a persistent store, allowing you to reconnect and resume from any point — even if your application crashes or network fails.
|
||||
|
||||
<CodeGroup>
|
||||
```curl curl maxLines=50
|
||||
curl --request POST \
|
||||
--url https://api.letta.com/v1/agents/$AGENT_ID/messages/stream \
|
||||
--header 'Authorization: Bearer $LETTA_API_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Run comprehensive analysis on this dataset"
|
||||
}
|
||||
],
|
||||
"stream_tokens": true,
|
||||
"background": true
|
||||
}'
|
||||
|
||||
# Response stream includes run_id and seq_id for each chunk:
|
||||
data: {"run_id":"run-123","seq_id":0,"message_type":"reasoning_message","reasoning":"Analyzing"}
|
||||
data: {"run_id":"run-123","seq_id":1,"message_type":"reasoning_message","reasoning":" the dataset"}
|
||||
data: {"run_id":"run-123","seq_id":2,"message_type":"tool_call","tool_call":{...}}
|
||||
# ... stream continues
|
||||
|
||||
# Step 2: If disconnected, resume from last received seq_id
|
||||
curl --request GET \
|
||||
--url https://api.letta.com/v1/runs/$RUN_ID/stream \
|
||||
--header 'Accept: text/event-stream' \
|
||||
--data '{
|
||||
"starting_after": 57
|
||||
}'
|
||||
```
|
||||
```python python maxLines=50
|
||||
stream = client.agents.messages.create_stream(
|
||||
agent_id=agent_state.id,
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Run comprehensive analysis on this dataset"
|
||||
}
|
||||
],
|
||||
stream_tokens=True,
|
||||
background=True,
|
||||
)
|
||||
run_id = None
|
||||
last_seq_id = None
|
||||
for chunk in stream:
|
||||
if hasattr(chunk, "run_id") and hasattr(chunk, "seq_id"):
|
||||
run_id = chunk.run_id # Save this to reconnect if your connection drops
|
||||
last_seq_id = chunk.seq_id # Save this as your resumption point for cursor-based pagination
|
||||
print(chunk)
|
||||
|
||||
# If disconnected, resume from last received seq_id:
|
||||
for chunk in client.runs.stream(run_id, starting_after=last_seq_id):
|
||||
print(chunk)
|
||||
```
|
||||
```typescript TypeScript maxLines=50
|
||||
const stream = await client.agents.messages.createStream({
|
||||
agentId: agentState.id,
|
||||
requestBody: {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: "Run comprehensive analysis on this dataset"
|
||||
}
|
||||
],
|
||||
streamTokens: true,
|
||||
background: true,
|
||||
}
|
||||
});
|
||||
|
||||
let runId = null;
|
||||
let lastSeqId = null;
|
||||
for await (const chunk of stream) {
|
||||
if (chunk.run_id && chunk.seq_id) {
|
||||
runId = chunk.run_id; // Save this to reconnect if your connection drops
|
||||
lastSeqId = chunk.seq_id; // Save this as your resumption point for cursor-based pagination
|
||||
}
|
||||
console.log(chunk);
|
||||
}
|
||||
|
||||
// If disconnected, resume from last received seq_id
|
||||
for await (const chunk of client.runs.stream(runId, {startingAfter: lastSeqId})) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
```python python maxLines=60
|
||||
# 1) Start background stream and capture approval request
|
||||
stream = client.agents.messages.create_stream(
|
||||
agent_id=agent.id,
|
||||
messages=[{"role": "user", "content": "Do a sensitive operation"}],
|
||||
stream_tokens=True,
|
||||
background=True,
|
||||
)
|
||||
|
||||
approval_request_id = None
|
||||
orig_run_id = None
|
||||
last_seq_id = 0
|
||||
for chunk in stream:
|
||||
if hasattr(chunk, "run_id") and hasattr(chunk, "seq_id"):
|
||||
orig_run_id = chunk.run_id
|
||||
last_seq_id = chunk.seq_id
|
||||
if getattr(chunk, "message_type", None) == "approval_request_message":
|
||||
approval_request_id = chunk.id
|
||||
break
|
||||
|
||||
# 2) Approve in background; capture the approval stream cursor (this creates a new run)
|
||||
approve = client.agents.messages.create_stream(
|
||||
agent_id=agent.id,
|
||||
messages=[{"type": "approval", "approve": True, "approval_request_id": approval_request_id}],
|
||||
stream_tokens=True,
|
||||
background=True,
|
||||
)
|
||||
|
||||
run_id = None
|
||||
approve_seq = 0
|
||||
for chunk in approve:
|
||||
if hasattr(chunk, "run_id") and hasattr(chunk, "seq_id"):
|
||||
run_id = chunk.run_id
|
||||
approve_seq = chunk.seq_id
|
||||
if getattr(chunk, "message_type", None) == "tool_return_message":
|
||||
# Tool result arrives here on the approval stream
|
||||
break
|
||||
|
||||
# 3) Resume that run to read follow-up tokens
|
||||
for chunk in client.runs.stream(run_id, starting_after=approve_seq):
|
||||
print(chunk)
|
||||
```
|
||||
```typescript TypeScript maxLines=60
|
||||
// 1) Start background stream and capture approval request
|
||||
const stream = await client.agents.messages.createStream(
|
||||
agent.id, {
|
||||
messages: [{role: "user", content: "Do a sensitive operation"}],
|
||||
streamTokens: true,
|
||||
background: true,
|
||||
}
|
||||
);
|
||||
|
||||
let approvalRequestId = null;
|
||||
let origRunId = null;
|
||||
let lastSeqId = 0;
|
||||
for await (const chunk of stream) {
|
||||
if (chunk.runId && chunk.seqId) {
|
||||
origRunId = chunk.runId;
|
||||
lastSeqId = chunk.seqId;
|
||||
}
|
||||
if (chunk.messageType === "approval_request_message") {
|
||||
approvalRequestId = chunk.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Approve in background; capture the approval stream cursor (this creates a new run)
|
||||
const approveStream = await client.agents.messages.createStream(
|
||||
agent.id, {
|
||||
messages: [{type: "approval", approve: true, approvalRequestId}],
|
||||
streamTokens: true,
|
||||
background: true,
|
||||
}
|
||||
);
|
||||
|
||||
let runId = null;
|
||||
let approveSeq = 0;
|
||||
for await (const chunk of approveStream) {
|
||||
if (chunk.runId && chunk.seqId) {
|
||||
runId = chunk.runId;
|
||||
approveSeq = chunk.seqId;
|
||||
}
|
||||
if (chunk.messageType === "tool_return_message") {
|
||||
// Tool result arrives here on the approval stream
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Resume that run to read follow-up tokens
|
||||
for await (const chunk of client.runs.stream(runId, {startingAfter: approveSeq})) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### HITL in Background Mode
|
||||
|
||||
When [Human‑in‑the‑Loop (HITL) approval](/guides/agents/human-in-the-loop) is enabled for a tool, your background stream may pause and emit an `approval_request_message`. In background mode, send the approval via a separate background stream and capture that stream’s `run_id`/`seq_id`.
|
||||
|
||||
<Note>
|
||||
Approval responses in background mode emit the `tool_return_message` on the approval stream itself (with a new `run_id`, different from the original stream). Save the approval stream cursor, then resume with `runs.stream` to consume subsequent reasoning/assistant messages.
|
||||
</Note>
|
||||
|
||||
<CodeGroup>
|
||||
```curl curl maxLines=70
|
||||
# 1) Start background stream; capture approval request
|
||||
curl --request POST \
|
||||
--url https://api.letta.com/v1/agents/$AGENT_ID/messages/stream \
|
||||
--header 'Authorization: Bearer $LETTA_API_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"messages": [{"role": "user", "content": "Do a sensitive operation"}],
|
||||
"stream_tokens": true,
|
||||
"background": true
|
||||
}'
|
||||
|
||||
# Example stream output (approval request arrives):
|
||||
data: {"run_id":"run-abc","seq_id":0,"message_type":"reasoning_message","reasoning":"..."}
|
||||
data: {"run_id":"run-abc","seq_id":1,"message_type":"approval_request_message","id":"message-abc","tool_call":{"name":"sensitive_operation","arguments":"{...}","tool_call_id":"tool-xyz"}}
|
||||
|
||||
# 2) Approve in background; capture approval stream cursor (this creates a new run)
|
||||
curl --request POST \
|
||||
--url https://api.letta.com/v1/agents/$AGENT_ID/messages/stream \
|
||||
--header 'Authorization: Bearer $LETTA_API_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"messages": [{"type": "approval", "approve": true, "approval_request_id": "message-abc"}],
|
||||
"stream_tokens": true,
|
||||
"background": true
|
||||
}'
|
||||
|
||||
# Example approval stream output (tool result arrives here):
|
||||
data: {"run_id":"run-new","seq_id":0,"message_type":"tool_return_message","status":"success","tool_return":"..."}
|
||||
|
||||
# 3) Resume the approval stream's run to continue
|
||||
curl --request GET \
|
||||
--url https://api.letta.com/v1/runs/$RUN_ID/stream \
|
||||
--header 'Accept: text/event-stream' \
|
||||
--data '{
|
||||
"starting_after": 0
|
||||
}'
|
||||
```
|
||||
```python python maxLines=70
|
||||
# 1) Start background stream and capture approval request
|
||||
stream = client.agents.messages.create_stream(
|
||||
agent_id=agent.id,
|
||||
messages=[{"role": "user", "content": "Do a sensitive operation"}],
|
||||
stream_tokens=True,
|
||||
background=True,
|
||||
)
|
||||
|
||||
approval_request_id = None
|
||||
orig_run_id = None
|
||||
last_seq_id = 0
|
||||
for chunk in stream:
|
||||
if hasattr(chunk, "run_id") and hasattr(chunk, "seq_id"):
|
||||
orig_run_id = chunk.run_id
|
||||
last_seq_id = chunk.seq_id
|
||||
if getattr(chunk, "message_type", None) == "approval_request_message":
|
||||
approval_request_id = chunk.id
|
||||
break
|
||||
|
||||
# 2) Approve in background; capture the approval stream cursor (this creates a new run)
|
||||
approve = client.agents.messages.create_stream(
|
||||
agent_id=agent.id,
|
||||
messages=[{"type": "approval", "approve": True, "approval_request_id": approval_request_id}],
|
||||
stream_tokens=True,
|
||||
background=True,
|
||||
)
|
||||
|
||||
run_id = None
|
||||
approve_seq = 0
|
||||
for chunk in approve:
|
||||
if hasattr(chunk, "run_id") and hasattr(chunk, "seq_id"):
|
||||
run_id = chunk.run_id
|
||||
approve_seq = chunk.seq_id
|
||||
if getattr(chunk, "message_type", None) == "tool_return_message":
|
||||
# Tool result arrives here on the approval stream
|
||||
break
|
||||
|
||||
# 3) Resume that run to read follow-up tokens
|
||||
for chunk in client.runs.stream(run_id, starting_after=approve_seq):
|
||||
print(chunk)
|
||||
```
|
||||
```typescript TypeScript maxLines=70
|
||||
// 1) Start background stream and capture approval request
|
||||
const stream = await client.agents.messages.createStream({
|
||||
agentId: agent.id,
|
||||
requestBody: {
|
||||
messages: [{ role: "user", content: "Do a sensitive operation" }],
|
||||
streamTokens: true,
|
||||
background: true,
|
||||
}
|
||||
});
|
||||
|
||||
let approvalRequestId: string | null = null;
|
||||
let origRunId: string | null = null;
|
||||
let lastSeqId = 0;
|
||||
for await (const chunk of stream) {
|
||||
if (chunk.run_id && chunk.seq_id) { origRunId = chunk.run_id; lastSeqId = chunk.seq_id; }
|
||||
if (chunk.message_type === "approval_request_message") {
|
||||
approvalRequestId = chunk.id; break;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) Approve in background; capture the approval stream cursor (this creates a new run)
|
||||
const approve = await client.agents.messages.createStream({
|
||||
agentId: agent.id,
|
||||
requestBody: {
|
||||
messages: [{ type: "approval", approve: true, approvalRequestId }],
|
||||
streamTokens: true,
|
||||
background: true,
|
||||
}
|
||||
});
|
||||
|
||||
let runId: string | null = null;
|
||||
let approveSeq = 0;
|
||||
for await (const chunk of approve) {
|
||||
if (chunk.run_id && chunk.seq_id) { runId = chunk.run_id; approveSeq = chunk.seq_id; }
|
||||
if (chunk.message_type === "tool_return_message") {
|
||||
// Tool result arrives here on the approval stream
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Resume that run to read follow-up tokens
|
||||
const resume = await client.runs.stream(runId!, { startingAfter: approveSeq });
|
||||
for await (const chunk of resume) {
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
|
||||
### Discovering and Resuming Active Streams
|
||||
|
||||
When your application starts or recovers from a crash, you can check for any active background streams and resume them. This is particularly useful for:
|
||||
- **Application restarts**: Resume processing after deployments or crashes
|
||||
- **Load balancing**: Pick up streams started by other instances
|
||||
- **Monitoring**: Check progress of long-running operations from different clients
|
||||
|
||||
<CodeGroup>
|
||||
```curl curl maxLines=50
|
||||
# Step 1: Find active background streams for your agents
|
||||
curl --request GET \
|
||||
--url https://api.letta.com/v1/runs/active \
|
||||
--header 'Authorization: Bearer $LETTA_API_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"agent_ids": [
|
||||
"agent-123",
|
||||
"agent-456"
|
||||
],
|
||||
"background": true
|
||||
}'
|
||||
# Returns: [{"run_id": "run-abc", "agent_id": "agent-123", "status": "processing", ...}]
|
||||
|
||||
# Step 2: Resume streaming from the beginning (or any specified seq_id)
|
||||
curl --request GET \
|
||||
--url https://api.letta.com/v1/runs/$RUN_ID/stream \
|
||||
--header 'Accept: text/event-stream' \
|
||||
--data '{
|
||||
"starting_after": 0, # Start from beginning
|
||||
"batch_size": 1000 # Fetch historical chunks in larger batches
|
||||
}'
|
||||
```
|
||||
```python python maxLines=50
|
||||
# Find and resume active background streams
|
||||
active_runs = client.runs.active(
|
||||
agent_ids=["agent-123", "agent-456"],
|
||||
background=True,
|
||||
)
|
||||
|
||||
if active_runs:
|
||||
# Resume the first active stream from the beginning
|
||||
run = active_runs[0]
|
||||
print(f"Resuming stream for run {run.id}, status: {run.status}")
|
||||
|
||||
stream = client.runs.stream(
|
||||
run_id=run.id,
|
||||
starting_after=0, # Start from beginning
|
||||
batch_size=1000 # Fetch historical chunks in larger batches
|
||||
)
|
||||
|
||||
# Each historical chunk is streamed one at a time, followed by new chunks as they become available
|
||||
for chunk in stream:
|
||||
print(chunk)
|
||||
```
|
||||
```typescript TypeScript maxLines=50
|
||||
// Find and resume active background streams
|
||||
const activeRuns = await client.runs.active({
|
||||
agentIds: ["agent-123", "agent-456"],
|
||||
background: true,
|
||||
});
|
||||
|
||||
if (activeRuns.length > 0) {
|
||||
// Resume the first active stream from the beginning
|
||||
const run = activeRuns[0];
|
||||
console.log(`Resuming stream for run ${run.id}, status: ${run.status}`);
|
||||
|
||||
const stream = await client.runs.stream(run.id, {
|
||||
startingAfter: 0, // Start from beginning
|
||||
batchSize: 1000 // Fetch historical chunks in larger batches
|
||||
});
|
||||
|
||||
// Each historical chunk is streamed one at a time, followed by new chunks as they become available
|
||||
for await (const chunk of stream) {
|
||||
console.log(chunk);
|
||||
}
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Option 2: Async Operations with Polling
|
||||
|
||||
<Note>
|
||||
**Best for:** Usecases where you don't need real-time token streaming.
|
||||
</Note>
|
||||
|
||||
Ideal for batch processing, scheduled jobs, or when you don't need real-time updates. The [async SDK method](/api-reference/agents/messages/create-async) queues your request and returns immediately, letting you check results later:
|
||||
|
||||
<CodeGroup>
|
||||
```curl curl maxLines=50
|
||||
# Start async operation (returns immediately with run ID)
|
||||
curl --request POST \
|
||||
--url https://api.letta.com/v1/agents/$AGENT_ID/messages/async \
|
||||
--header 'Authorization: Bearer $LETTA_API_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Run comprehensive analysis on this dataset"
|
||||
}
|
||||
]
|
||||
}'
|
||||
|
||||
# Poll for results using the returned run ID
|
||||
curl --request GET \
|
||||
--url https://api.letta.com/v1/runs/$RUN_ID
|
||||
```
|
||||
```python python maxLines=50
|
||||
# Start async operation (returns immediately with run ID)
|
||||
run = client.agents.messages.create_async(
|
||||
agent_id=agent_state.id,
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Run comprehensive analysis on this dataset"
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
# Poll for completion
|
||||
import time
|
||||
while run.status != "completed":
|
||||
time.sleep(2)
|
||||
run = client.runs.retrieve(run_id=run.id)
|
||||
|
||||
# Get the messages once complete
|
||||
messages = client.runs.messages.list(run_id=run.id)
|
||||
```
|
||||
```typescript TypeScript maxLines=50
|
||||
// Start async operation (returns immediately with run ID)
|
||||
const run = await client.agents.createAgentMessageAsync({
|
||||
agentId: agentState.id,
|
||||
requestBody: {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: "Run comprehensive analysis on this dataset"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
// Poll for completion
|
||||
while (run.status !== "completed") {
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
run = await client.runs.retrieveRun({ runId: run.id });
|
||||
}
|
||||
|
||||
// Get the messages once complete
|
||||
const messages = await client.runs.messages.list({ runId: run.id });
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Option 3: Configure Streaming with Keepalive Pings and Longer Timeouts
|
||||
|
||||
<Note>
|
||||
**Best for:** Usecases where you are already using the standard [streaming code](/guides/agents/streaming), but are experiencing issues with timeouts or disconnects (e.g. due to network interruptions or hanging tool executions).
|
||||
|
||||
**Trade-off:** Not as reliable as background mode, and does not support resuming a disconnected stream/request.
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
This approach assumes a persistent HTTP connection. We highly recommend using **background mode** (or async polling) for long-running jobs, especially when:
|
||||
- Your infrastructure uses aggressive proxy timeouts
|
||||
- You need to handle network interruptions gracefully
|
||||
- Operations might exceed 10 minutes
|
||||
</Warning>
|
||||
|
||||
For operations under 10 minutes that need real-time updates without the complexity of background processing. Configure keepalive pings and timeouts to maintain stable connections:
|
||||
|
||||
<CodeGroup>
|
||||
```curl curl maxLines=50
|
||||
curl --request POST \
|
||||
--url https://api.letta.com/v1/agents/$AGENT_ID/messages/stream \
|
||||
--header 'Authorization: Bearer $LETTA_API_KEY' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Execute this long-running analysis"
|
||||
}
|
||||
],
|
||||
"include_pings": true
|
||||
}'
|
||||
```
|
||||
```python python
|
||||
# Configure client with extended timeout
|
||||
from letta_client import Letta
|
||||
import os
|
||||
|
||||
client = Letta(
|
||||
token=os.getenv("LETTA_API_KEY")
|
||||
)
|
||||
|
||||
# Enable pings to prevent timeout during long operations
|
||||
stream = client.agents.messages.create_stream(
|
||||
agent_id=agent_state.id,
|
||||
messages=[
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Execute this long-running analysis"
|
||||
}
|
||||
],
|
||||
include_pings=True, # Sends periodic keepalive messages
|
||||
request_options={"timeout_in_seconds": 600} # 10 min timeout
|
||||
)
|
||||
|
||||
# Process the stream (pings will keep connection alive)
|
||||
for chunk in stream:
|
||||
if chunk.message_type == "ping":
|
||||
# Keepalive ping received, connection is still active
|
||||
continue
|
||||
print(chunk)
|
||||
```
|
||||
```typescript TypeScript maxLines=50
|
||||
// Configure client with extended timeout
|
||||
import { Letta } from '@letta/sdk';
|
||||
|
||||
const client = new Letta({
|
||||
token: process.env.LETTA_API_KEY
|
||||
});
|
||||
|
||||
// Enable pings to prevent timeout during long operations
|
||||
const stream = await client.agents.createAgentMessageStream({
|
||||
agentId: agentState.id,
|
||||
requestBody: {
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: "Execute this long-running analysis"
|
||||
}
|
||||
],
|
||||
includePings: true // Sends periodic keepalive messages
|
||||
}, {
|
||||
timeoutInSeconds: 600 // 10 minutes timeout in seconds
|
||||
}
|
||||
});
|
||||
|
||||
// Process the stream (pings will keep connection alive)
|
||||
for await (const chunk of stream) {
|
||||
if (chunk.message_type === "ping") {
|
||||
// Keepalive ping received, connection is still active
|
||||
continue;
|
||||
}
|
||||
console.log(chunk);
|
||||
}
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Configuration Guidelines
|
||||
|
||||
| Parameter | Purpose | When to Use |
|
||||
|-----------|---------|------------|
|
||||
| Timeout in seconds | Extends request timeout beyond 60s default | Set to 1.5x your expected max duration |
|
||||
| Include pings | Sends keepalive messages every ~30s | Enable for operations with long gaps between outputs |
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ try:
|
||||
__version__ = version("letta")
|
||||
except PackageNotFoundError:
|
||||
# Fallback for development installations
|
||||
__version__ = "0.15.0"
|
||||
__version__ = "0.15.1"
|
||||
|
||||
if os.environ.get("LETTA_VERSION"):
|
||||
__version__ = os.environ["LETTA_VERSION"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "letta"
|
||||
version = "0.15.0"
|
||||
version = "0.15.1"
|
||||
description = "Create LLM agents with long-term memory and custom tools"
|
||||
authors = [
|
||||
{name = "Letta Team", email = "contact@letta.com"},
|
||||
|
||||
Reference in New Issue
Block a user