Automattic / Automattic/agents-api

Resumable event streams via event ids and cursors

Open
#552 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
PHP
Stars
33
Forks
8
Avg merge
1h 36m
Merged PRs (30d)
31

Description

## Problem

Streaming has no resume. The SSE helper writes `data:` frames only, so a browser `EventSource` has no event id to send back and reconnects with no position. On a dropped connection, a PHP timeout, a proxy cutting an idle stream, or a phone changing network, everything emitted meanwhile is lost to that client.

The data is already there. `agents/list-chat-run-events` takes a `cursor` and returns one with `has_more`. The stream just does not expose it, so clients have to choose between replaying a whole run and losing part of it. Long runs are where this hurts, and long runs are what run control was built for.

## Evidence

- `src/Runtime/functions-sse-response.php` — `agents_api_emit_sse_json_frame()` writes `data:` and flushes. No `id:` line.
- `src/Channels/register-agents-chat-run-control-abilities.php` — the events ability already accepts `cursor` and `limit` and returns `cursor` and `has_more`.
- `docs/external-clients.md` documents `message/stream` with no resume path.

## Required contract

- Emit an `id:` line on each SSE frame, using the same event id `agents/list-chat-run-events` returns, so stream position and page cursor are the same coordinate.
- Accept `Last-Event-ID` on the streaming routes, plus an explicit cursor parameter for clients that are not `EventSource`, and resume after that point.
- An unknown or expired cursor returns an explicit error. Never silently restart from the beginning of the run, which is how duplicates reach the user.
- Keep resume optional for adapters that cannot replay. Those reject the resume request rather than serving a partial stream as if it were complete.

## Tests

- A reconnect with `Last-Event-ID` receives only events after that id.
- An unknown or expired cursor returns an explicit error, not a full replay.
- A connection with no cursor behaves exactly as today.
- Event ids on the stream sort in the same order as the ids from `agents/list-chat-run-events` for the same run.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with src/Runtime/functions-sse-response.php and the streaming routes, then compare their behavior with src/Channels/register-agents-chat-run-control-abilities.php, which already handles cursors. Read docs/external-clients.md for the current client contract and add or run tests for reconnects, invalid cursors, no-cursor compatibility, and event ordering. Done means supported adapters resume after Last-Event-ID or an explicit cursor, while unsupported adapters reject resume explicitly.

Written by the indexing model from the issue text.

Assessment

Tech stack
php
Domain
api, backend, stream-processing
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.