Chat & Agents Guide
Learn how to use Satori's AI agents for advanced interactions with your documents and knowledge bases.
Overview
Satori provides two types of AI agents:
- Knowledge Base Agents: Query documents in your enclaves
- Clinical Research Agents: Access research databases and medical literature
Knowledge Base Chat
The simplest way to interact with your documents is through the enclave chat endpoint.
Basic Chat
curl -X POST "{api_host}/api/tenants/{tenant_id}/enclaves/{enclave_id}/chat/" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"query": "What are the key findings?",
"user_id": "user-123",
"session_id": "session-abc"
}'
Response: Streaming text via Server-Sent Events
Python Example
import requests
def chat_with_enclave(enclave_id, query, session_id=None, user_id=None):
url = f"{BASE_URL}/api/tenants/{tenant_id}/enclaves/{enclave_id}/chat/"
headers = {
"Authorization": f"Bearer {JWT_TOKEN}",
"Content-Type": "application/json"
}
data = {
"query": query,
"session_id": session_id or f"session-{uuid.uuid4()}",
"user_id": user_id
}
response = requests.post(url, headers=headers, json=data, stream=True)
full_response = ""
for line in response.iter_lines():
if line:
text = line.decode('utf-8')
if text.startswith('data: '):
content = text[6:]
if content == '[DONE]':
break
full_response += content
print(content, end='', flush=True)
return full_response
Session Management
Sessions maintain conversation history for context:
session_id = "my-session-123"
# First message
response1 = chat_with_enclave(enclave_id, "What is this document about?", session_id)
# Follow-up (uses previous context)
response2 = chat_with_enclave(enclave_id, "Tell me more about that", session_id)
Retrieving Session History
curl -X GET "{api_host}/api/tenants/{tenant_id}/enclaves/{enclave_id}/chat/{session_id}/messages" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>"
Response:
{
"messages": [
{
"role": "user",
"content": "What are the primary endpoints?",
"timestamp": "2025-01-15T10:30:00Z"
},
{
"role": "assistant",
"content": "The primary endpoints are...",
"timestamp": "2025-01-15T10:30:05Z",
"sources": [
{
"file_name": "protocol.pdf",
"chunk_id": "node_abc123",
"page": 12
}
]
}
],
"session_id": "my-session-123",
"message_count": 2
}
Advanced Agents
Satori supports advanced AI agents with tool calling capabilities.
Agent Chat Endpoint
curl -X POST "{api_host}/api/tenants/{tenant_id}/chat/agent" \
-H "Authorization: Bearer <YOUR_JWT_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"threadId": "thread-123",
"runId": "run-456",
"messages": [...],
"tools": [...],
"context": [...]
}'
Agent Architecture
Agents use a message-based system:
- User Messages: Questions and instructions
- System Messages: Configuration and context
- Assistant Messages: Agent responses
- Tool Messages: Results from tool executions
- Developer Messages: System instructions
Example Agent Interaction
from typing import List, Dict, Any
def create_agent_request(
query: str,
thread_id: str,
run_id: str,
tools: List[Dict[str, Any]] = None,
context: List[Dict[str, Any]] = None
) -> Dict[str, Any]:
return {
"threadId": thread_id,
"runId": run_id,
"messages": [
{
"id": "msg-1",
"role": "user",
"content": query
}
],
"tools": tools or [],
"context": context or [],
"state": {},
"forwardedProps": {}
}
# Use the agent
request = create_agent_request(
query="What are the key findings in the research papers?",
thread_id="thread-123",
run_id="run-456"
)
response = requests.post(
f"{BASE_URL}/api/tenants/{tenant_id}/chat/agent",
headers={"Authorization": f"Bearer {JWT_TOKEN}"},
json=request,
stream=True
)
Clinical Research Agents
Clinical research agents have access to medical literature and research databases.
Clinical Agent Features
- Access to medical research databases
- Clinical trial information
- Medical literature search
- Evidence-based answers
Using Clinical Agents
def query_clinical_agent(query: str, session_id: str = None):
"""Query the clinical research agent."""
url = f"{BASE_URL}/api/tenants/{tenant_id}/chat/agent"
# Configure agent for clinical research
request = {
"threadId": session_id or f"clinical-{uuid.uuid4()}",
"runId": f"run-{uuid.uuid4()}",
"messages": [
{
"id": "msg-1",
"role": "user",
"content": query
}
],
"tools": [], # Agent will use built-in clinical tools
"context": [
{
"description": "Clinical research query",
"value": "medical"
}
],
"state": {},
"forwardedProps": {}
}
response = requests.post(
url,
headers={"Authorization": f"Bearer {JWT_TOKEN}"},
json=request,
stream=True
)
return response
Tool Calling
Agents can use tools to perform actions:
Available Tools
- Document Search: Search within enclave documents
- Web Search: Search the web for information
- Database Queries: Query structured data
- Custom Tools: Define your own tools
Tool Definition
tool = {
"name": "search_documents",
"description": "Search for information in uploaded documents",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query"
},
"limit": {
"type": "integer",
"description": "Maximum number of results"
}
},
"required": ["query"]
}
}
Agent with Tools
def agent_with_tools(query: str, enclave_id: str):
tools = [
{
"name": "search_enclave",
"description": f"Search documents in enclave {enclave_id}",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"},
"limit": {"type": "integer", "default": 5}
}
}
}
]
request = create_agent_request(
query=query,
thread_id=f"thread-{uuid.uuid4()}",
run_id=f"run-{uuid.uuid4()}",
tools=tools
)
response = requests.post(
f"{BASE_URL}/api/tenants/{tenant_id}/chat/agent",
headers={"Authorization": f"Bearer {JWT_TOKEN}"},
json=request,
stream=True
)
return response
Streaming Responses
All chat endpoints support streaming for real-time responses.
Handling Streams
def process_stream(response):
"""Process streaming response from agent."""
full_text = ""
for line in response.iter_lines():
if line:
text = line.decode('utf-8')
# Handle Server-Sent Events format
if text.startswith('data: '):
content = text[6:]
if content == '[DONE]':
break
full_text += content
yield content
return full_text
JavaScript Streaming
async function* streamAgentResponse(response: Response) {
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split("\n");
for (const line of lines) {
if (line.startsWith("data: ")) {
const text = line.slice(6);
if (text === "[DONE]") return;
yield text;
}
}
}
}
Best Practices
✅ DO:
- Use sessions for conversational context
- Provide clear, specific queries
- Handle streaming responses properly
- Review source citations
- Use appropriate agent types for your use case
❌ DON'T:
- Mix different conversation topics in the same session
- Ignore source citations
- Make too many concurrent agent requests
- Use agents for simple queries (use direct query endpoint instead)
Error Handling
Common Errors
404 Not Found
- Enclave doesn't exist
- Session not found
- Solution: Verify IDs and create resources first
500 Internal Server Error
- Agent execution error
- Tool execution failed
- Solution: Check query format and tool definitions
Error Handling Example
def safe_agent_query(query: str, enclave_id: str):
try:
response = agent_with_tools(query, enclave_id)
return process_stream(response)
except requests.HTTPError as e:
if e.response.status_code == 404:
raise ValueError("Enclave or session not found")
elif e.response.status_code == 500:
raise ValueError("Agent execution error")
else:
raise
Next Steps
- Querying Documents Guide - Direct document queries
- Text Processing Guide - Text processing tools
- Best Practices Guide - General usage best practices
- API Reference - Full API documentation