Implement inbox read cursors for unread threads

This commit is contained in:
2026-03-19 03:43:10 +08:00
parent 02d98a78dd
commit 1927930570
19 changed files with 240 additions and 38 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ As of now:
- `inbox` and `orch` both compile
- shared SQLite schema initialization exists
- `inbox` is implemented end-to-end, including send/fetch/claim/renew/update/reply/done/fail/cancel/list/show/watch/wait-reply
- `inbox` supports blocking waits, lease renewal, unread fetches, `--body-file`, artifact attachments, and structured JSON errors with stable exit codes
- `inbox` supports blocking waits, lease renewal, unread fetches backed by per-agent read cursors, `--body-file`, artifact attachments, and structured JSON errors with stable exit codes
- integration tests cover the main inbox lifecycle, wait/watch flows, artifact persistence, and JSON error contracts
- `orch` currently exists as a command skeleton only
- no scheduler workflows have been implemented yet
+17
View File
@@ -39,6 +39,7 @@ Those decisions belong to `orch`.
- `lease`: an exclusive worker claim for a thread
- `artifact`: a path or file reference attached to a message
- `event`: a monotonic record used to wake blocking waiters
- `read cursor`: the last thread message an agent has explicitly consumed
## Required Fields
@@ -161,6 +162,8 @@ Suggested flags:
- `--limit N`
- `--unread`
`--unread` should use a per-agent thread read cursor, not a latest-message heuristic alone.
### `inbox claim`
Acquire a lease on a thread.
@@ -280,6 +283,7 @@ Suggested flags:
- `--thread THREAD_ID`
- `--json`
- `--mark-read`
`show` should include per-message artifact references when present.
@@ -420,6 +424,16 @@ CREATE TABLE IF NOT EXISTS artifacts (
FOREIGN KEY(message_id) REFERENCES messages(message_id)
);
CREATE TABLE IF NOT EXISTS thread_reads (
thread_id TEXT NOT NULL,
agent_id TEXT NOT NULL,
last_read_message_id TEXT NOT NULL,
last_read_at TEXT NOT NULL,
PRIMARY KEY(thread_id, agent_id),
FOREIGN KEY(thread_id) REFERENCES threads(thread_id),
FOREIGN KEY(last_read_message_id) REFERENCES messages(message_id)
);
CREATE TABLE IF NOT EXISTS events (
event_id INTEGER PRIMARY KEY AUTOINCREMENT,
run_id TEXT NOT NULL,
@@ -441,6 +455,9 @@ CREATE INDEX IF NOT EXISTS idx_messages_thread_created
CREATE INDEX IF NOT EXISTS idx_events_thread_event
ON events(thread_id, event_id);
CREATE INDEX IF NOT EXISTS idx_thread_reads_agent
ON thread_reads(agent_id, last_read_at);
```
## Concurrency Notes