Files

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.