105 lines
2.8 KiB
Markdown
105 lines
2.8 KiB
Markdown
# Conol.ai SSE Protocol (Agent Sessions)
|
|
|
|
Conol.ai uses a custom SSE protocol over `/api/sessions`. This is NOT standard OpenAI SSE.
|
|
|
|
## Endpoints
|
|
|
|
### 1. Create Session
|
|
```
|
|
POST https://conol.ai/api/sessions
|
|
Content-Type: application/json
|
|
Cookies: __Secure-better-auth.session_token=<token>
|
|
__Secure-better-auth.better-auth-passkey=<key>
|
|
|
|
Body: {
|
|
"source": {"type": "home"},
|
|
"messages": [{"type": "text", "content": "user prompt"}],
|
|
"timezone": "Europe/Kyiv",
|
|
"agentModel": "gpt-5.5",
|
|
"agentEffort": "low"
|
|
}
|
|
|
|
Response: 201 Created
|
|
{
|
|
"sessionId": "dh2btg2juiqtjfuv5m02by2v"
|
|
}
|
|
```
|
|
|
|
### 2. Stream SSE Messages
|
|
```
|
|
GET https://conol.ai/api/sessions/{sessionId}/messages?logDeltas=1
|
|
```
|
|
|
|
## SSE Event Types
|
|
|
|
### `history_delta` — Main content event
|
|
This is the PRIMARY event type. Content is nested: `stages[] → logs[] → content[] → {type: "text", text: "..."}`
|
|
|
|
```json
|
|
{
|
|
"type": "history_delta",
|
|
"runtimeVersion": "orcai",
|
|
"stages": [{
|
|
"id": "hjbl6q...",
|
|
"logs": [{
|
|
"role": "assistant",
|
|
"type": "thinking",
|
|
"content": [{"type": "text", "text": "The user is asking..."}]
|
|
}],
|
|
"preview": [{
|
|
"role": "assistant",
|
|
"type": "thinking",
|
|
"content": [{"text": "..."}]
|
|
}]
|
|
}]
|
|
}
|
|
```
|
|
|
|
### `done` — End of stream
|
|
```json
|
|
{"type": "done"}
|
|
```
|
|
|
|
## Common Mistakes
|
|
|
|
### ❌ Looking for `text-delta` events
|
|
Conol.ai does NOT emit `text-delta`. All content comes via `history_delta`.
|
|
|
|
### ❌ Direct `POST /api/chat`
|
|
There is NO `/api/chat` endpoint. The only way to interact is through `/api/sessions`.
|
|
|
|
### ❌ Parsing only top-level content
|
|
Content is always nested: `stages[].logs[].content[]`. Must iterate through all levels.
|
|
|
|
## Correct Parser (Python)
|
|
|
|
```python
|
|
async with client.stream("GET", f"https://conol.ai/api/sessions/{sid}/messages?logDeltas=1") as stream:
|
|
async for line in stream.aiter_lines():
|
|
if not line or not line.startswith("data:"):
|
|
continue
|
|
ev = json.loads(line[5:].strip())
|
|
|
|
if ev.get("type") == "done":
|
|
break
|
|
|
|
if ev.get("type") == "history_delta":
|
|
for stage in ev.get("stages", []):
|
|
for log in stage.get("logs", []):
|
|
content = log.get("content", [])
|
|
if isinstance(content, list):
|
|
for part in content:
|
|
if isinstance(part, dict) and part.get("type") == "text":
|
|
full_text = part.get("text", full_text)
|
|
```
|
|
|
|
## Cookies
|
|
|
|
Conol.ai uses `better-auth` (not next-auth):
|
|
- `__Secure-better-auth.session_token` — session token
|
|
- `__Secure-better-auth.better-auth-passkey` — passkey
|
|
|
|
Both are `Secure`, `HttpOnly`, `SameSite=Lax`, domain `.conol.ai`.
|
|
|
|
Cookies expire and return HTTP 401 — re-login via Chrome CDP.
|