Files
ironclaw/docs/drafts/ops/orchestrator.mdx
2026-04-09 14:18:30 +02:00

349 lines
7.4 KiB
Plaintext

---
title: Orchestrator API
sidebarTitle: Orchestrator
description: Internal worker API for sandbox container communication
---
The Orchestrator runs on a separate internal port (default `50051`) from the web gateway. This API is used by worker containers to communicate with the orchestrator for LLM calls, credential injection, and job lifecycle management.
<Note>
This is an internal API. Worker containers receive a per-job bearer token during initialization. All `/worker/` endpoints require authentication.
</Note>
## Base URL
```
http://localhost:50051
```
## Authentication
Workers authenticate using per-job bearer tokens issued during container initialization:
```http
Authorization: Bearer <job_token>
```
Tokens are scoped to specific job IDs and rejected if used for other jobs.
---
## Health
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/health` | Liveness check — returns `200 OK` if orchestrator is running |
### GET /health
```bash
curl -s http://localhost:50051/health
# Response: "ok"
```
---
## Job Management
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/worker/{job_id}/job` | Get job description and configuration |
| `POST` | `/worker/{job_id}/status` | Worker reports current status/iteration |
| `POST` | `/worker/{job_id}/complete` | Worker reports job completion or failure |
### GET /worker/{job_id}/job
```bash
curl -s -H "Authorization: Bearer $TOKEN" \
http://localhost:50051/worker/job_01j9abc123/job | jq .
```
**Response:**
```json
{
"title": "Job job_01j9abc123",
"description": "Analyze the codebase and summarize findings",
"project_dir": "/workspace/my-project"
}
```
### POST /worker/{job_id}/status
```bash
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"state": "in_progress",
"message": "Running analysis",
"iteration": 3
}' \
http://localhost:50051/worker/job_01j9abc123/status
```
**Request body:**
```json
{
"state": "string (pending|running|in_progress|completed|failed)",
"message": "string (optional status message)",
"iteration": "integer (current iteration count)"
}
```
### POST /worker/{job_id}/complete
```bash
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"success": true,
"message": "Analysis complete. Found 5 key files."
}' \
http://localhost:50051/worker/job_01j9abc123/complete
```
**Request body:**
```json
{
"success": "boolean (required)",
"message": "string (optional result message)"
}
```
**Response:**
```json
{
"status": "ok"
}
```
---
## LLM Proxy
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/worker/{job_id}/llm/complete` | Proxy a completion request to the LLM |
| `POST` | `/worker/{job_id}/llm/complete_with_tools` | Proxy a tool-use request to the LLM |
### POST /worker/{job_id}/llm/complete
```bash
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "Hello"}
],
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 1024,
"temperature": 0.7
}' \
http://localhost:50051/worker/job_01j9abc123/llm/complete | jq .
```
**Request body:**
```json
{
"messages": "array (ChatMessage array)",
"model": "string (model identifier)",
"max_tokens": "integer (optional, default from config)",
"temperature": "float (optional, 0.0-1.0)",
"stop_sequences": "array (optional)"
}
```
**Response:**
```json
{
"content": "LLM response text",
"input_tokens": 15,
"output_tokens": 42,
"finish_reason": "stop"
}
```
### POST /worker/{job_id}/llm/complete_with_tools
```bash
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{"role": "user", "content": "List files in the project"}
],
"tools": [
{
"name": "shell",
"description": "Execute shell commands",
"input_schema": {
"type": "object",
"properties": {
"command": {"type": "string"}
}
}
}
],
"model": "claude-3-5-sonnet-20241022",
"max_tokens": 1024
}' \
http://localhost:50051/worker/job_01j9abc123/llm/complete_with_tools | jq .
```
**Request body:**
```json
{
"messages": "array (ChatMessage array)",
"tools": "array (Tool definition array)",
"model": "string (model identifier)",
"max_tokens": "integer",
"temperature": "float (optional)",
"tool_choice": "string (optional, 'auto'|'none'|tool name)"
}
```
**Response:**
```json
{
"content": "I'll list the files for you.",
"tool_calls": [
{
"id": "call_abc123",
"name": "shell",
"input": {"command": "ls -la"}
}
],
"input_tokens": 120,
"output_tokens": 85,
"finish_reason": "tool_use"
}
```
---
## Job Events
| Method | Endpoint | Description |
|--------|----------|-------------|
| `POST` | `/worker/{job_id}/event` | Worker sends events (message, tool_use, tool_result, result) |
### POST /worker/{job_id}/event
```bash
curl -s -X POST \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"event_type": "message",
"data": {
"role": "assistant",
"content": "Analyzing the codebase..."
}
}' \
http://localhost:50051/worker/job_01j9abc123/event
```
**Event types:**
| Event Type | Data Fields |
|------------|-------------|
| `message` | `role`, `content` |
| `tool_use` | `tool_name`, `input` |
| `tool_result` | `tool_name`, `output` |
| `result` | `status`, `session_id` (optional) |
**Response:** `200 OK` on success
---
## Claude Code Bridge
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/worker/{job_id}/prompt` | Get next queued follow-up prompt for Claude Code |
### GET /worker/{job_id}/prompt
```bash
curl -s -H "Authorization: Bearer $TOKEN" \
http://localhost:50051/worker/job_01j9abc123/prompt
```
**Response (with pending prompt):**
```json
{
"content": "What is the current git status?",
"done": false
}
```
**Response (queue empty):** `204 No Content`
---
## Credentials
| Method | Endpoint | Description |
|--------|----------|-------------|
| `GET` | `/worker/{job_id}/credentials` | Get decrypted secrets granted to this job |
### GET /worker/{job_id}/credentials
```bash
curl -s -H "Authorization: Bearer $TOKEN" \
http://localhost:50051/worker/job_01j9abc123/credentials | jq .
```
**Response:**
```json
[
{
"env_var": "GITHUB_TOKEN",
"value": "ghp_xxxxxxxxxxxx"
},
{
"env_var": "DATABASE_URL",
"value": "postgres://user:pass@localhost/db"
}
]
```
**Response (no grants):** `204 No Content`
**Response (secrets store unavailable):** `503 Service Unavailable`
---
## Error Codes
| Status | Code | Description |
|--------|------|-------------|
| `401` | Unauthorized | Missing or invalid job token |
| `404` | Not Found | Job not found or container not running |
| `503` | Service Unavailable | Secrets store not configured |
---
## Configuration
The orchestrator port is configured via:
| Environment Variable | Default | Description |
|----------------------|---------|-------------|
| `ORCHESTRATOR_PORT` | `50051` | Internal API port |
On Linux, the orchestrator binds to all interfaces (`0.0.0.0`) to allow container access. On macOS/Windows, it binds to loopback (`127.0.0.1`) since Docker Desktop routes through the VM.