Two Approaches
Option 1: Use ORS Python SDK
Simplest approach - handles all protocol details:Copy
from ors.client import ORS
client = ORS(base_url="http://localhost:8080")
env = client.environment("myenv")
# Run episode
with env.session(task=task) as session:
prompt = session.get_prompt()
result = session.call_tool("submit", {"answer": "42"})
Option 2: Custom HTTP Client
For other languages - implement HTTP protocol:Python HTTP Client Example
Copy
import httpx
import json
class ORSClient:
def __init__(self, base_url: str):
self.base_url = base_url
self.client = httpx.Client(timeout=60.0)
def list_tools(self, env_name: str):
"""Get available tools"""
response = self.client.get(f"{self.base_url}/{env_name}/tools")
response.raise_for_status()
return response.json()["tools"]
def list_tasks(self, env_name: str, split: str):
"""Get tasks for split"""
response = self.client.post(
f"{self.base_url}/{env_name}/tasks",
json={"split": split}
)
response.raise_for_status()
return response.json()["tasks"]
def create_session(self):
"""Generate session ID"""
response = self.client.post(f"{self.base_url}/create_session")
response.raise_for_status()
return response.json()["sid"]
def create_episode(self, session_id: str, env_name: str, task_spec: dict):
"""Create episode instance"""
response = self.client.post(
f"{self.base_url}/create",
headers={"X-Session-ID": session_id},
json={
"env_name": env_name,
"task_spec": task_spec,
"secrets": {}
}
)
response.raise_for_status()
return response.json()
def get_prompt(self, session_id: str, env_name: str):
"""Get initial prompt"""
response = self.client.get(
f"{self.base_url}/{env_name}/prompt",
headers={"X-Session-ID": session_id}
)
response.raise_for_status()
return response.json()
def call_tool(self, session_id: str, env_name: str, tool_name: str, tool_input: dict):
"""Call tool (handles SSE)"""
with self.client.stream(
"POST",
f"{self.base_url}/{env_name}/call",
headers={
"X-Session-ID": session_id,
"Accept": "text/event-stream"
},
json={"name": tool_name, "input": tool_input}
) as response:
response.raise_for_status()
buffer = ""
event_type = ""
for line in response.iter_lines():
if line.startswith("event: "):
event_type = line[7:]
elif line.startswith("data: "):
data = line[6:]
if event_type == "end":
complete_data = buffer + data
result = json.loads(complete_data)
if result["ok"]:
return result["output"]
else:
raise Exception(result["error"])
elif event_type == "chunk":
buffer += data
elif event_type == "error":
raise Exception(data)
def ping(self, session_id: str):
"""Keep session alive (prevents 15-minute timeout)"""
response = self.client.post(
f"{self.base_url}/ping",
headers={"X-Session-ID": session_id}
)
response.raise_for_status()
return response.json()
def delete_episode(self, session_id: str):
"""Clean up episode"""
response = self.client.post(
f"{self.base_url}/delete",
headers={"X-Session-ID": session_id}
)
response.raise_for_status()
return response.json()
# Usage
client = ORSClient("http://localhost:8080")
# List available tools
tools = client.list_tools("math")
print(f"Available tools: {[t['name'] for t in tools]}")
# Get tasks
tasks = client.list_tasks("math", "train")
# Run episode
task = tasks[0]
session_id = client.create_session()
try:
client.create_episode(session_id, "math", task)
prompt = client.get_prompt(session_id, "math")
print(f"Prompt: {prompt[0]['text']}")
result = client.call_tool(session_id, "math", "submit", {"answer": "4"})
print(f"Reward: {result['reward']}")
print(f"Finished: {result['finished']}")
finally:
client.delete_episode(session_id)
Session Timeouts: ORS sessions expire after 15 minutes of inactivity. For long-running episodes, call
client.ping(session_id) periodically to keep the session alive. The reference SDK pings automatically every 10 seconds.JavaScript/TypeScript Client
Copy
class ORSClient {
constructor(private baseUrl: string) {}
async listTools(envName: string) {
const response = await fetch(`${this.baseUrl}/${envName}/tools`);
const data = await response.json();
return data.tools;
}
async createSession(): Promise<string> {
const response = await fetch(`${this.baseUrl}/create_session`, {
method: 'POST'
});
const data = await response.json();
return data.sid;
}
async callTool(
sessionId: string,
envName: string,
toolName: string,
toolInput: any
) {
const response = await fetch(`${this.baseUrl}/${envName}/call`, {
method: 'POST',
headers: {
'X-Session-ID': sessionId,
'Accept': 'text/event-stream',
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: toolName, input: toolInput })
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let eventType = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split(/\r?\n/);
for (const line of lines) {
if (line.startsWith('event: ')) {
eventType = line.slice(7).trim();
} else if (line.startsWith('data: ')) {
const data = line.slice(6).trim();
if (eventType === 'end') {
const result = JSON.parse(buffer + data);
if (result.ok) {
return result.output;
} else {
throw new Error(result.error);
}
} else if (eventType === 'chunk') {
buffer += data;
} else if (eventType === 'error') {
throw new Error(data);
}
}
}
}
}
}
// Usage
const client = new ORSClient('http://localhost:8080');
const sessionId = await client.createSession();
// ... create episode, call tools
Next Steps
HTTP API
Complete endpoint documentation
Quick Start
See complete client example
Key Takeaway: Building an ORS client is straightforward HTTP programming. Handle SSE for tool calls, manage session IDs, and implement proper error handling. Use the Python SDK for quick development or implement custom clients in any language.

