Skip to content

Commit 52d9f40

Browse files
Update OSA docs for thin client CLI architecture (#7)
- getting-started: Split into user (pip install) and developer paths - cli-reference: Rewrite for new commands (init, ask, chat, health, config), BYOK flow, config file structure, API key priority chain - api-reference: Fix endpoint paths (/{community}/ask, /chat), update SSE format, add production/dev URLs, fix Python examples - index: Update quick start with pip install path - development: Fix merge strategy (squash, not merge commit)
1 parent 184b112 commit 52d9f40

5 files changed

Lines changed: 484 additions & 237 deletions

File tree

docs/osa/api-reference.md

Lines changed: 147 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,35 @@ The OSA REST API provides programmatic access to the assistant.
44

55
## Base URL
66

7-
```
8-
http://localhost:38528
9-
```
7+
- **Production**: `https://api.osc.earth/osa`
8+
- **Development**: `https://api.osc.earth/osa-dev`
9+
- **Local**: `http://localhost:38528`
1010

1111
## Authentication
1212

1313
OSA supports two authentication modes:
1414

1515
### Server API Key
1616

17+
For server-to-server access using an admin key:
18+
1719
```bash
18-
curl -H "X-API-Key: your-server-key" http://localhost:38528/chat
20+
curl -H "X-API-Key: your-server-key" https://api.osc.earth/osa/health
1921
```
2022

2123
### BYOK (Bring Your Own Key)
2224

23-
Pass your OpenRouter API key directly:
25+
Pass your OpenRouter API key directly. This is the primary method for CLI and widget users:
2426

2527
```bash
26-
curl -H "X-OpenRouter-Key: your-openrouter-key" http://localhost:38528/chat
28+
curl -H "X-OpenRouter-Key: your-openrouter-key" \
29+
https://api.osc.earth/osa/hed/ask \
30+
-H "Content-Type: application/json" \
31+
-d '{"question": "What is HED?"}'
2732
```
2833

34+
When using BYOK, no server API key is required. The user's key is forwarded to the LLM provider.
35+
2936
## Endpoints
3037

3138
### Health Check
@@ -40,25 +47,8 @@ Response:
4047
```json
4148
{
4249
"status": "healthy",
43-
"version": "0.1.0"
44-
}
45-
```
46-
47-
### API Info
48-
49-
Get API information.
50-
51-
```
52-
GET /info
53-
```
54-
55-
Response:
56-
```json
57-
{
58-
"name": "Open Science Assistant",
59-
"version": "0.1.0",
60-
"assistants": ["hed", "bids", "eeglab"],
61-
"models": ["openai/gpt-4.1-mini", "anthropic/claude-3-5-haiku"]
50+
"version": "0.7.0",
51+
"environment": "production"
6252
}
6353
```
6454

@@ -91,116 +81,213 @@ Response:
9181
]
9282
```
9383

94-
This endpoint is public (no authentication required) and is used by the widget to load display configuration from the community YAML configs.
84+
This endpoint is public (no authentication required).
85+
86+
### Ask
87+
88+
Ask a single question to a community assistant.
89+
90+
```
91+
POST /{community}/ask
92+
Content-Type: application/json
93+
X-OpenRouter-Key: your-key
94+
95+
{
96+
"question": "How do I annotate a button press in HED?",
97+
"stream": true
98+
}
99+
```
100+
101+
#### Non-streaming Response
102+
103+
When `stream: false`:
104+
105+
```json
106+
{
107+
"answer": "To annotate a button press in HED...",
108+
"tool_calls": []
109+
}
110+
```
111+
112+
#### Streaming Response (SSE)
113+
114+
When `stream: true` (default):
115+
116+
```
117+
data: {"event": "content", "content": "To"}
118+
119+
data: {"event": "content", "content": " annotate"}
120+
121+
data: {"event": "tool_start", "name": "retrieve_hed_docs", "params": {...}}
122+
123+
data: {"event": "tool_end", "name": "retrieve_hed_docs", "result": "..."}
124+
125+
data: {"event": "content", "content": "..."}
126+
127+
data: {"event": "done"}
128+
```
95129

96130
### Chat
97131

98-
Send a message and receive a streaming response.
132+
Multi-turn chat with conversation history.
99133

100134
```
101-
POST /chat
135+
POST /{community}/chat
102136
Content-Type: application/json
137+
X-OpenRouter-Key: your-key
103138
104139
{
105140
"message": "How do I annotate a button press in HED?",
106141
"session_id": "optional-session-id",
107-
"assistant": "hed",
108-
"model": "openai/gpt-4.1-mini"
142+
"stream": true
109143
}
110144
```
111145

112-
Response (Server-Sent Events):
146+
#### Non-streaming Response
147+
148+
```json
149+
{
150+
"session_id": "abc123",
151+
"message": {
152+
"role": "assistant",
153+
"content": "To annotate a button press..."
154+
},
155+
"tool_calls": []
156+
}
113157
```
114-
data: {"type": "start", "session_id": "abc123"}
115158

116-
data: {"type": "token", "content": "To"}
159+
#### Streaming Response (SSE)
117160

118-
data: {"type": "token", "content": " annotate"}
161+
```
162+
data: {"event": "session", "session_id": "abc123"}
119163
120-
data: {"type": "tool_call", "tool": "retrieve_hed_docs", "params": {...}}
164+
data: {"event": "content", "content": "To"}
121165
122-
data: {"type": "tool_result", "tool": "retrieve_hed_docs", "result": {...}}
166+
data: {"event": "tool_start", "name": "retrieve_hed_docs"}
123167
124-
data: {"type": "token", "content": "..."}
168+
data: {"event": "content", "content": " annotate"}
125169
126-
data: {"type": "end", "usage": {"prompt_tokens": 1234, "completion_tokens": 567}}
170+
data: {"event": "done", "session_id": "abc123"}
127171
```
128172

129173
## Request Parameters
130174

175+
### Ask Request
176+
177+
| Parameter | Type | Required | Description |
178+
|-----------|------|----------|-------------|
179+
| `question` | string | Yes | Question to ask |
180+
| `stream` | boolean | No | Enable SSE streaming (default: true) |
181+
| `model` | string | No | Custom LLM model (requires BYOK) |
182+
131183
### Chat Request
132184

133185
| Parameter | Type | Required | Description |
134186
|-----------|------|----------|-------------|
135187
| `message` | string | Yes | User message |
136188
| `session_id` | string | No | Session ID for multi-turn chat |
137-
| `assistant` | string | No | Assistant to use (hed, bids, eeglab) |
138-
| `model` | string | No | LLM model to use |
189+
| `stream` | boolean | No | Enable SSE streaming (default: true) |
190+
| `model` | string | No | Custom LLM model (requires BYOK) |
191+
192+
## Headers
193+
194+
| Header | Description | Required |
195+
|--------|-------------|----------|
196+
| `X-OpenRouter-Key` | OpenRouter API key (BYOK) | Yes (or X-API-Key) |
197+
| `X-API-Key` | Server admin API key | Yes (or BYOK) |
198+
| `X-User-ID` | User ID for cache optimization | No |
199+
| `Content-Type` | Must be `application/json` | Yes |
139200

140201
## Error Responses
141202

142-
### 400 Bad Request
203+
### 401 Unauthorized
143204

144205
```json
145206
{
146-
"error": "Invalid request",
147-
"detail": "Message is required"
207+
"detail": "API key required (or provide your own LLM key via BYOK headers)"
148208
}
149209
```
150210

151-
### 401 Unauthorized
211+
### 403 Forbidden
152212

153213
```json
154214
{
155-
"error": "Unauthorized",
156-
"detail": "API key required"
215+
"detail": "Invalid API key"
157216
}
158217
```
159218

160219
### 500 Internal Server Error
161220

162221
```json
163222
{
164-
"error": "Internal error",
165223
"detail": "LLM provider error"
166224
}
167225
```
168226

169-
## Python Client
227+
## Python Client Example
170228

171229
```python
172230
import httpx
173231

