* chore: have letta fire a request after every step * chore: have letta fire a request after every step * chore: temporal * chore: temporal --------- Co-authored-by: Shubham Naik <shub@memgpt.ai>
6.3 KiB
Step Completion Webhook
This feature allows you to receive webhook notifications whenever an agent step completes in the Letta agent loop.
Architecture
The webhook service integrates with Letta's execution architecture in two ways:
1. With Temporal (Recommended)
When using Temporal for agent workflows, webhook calls are wrapped as Temporal activities, providing:
- Built-in retry logic with configurable timeouts
- Full observability in Temporal UI
- Durability guarantees
- Consistent error handling
- Activity history and replay capability
Webhooks are triggered after the create_step activity completes in the Temporal workflow.
2. Without Temporal (Direct Execution)
For direct agent execution (non-Temporal), webhooks are called directly from the StepManager service methods:
update_step_success_async()- When step completes successfullyupdate_step_error_async()- When step fails with an errorupdate_step_cancelled_async()- When step is cancelled
Webhooks are sent after the step status is committed to the database.
Common Behavior
In both cases:
- ✅ Webhook failures do not prevent step completion
- ✅ Step is always marked as complete in the database first
- ✅ Webhook delivery is logged for debugging
- ✅ Same authentication and payload format
Configuration
Set the following environment variables to enable webhook notifications:
Required
STEP_COMPLETE_WEBHOOK: The URL endpoint that will receive POST requests when steps complete.- Example:
https://your-app.com/api/webhooks/step-complete
- Example:
Optional
STEP_COMPLETE_KEY: A secret key used for authentication.- When set, the webhook service will include this in an
Authorizationheader asBearer {key} - Example:
your-secret-webhook-key-12345
- When set, the webhook service will include this in an
Webhook Payload
When a step completes, the webhook service will send a POST request with the following JSON payload:
{
"step_id": "step-01234567-89ab-cdef-0123-456789abcdef"
}
Authentication
If STEP_COMPLETE_KEY is configured, requests will include an Authorization header:
Authorization: Bearer your-secret-webhook-key-12345
Your webhook endpoint should validate this key to ensure requests are coming from your Letta instance.
Example Webhook Endpoint
Here's a simple example of a webhook endpoint (using FastAPI):
from fastapi import FastAPI, Header, HTTPException
from pydantic import BaseModel
import os
app = FastAPI()
class StepCompletePayload(BaseModel):
step_id: str
WEBHOOK_SECRET = os.getenv("STEP_COMPLETE_KEY")
@app.post("/api/webhooks/step-complete")
async def handle_step_complete(
payload: StepCompletePayload,
authorization: str = Header(None)
):
# Validate the webhook key
if WEBHOOK_SECRET:
if not authorization or not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Missing authorization")
token = authorization.replace("Bearer ", "")
if token != WEBHOOK_SECRET:
raise HTTPException(status_code=401, detail="Invalid authorization")
# Process the step completion
print(f"Step completed: {payload.step_id}")
# You can now:
# - Log the step completion
# - Trigger downstream processes
# - Update your application state
# - Send notifications
return {"status": "success"}
Usage Example
# Set environment variables
export STEP_COMPLETE_WEBHOOK="https://your-app.com/api/webhooks/step-complete"
export STEP_COMPLETE_KEY="your-secret-webhook-key-12345"
# Start your Letta server
python -m letta.server
When Webhooks Are Sent
Webhooks are triggered when a step reaches a terminal state:
- Success - Step completed successfully (
StepStatus.SUCCESS) - Error - Step failed with an error (
StepStatus.FAILED) - Cancelled - Step was cancelled (
StepStatus.CANCELLED)
All three states trigger the webhook with the same payload containing just the step_id.
Behavior
- No webhook URL configured: The service will skip sending notifications (logged at debug level)
- Webhook call succeeds: Returns status 200-299, logged at info level
- Webhook timeout: Returns error, logged at warning level (does not fail the step)
- HTTP error: Returns non-2xx status, logged at warning level (does not fail the step)
- Other errors: Logged at error level (does not fail the step)
Important: Webhook failures do not prevent step completion. The step will be marked as complete in the database regardless of webhook delivery status. This ensures system reliability - your webhook endpoint being down will not block agent execution.
Testing
To test the webhook functionality:
- Set up a webhook endpoint (you can use webhook.site for testing)
- Configure the environment variables
- Run an agent and observe webhook calls when steps complete
# Example using webhook.site
export STEP_COMPLETE_WEBHOOK="https://webhook.site/your-unique-url"
export STEP_COMPLETE_KEY="test-key-123"
# Run tests
python -m pytest apps/core/letta/services/webhook_service_test.py -v
Implementation Details
The webhook notification is sent after:
- The step is persisted to the database
- Step metrics are recorded
This ensures that the step data is fully committed before external systems are notified.
Temporal Integration
When using Temporal, the webhook call is executed as a separate activity (send_step_complete_webhook) with the following configuration:
- Start-to-close timeout: 15 seconds
- Schedule-to-close timeout: 30 seconds
- Retry behavior: Wrapped in try-catch to prevent workflow failure on webhook errors
This allows you to monitor webhook delivery in the Temporal UI and get detailed visibility into any failures.
File Locations
Core Service:
apps/core/letta/services/webhook_service.py- HTTP client for webhook delivery
Temporal Integration:
apps/core/letta/agents/temporal/activities/send_webhook.py- Temporal activity wrapperapps/core/letta/agents/temporal/temporal_agent_workflow.py- Workflow integrationapps/core/letta/agents/temporal/constants.py- Timeout constants
Non-Temporal Integration:
apps/core/letta/services/step_manager.py- Direct calls in update_step_* methods
Tests:
apps/core/letta/services/webhook_service_test.py- Unit tests