Add QR pairing (terminal QR, in-app scanner, iris://pair deep link)
CI / Kotlin tests (android host + desktop) (push) Successful in 8m5s
CI / Gateway plugin tests (push) Successful in 9m47s

This commit is contained in:
ARIA committed 2026-08-22 22:43:13 +02:00
1 parent 27dc7917f2
commit 7a6d922d12
63 files changed
+2073 -630

No files matched your search

+20 -20
View File
@@ -12,7 +12,7 @@ Every frame:
"v": 1,
"id": 42, // optional; present on requests + their responses
"type": "message", // frame type (below)
"chat_id": "android:default", // optional; scope for chat-scoped frames
"chat_id": "default", // optional; scope for chat-scoped frames
"thread_id": "t_123", // optional
"payload": { } // type-specific object
}
@@ -43,7 +43,7 @@ Pairing succeeded.
"search":true,"push":"fcm","pickers":true},
"sync_cursor":1042,
"last_pushed_cursor":1040,
"channels":[{"chat_id":"android:default","name":"Default","kind":"default","is_default":true}]
"channels":[{"chat_id":"default","name":"Default","kind":"default","is_default":true}]
}}
```
@@ -57,7 +57,7 @@ woke the device via push (dedupe, `08-push.md` §8.7).
A final / standalone message.
```json
{"type":"message","chat_id":"android:default","thread_id":null,
{"type":"message","chat_id":"default","thread_id":null,
"payload":{
"message_id":"m_9001","role":"assistant",
"text":"Here is the answer…",
@@ -107,7 +107,7 @@ them drop the message(s) from their cache. Also outboxed, so a device that was
offline learns of the deletion on its next `sync`.
```json
{"type":"message.deleted","id":30,"chat_id":"android:default","thread_id":null,
{"type":"message.deleted","id":30,"chat_id":"default","thread_id":null,
"payload":{"message_ids":["m_9001","m_9002"]}}
```
@@ -176,7 +176,7 @@ Channel directory updates. **Broadcast to all connected devices** (no explicit
subscribe; the server pushes to every open WS).
```json
{"type":"channel.created","payload":{"chat_id":"android:chan_7","name":"Cron Reports",
{"type":"channel.created","payload":{"chat_id":"chan_7","name":"Cron Reports",
"kind":"channel","parent_chat_id":null}}
```
@@ -190,7 +190,7 @@ title.
Response to a `history` request. Returns a page of messages for a chat/thread.
```json
{"type":"history","id":20,"chat_id":"android:default","thread_id":null,
{"type":"history","id":20,"chat_id":"default","thread_id":null,
"payload":{
"messages":[
{"message_id":"m_8990","role":"user","text":"Hi","ts":1723990000000},
@@ -244,9 +244,9 @@ Response to a `commands.complete` request. Autocomplete matches for a typed pref
Agent lifecycle for a chat/thread. App shows a "thinking…" indicator on `busy`.
```json
{"type":"agent.busy","chat_id":"android:default","thread_id":null,
{"type":"agent.busy","chat_id":"default","thread_id":null,
"payload":{"reason":"processing"}}
{"type":"agent.idle","chat_id":"android:default","thread_id":null,"payload":{}}
{"type":"agent.idle","chat_id":"default","thread_id":null,"payload":{}}
```
`reason` ∈ `processing | tool | waiting_input | cron`.
@@ -256,7 +256,7 @@ Agent lifecycle for a chat/thread. App shows a "thinking…" indicator on `busy`
```json
{"type":"search.results","id":7,"payload":{
"query":"deploy","scope":"all","hits":[
{"message_id":"m_123","chat_id":"android:chan_7","thread_id":null,
{"message_id":"m_123","chat_id":"chan_7","thread_id":null,
"role":"assistant","snippet":"…deploy the service…","ts":1723900000000}]}}
```
@@ -275,7 +275,7 @@ The gateway acknowledges that the agent has received and started processing
the user's message. The app uses it to show ✓✓ on user bubbles.
```json
{"type":"read.receipt","chat_id":"android:default","payload":{"message_id":"m_9001"}}
{"type":"read.receipt","chat_id":"default","payload":{"message_id":"m_9001"}}
```
Emitted to the originating connection when a `message.send` is accepted for
@@ -319,7 +319,7 @@ First frame; auth + caps.
```json
{"type":"hello","payload":{
"token":"<ANDROID_TOKEN>","device_id":"dev_a1b2","device_name":"MIX 2S",
"token":"<IRIS_TOKEN>","device_id":"dev_a1b2","device_name":"MIX 2S",
"caps":{"min_protocol":1,"media":true,"push":"fcm"},
"fcm_token":"<FCM token>","ntfy_topic":"<topic, if ntfy>"}}
```
@@ -329,7 +329,7 @@ First frame; auth + caps.
Send text (or a `/slash-command`).
```json
{"type":"message.send","id":10,"chat_id":"android:default","thread_id":null,
{"type":"message.send","id":10,"chat_id":"default","thread_id":null,
"payload":{"text":"/model qwen3-27b","reply_to":"m_9001","media_refs":["mu_1"],
"auto_thread":false}}
```
@@ -383,8 +383,8 @@ Answer an interactive picker.
```json
{"type":"channel.create","id":14,"payload":{"name":"Cron Reports","kind":"channel"}}
{"type":"channel.rename","id":15,"chat_id":"android:chan_7","payload":{"name":"Reports"}}
{"type":"channel.set_default","id":16,"chat_id":"android:chan_7","payload":{}}
{"type":"channel.rename","id":15,"chat_id":"chan_7","payload":{"name":"Reports"}}
{"type":"channel.set_default","id":16,"chat_id":"chan_7","payload":{}}
```
`channel.delete` is a **hard delete**: the channel/thread row is removed from
@@ -396,7 +396,7 @@ removes its threads. The default channel cannot be deleted.
```json
{"type":"search","id":17,"payload":{"query":"deploy","scope":"all"}}
{"type":"search","id":18,"payload":{"query":"deploy","scope":"chat","chat_id":"android:chan_7","thread_id":null}}
{"type":"search","id":18,"payload":{"query":"deploy","scope":"chat","chat_id":"chan_7","thread_id":null}}
```
`scope` ∈ `all | chat`.
@@ -408,7 +408,7 @@ broadcasts to other devices (for multi-device ✓✓ sync). The app uses it to
mark messages as read locally (✓✓ on user bubbles).
```json
{"type":"read.receipt","payload":{"chat_id":"android:default","message_id":"m_9001"}}
{"type":"read.receipt","payload":{"chat_id":"default","message_id":"m_9001"}}
```
### `history`
@@ -416,7 +416,7 @@ mark messages as read locally (✓✓ on user bubbles).
Load a page of messages for a chat/thread (initial open, scroll-up pagination).
```json
{"type":"history","id":20,"chat_id":"android:default","thread_id":null,
{"type":"history","id":20,"chat_id":"default","thread_id":null,
"payload":{"before_message_id":"m_8990","limit":50}}
```
@@ -433,7 +433,7 @@ message already gone (pruned by retention) still yields a `message.deleted`
broadcast so live caches drop it.
```json
{"type":"message.delete","id":30,"chat_id":"android:default","thread_id":null,
{"type":"message.delete","id":30,"chat_id":"default","thread_id":null,
"payload":{"message_ids":["m_9001","m_9002"]}}
```
@@ -458,7 +458,7 @@ Autocomplete for a typed `/prefix`.
Stop the current agent turn (abort generation / tool execution).
```json
{"type":"agent.stop","id":23,"chat_id":"android:default","thread_id":null,"payload":{}}
{"type":"agent.stop","id":23,"chat_id":"default","thread_id":null,"payload":{}}
```
### `agent.steer`
@@ -466,7 +466,7 @@ Stop the current agent turn (abort generation / tool execution).
Inject a steering message mid-turn (redirects the agent without a new turn).
```json
{"type":"agent.steer","id":24,"chat_id":"android:default","thread_id":null,
{"type":"agent.steer","id":24,"chat_id":"default","thread_id":null,
"payload":{"text":"Actually, focus on the error case."}}
```