feat(api): GET /events accepts since and limit query params with X-EXO-Last-Idx header#2133
Open
5F0jd2vLq54RerYW wants to merge 3 commits into
Open
feat(api): GET /events accepts since and limit query params with X-EXO-Last-Idx header#21335F0jd2vLq54RerYW wants to merge 3 commits into
5F0jd2vLq54RerYW wants to merge 3 commits into
Conversation
…st-Idx header Extends GET /events stream_events handler to accept optional since (default 0) and limit (default None) query parameters. Reuses the existing DiskEventLog.read_range(start, end) primitive, so cost is ~10 LOC of API surface plus a test. The response includes an X-EXO-Last-Idx header set to the upper bound consumed, allowing clients to chain reads without a separate /state round-trip for lastEventAppliedIdx. Backward compatible: no params (since=0, limit=None) takes a fast path that calls read_all() and matches pre-patch behavior exactly. Use case: enables event-cursor tailing for downstream tools like the control-plane EXO swarm dispatcher, which previously had to poll the full ~150KB /state snapshot to detect runner state changes. Test: src/exo/api/tests/test_stream_events.py — 7 cases covering full dump backward compat, since+limit, since-only, since-beyond-count (empty), limit-larger-than-remaining (clamped), negative since rejected (FastAPI ge=0 validator), and chained cursor reads with no overlap. Patch is intended for upstream PR to exo-explore/exo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…vents tests Adds src/exo/api/tests/conftest.py with a sys.modules stub for the exo_rs Rust extension so Python-level API tests can run without a compiled binary. The stub provides empty placeholder classes for FromSwarm, AllQueuesFullError, MessageTooLargeError, NoPeersSubscribedToTopicError, Keypair, NetworkingHandle, Pidfile, and PidfileError — covering all exo_rs symbols imported at module level by exo.routing and exo.main. Only installed when the real extension is absent. Also removes unused `pytest` import from test_stream_events.py (ruff F401). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Author
|
Note: nix is not available in this dev environment, so I ran |
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends
GET /eventsto support cursor-based tailing without polling the full/statesnapshot.Changes:
src/exo/api/main.py: Add optionalsince(default 0) andlimit(default None) query params tostream_events(). Takes a fast-path toread_all()when both are absent — identical to pre-patch behavior.src/exo/api/tests/test_stream_events.py: 7 test cases covering full-dump backward compat,since+limit,since-only,since-beyond-count (empty), limit-clamped, negativesincerejected (FastAPIge=0), and chained cursor reads with no overlap.src/exo/api/tests/conftest.py:sys.modulesstub forexo_rsso API tests run without requiring a compiled Rust extension.Response header:
X-EXO-Last-Idx: <N>is set to the upper exclusive bound of the range consumed, allowing clients to chain reads with no gap and no overlap.Motivation
Downstream tooling needs to detect state changes efficiently. The previous approach required polling the full
/statesnapshot (~150KB). With this change, a client can tail events incrementally:Backward Compatibility
GET /eventswith no query params takes the sameread_all()fast-path as before. No existing client behavior changes.🤖 Generated with Claude Code