174-
async with httpx.AsyncClient() as client:
175-
async with client.stream(
232+
# Non-streaming
233+
response = httpx.post(
234+
"https://api.osc.earth/osa/hed/ask",
235+
json={"question": "What is HED?", "stream": False},
236+
headers={"X-OpenRouter-Key": "your-key"},
237+
)
238+
print(response.json()["answer"])
239+
```
240+
241+
```python
242+
import json
243+
import httpx
244+
245+
# Streaming
246+
with httpx.Client() as client:
247+
with client.stream(
176248
"POST",
177-
"http://localhost:38528/chat",
178-
json={"message": "What is HED?"},
249+
"https://api.osc.earth/osa/hed/ask",
250+
json={"question": "What is HED?", "stream": True},
179251
headers={"X-OpenRouter-Key": "your-key"},
180252
) as response:
181-
async for line in response.aiter_lines():
253+
for line in response.iter_lines():
182254
if line.startswith("data: "):
183255
data = json.loads(line[6:])
184-
if data["type"] == "token":
256+
if data["event"] == "content":
185257
print(data["content"], end="", flush=True)
186258
```
187259

188260
## cURL Examples
189261

190-
### Basic Query
262+
### Ask (Non-streaming)
191263

192264
```bash
193-
curl -X POST http://localhost:38528/chat \
265+
curl -X POST https://api.osc.earth/osa/hed/ask \
194266
-H "Content-Type: application/json" \
195267
-H "X-OpenRouter-Key: your-key" \
196-
-d '{"message": "What is HED?"}'
268+
-d '{"question": "What is HED?", "stream": false}'
197269
```
198270

199-
### With Session
271+
### Ask (Streaming)
200272

201273
```bash
202-
curl -X POST http://localhost:38528/chat \
274+
curl -N -X POST https://api.osc.earth/osa/hed/ask \
275+
-H "Content-Type: application/json" \
276+
-H "X-OpenRouter-Key: your-key" \
277+
-d '{"question": "What is HED?"}'
278+
```
279+
280+
### Chat with Session
281+
282+
```bash
283+
curl -X POST https://api.osc.earth/osa/hed/chat \
284+
-H "Content-Type: application/json" \
285+
-H "X-OpenRouter-Key: your-key" \
286+
-d '{"message": "What is HED?", "stream": false}'
287+
288+
# Continue conversation with session_id from response
289+
curl -X POST https://api.osc.earth/osa/hed/chat \
203290
-H "Content-Type: application/json" \
204291
-H "X-OpenRouter-Key: your-key" \
205-
-d '{"message": "Tell me more", "session_id": "my-session"}'
292+
-d '{"message": "Tell me more", "session_id": "abc123", "stream": false}'
206293
```

0 commit comments

Comments
 (0)