Skip to content

refactor(endpointing): sans-io reducer core with language-neutral fixtures - #7638

Closed
u9g wants to merge 3 commits into
mainfrom
jason/sans-io-endpointing
Closed

u9g wants to merge 3 commits into
mainfrom
jason/sans-io-endpointing

Conversation

@u9g

@u9g u9g commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Why

This is the first step toward a shared sans-io core for the voice pipeline that both livekit/agents (Python) and livekit/agents-js could eventually run as a single Rust implementation. Endpointing is the proving ground for three reasons: it's small, the two SDKs already maintain hand-ported copies of it, and its logic was already almost pure.

This PR writes the core in pure Python and defines a language-neutral contract that a later Rust or JS core has to pass. It changes no behavior.

What

  • livekit.agents.core.endpointing is a sans-io reducer.
    • Events go in: UserSpeechStarted, UserSpeechEnded, AgentSpeechStarted, AgentSpeechEnded, OptionsUpdated.
    • Outputs come out of handle(event): MinDelayUpdated, UtteranceEndAdjusted, NonInterruptionOverridden.
    • FixedEndpointing and DynamicEndpointing expose read-only min_delay / max_delay / overlapping.
    • Invariants: imports only the stdlib (enforced by a test), never reads a clock (time arrives only as event at), never logs.
  • livekit.agents.voice.endpointing keeps BaseEndpointing, DynamicEndpointing and create_endpointing with identical signatures. These are now thin subclasses of the core: each method call becomes an event, and the returned outputs are logged with the same message, level and extra keys as before. AudioRecognition and AgentActivity are untouched.
  • tests/core_fixtures/endpointing.json holds 13 scenarios. Each step lists the event, the exact outputs, and the resulting state, and together they cover every branch of the dynamic logic. They were recorded from the pre-refactor implementation. tests/test_core_endpointing.py replays them against the core with an absolute float tolerance of 1e-9.

Commits

  1. refactor(endpointing): move logic into livekit.agents.core: a pure move with no behavior change.
  2. refactor(endpointing): sans-io reducer core: adds the events, outputs and handle(). The shell translates method calls and logs.
  3. test(endpointing): language-neutral core fixtures: adds the fixture contract, its runner, and the stdlib-only import test.

Verification

  • pytest --unit: 4424 passed, 5 skipped. Existing endpointing, agent-session and STT-trace tests pass, and the only edit to them is one appended regression test for explicit interruption=None.
  • Log parity: a recorder drove all 13 scenarios through the public shell on main and on this branch, capturing log records and state. Both runs produced byte-identical output.
  • make type-check and ruff are clean.

Not in this PR

  • agents-js: agents/src/voice/turn_config/endpointing.ts is unchanged. A follow-up can run tests/core_fixtures/endpointing.json against it to check parity. Its interruption === false check already matches the core's semantics.
  • Rust: there is no Rust implementation or binding yet. The event and output dataclasses are shaped to map one-to-one onto Rust enums and TS discriminated unions.

@u9g
u9g requested a review from a team as a code owner October 5, 2026 19:55

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Devin Review: 1 flag

Not posted on this PR by your GitHub settings — view it in Devin Review. (Configure)

Devin Review

@u9g u9g closed this Oct 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant