fix(sessions): expose turn detection and barge-in configuration across SDKs - #1056
Conversation
Signed-off-by: WANG Qingmin <75425799+FriendlyPasser@users.noreply.github.com>
Performance
⚠ Regression detected:
|
📊 Coverage gateThresholds from
✅ Gate passedNo surface regressed past the allowed threshold and the aggregate stayed above the floor. |
📐 Patch coverage gateThreshold: 80% on lines this PR touches vs
✅ Patch gate passedEvery surface whose lines were touched by this PR has patch coverage at or above the threshold. |
Signed-off-by: WANG Qingmin <75425799+FriendlyPasser@users.noreply.github.com>
santoshkumarradha
left a comment
There was a problem hiding this comment.
This looks good. I checked the turn-detection contract across the control plane and all three SDKs, including explicit false and zero values, semantic VAD, target resolution at offer time, and the OpenAI Realtime payload shape. The focused Go, Python, and TypeScript tests pass locally, along with TypeScript lint and build, and the required CI and CLA checks are green.
session_turn_detection.py landed on main (via Agent-Field#1056) after this PR opened and carries 3 mypy errors (loosely-typed dict value used in numeric comparisons at line 58). The mypy gate correctly failed on it because it was not allowlisted - the ratchet working as designed. Add it to the allowlist to keep this PR a pure CI-wiring change; the module's type errors can be cleaned in a follow-up (phase 2).
…971) (#1052) * ci(python-sdk): enforce mypy with module-by-module allowlist ratchet Adopts the mypy half of #620 (the ruff half shipped in #812). mypy.ini existed but nothing ran it. This wires a required mypy step into the Python SDK CI without changing any behavior. Phase 1 of #971: - Pin mypy==1.18.2 in the dev extras (and uv.lock). - Add a per-module ignore_errors allowlist to mypy.ini for the 34 modules that currently have type errors, so the gate can be enforced now and the allowlist shrunk module by module. - Add a 'Type check (mypy)' step to .github/workflows/sdk-python.yml running 'mypy --config-file mypy.ini agentfield/'. The gate is green today (Success: no issues found). It fails if a non-allowlisted module gains a new error, or if a module is removed from the allowlist while it still has errors. No '# type: ignore' sprinkles were added. * ci(python-sdk): pin types-requests so mypy gate is reproducible Addresses review on #1052. The locked dev environment pins requests 2.33.1, which ships no type stubs, so 'uv sync --extra dev' followed by mypy failed with [import-untyped] in multimodal.py and agent_field_handler.py. CI was green only because 'pip install .[dev]' resolved a newer requests that bundles stubs, so it wasn't validating the reproducible environment. Pin types-requests==2.33.0.20260906 in the dev extras (and uv.lock) so mypy passes in both the locked (uv sync) and pip-resolved environments. Verified mypy clean against the locked requests 2.33.1 and a newer requests; ruff still clean; uv lock --check clean. * ci(python-sdk): allowlist session_turn_detection for mypy ratchet session_turn_detection.py landed on main (via #1056) after this PR opened and carries 3 mypy errors (loosely-typed dict value used in numeric comparisons at line 58). The mypy gate correctly failed on it because it was not allowlisted - the ratchet working as designed. Add it to the allowlist to keep this PR a pure CI-wiring change; the module's type errors can be cleaned in a follow-up (phase 2).
Summary
Session authors cannot currently configure voice turn detection or interruption, and the stateless WebRTC offer endpoint does not resolve the registered session configuration. This PR adds validated
turn_detectionoptions to the Python, TypeScript, and Go SDKs and forwards them to OpenAI undersession.audio.input.turn_detection, with interruptible server VAD enabled by default.server_vadthresholds/padding/silence duration andsemantic_vadeagerness, pluscreate_responseandinterrupt_response; preserve explicitfalseand0.offer_url, re-read and validate its configuration at offer time, and add CLIsession offer --target <node>.<session>support. Legacy direct offers retain default VAD behavior; clients building URLs themselves must include the target to use registered settings.Type of change
Test plan
Passed locally:
python -m pytest tests/test_agent_session.py tests/test_session_transport.py -o addopts='' -q— 25 tests.npm test -- tests/session_turn_detection.test.ts tests/session_transport.test.ts tests/agent.test.ts— 31 tests.npm run lintandnpm run build.go test ./agent -run 'Session|TurnDetection' -count=1— 9 top-level tests.go test ./pkg/types ./internal/handlers ./internal/cli -run 'Session|TurnDetection' -count=1— 41 top-level tests, including table-driven subtests.git diff --check.The new control-plane regression tests failed before the handler fix: invalid configurations were accepted and the start response omitted turn detection. They now exercise registration metadata → start → SDP offer → the actual multipart request sent to a mocked OpenAI endpoint, including defaults, explicit false/zero values, semantic VAD, and model/voice resolution.
Not tested: real OpenAI Realtime calls or microphone-based voice conversations. The test environment has no configured
OPENAI_API_KEY, so we did not have the credentials needed to perform live voice testing. Actual speech detection, interruption/barge-in behavior, audio quality, and latency remain unverified against the live service. Automated request validation is not a substitute for those checks.Test coverage
998dba0.After the initial CI patch-coverage failure (75% for the control plane), commit
998dba0adds direct parser contract tests and invalid-target handler tests. Using the samegocover-cobertura/diff-coverapproach as CI, the local control-plane patch report now covers 156/156 changed lines (100%); the subsequent CI run also passed with 100% control-plane patch coverage.Coverage baselines have not been changed. The full repository-wide coverage suite was not run locally.
Checklist
docs/DEVELOPMENT.md(CONTRIBUTING.mdis not present).Related issues / PRs
Fixes #663