Fix voice-call streaming provider resolution#97170
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 6, 2026, 3:20 AM ET / 07:20 UTC. Summary PR surface: Source +240, Tests +476, Docs +9, Config 0, Other 0. Total +725 across 20 files. Reproducibility: yes. Current main still lists and resolves realtime transcription providers directly from the active registry, while the linked issue and PR proof show that path can hide the configured xAI Voice Call streaming provider. Review metrics: 2 noteworthy metrics.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review detailsBest possible solution: Keep the bounded Talk/provider-runtime fix, refresh the branch onto current main without duplicate drift, update the PR body to the rewritten exact-head semantics, and land only after exact-head gates pass. Do we have a high-confidence way to reproduce the issue? Yes. Current main still lists and resolves realtime transcription providers directly from the active registry, while the linked issue and PR proof show that path can hide the configured xAI Voice Call streaming provider. Is this the best way to solve the issue? Yes for the rewritten Talk/provider-runtime fix; no for the current branch as a landing artifact until the dirty duplicate drift and stale PR body are refreshed. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against d7d19a3a8e0f. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +240, Tests +476, Docs +9, Config 0, Other 0. Total +725 across 20 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 95340b88d6
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a4c589f5fc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f3782ec54e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Addressed the ClawSweeper review findings in 7679e13:
Local verification:
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 151cf3c9b8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Addressed the two current ClawSweeper P1 compatibility findings in 9bb9ac7:
Resolved the two matching connector threads as fixed and updated the PR body's behavior-change notes to match the new semantics. Local verification:
All passed locally. GitHub checks are rerunning on the updated head. @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Keep PR openclaw#97170 current with upstream Talk settings changes. Codex automation: monitor-openclaw-pr-97170
7e648d9 to
3b4e8b7
Compare
|
Maintainer rewrite complete and land-ready. What changed:
Proof on rewritten head
The rewrite removes unrelated config-precedence and speech-filtering changes from the submitted patch while fixing the linked #97738 behavior at the owning boundaries. Thanks @solavrc for the report and initial implementation. |
Co-authored-by: sola <[email protected]>
|
Merged via squash.
|
Fixes #97738
What Problem This Solves
talk.catalogreportstranscription.activeProviderfrom the Talk/voice-call streaming config, but realtime transcription provider listing could return only the already-active runtime registry providers.In a Gateway configured with
plugins.entries["voice-call"].config.streaming.provider = "xai", the failure mode was:talk.catalogstill reportsactiveProvider: "xai", buttranscription.providersonly containsopenai.talk.session.createfor Review voice then fails withRealtime transcription provider "xai" is not configured.Root cause: Talk/voice-call streaming provider IDs were not consistently carried into realtime transcription provider resolution. The first version of this PR fixed catalog/config building, but
talk.session.createstill re-listed providers without the Talk-requested provider set, so the session path could still miss a cold provider when the active registry only contained OpenAI.This patch keeps Talk-owned provider selection in Talk code. The generic capability resolver accepts explicit
requestedProviderIds, and Talk passes its configured transcription provider IDs through both catalog and session resolution. It also reads both supported Voice Call config entry IDs:voice-calland@openclaw/voice-call.Implementation Notes
requestedProviderIdsoption toresolvePluginCapabilityProviders.voice-call/@openclaw/voice-callstreaming config parsing intalk-shared.ts.talk.catalog,buildTalkTranscriptionConfig, andresolveConfiguredRealtimeTranscriptionProvider.plugins.entries["@openclaw/voice-call"]config.Evidence
Current head:
7e648d9b51fe08476a59ffb54dbc93a07bd0f412after merging upstreammain(5d8293c1fe404f607b3ecddcb9f12d1753a4de51).Current local validation on this branch after the upstream-main merge:
Real Gateway proof, redacted, using the same local config/auth state with
voice-call.streaming.provider = "xai":Before the completed fix, installed Gateway
2026.6.10 (aa69b12):{ "activeProvider": "xai", "providers": [ { "id": "openai", "configured": true, "transports": ["gateway-relay"], "brains": ["none"], "defaultModel": "gpt-4o-transcribe" } ] }{ "ok": false, "error": { "code": "UNAVAILABLE", "message": "Error: Realtime transcription provider \"xai\" is not configured" } }After the completed fix, patched source Gateway on a separate local port with channels skipped:
{ "activeProvider": "xai", "providers": [ { "id": "xai", "configured": true, "transports": ["gateway-relay"], "brains": ["none"] } ] }{ "provider": "xai", "mode": "transcription", "transport": "gateway-relay", "audio": { "inputEncoding": "g711_ulaw", "inputSampleRateHz": 8000 }, "brain": "none" }Minimal Config / OAuth State Check
I also verified the provider/config interaction separately from the full local plugin set.
Minimal config used for the clean check:
{ "gateway": { "mode": "local", "bind": "loopback", "auth": { "mode": "none" }, "tailscale": { "mode": "off" } }, "plugins": { "allow": ["voice-call", "xai"], "entries": { "voice-call": { "enabled": true, "config": { "streaming": { "enabled": true, "provider": "xai", "providers": { "xai": { "endpointingMs": 800 } } } } }, "xai": { "enabled": true } } } }openclaw config validate --jsonpassed with no warnings for that config.With an empty temporary state dir, the same config returns the xAI provider but marks it unconfigured, as expected because no API key or OAuth profile exists there:
{ "activeProvider": "xai", "providers": [ { "id": "xai", "configured": false } ] }With the same minimal config and the existing local OpenClaw state/auth store, the xAI OAuth profile is used. No
XAI_API_KEYorOPENAI_API_KEYwas present in~/.openclaw/.envduring this check.{ "activeProvider": "xai", "providers": [ { "id": "xai", "label": "xAI Realtime Transcription", "configured": true, "modes": ["transcription"], "transports": ["gateway-relay"], "brains": ["none"] } ] }{ "provider": "xai", "mode": "transcription", "transport": "gateway-relay", "audio": { "inputEncoding": "g711_ulaw", "inputSampleRateHz": 8000 }, "brain": "none" }This confirms the expected X Premium / xAI OAuth state path works independently of the full local plugin set. The original failure is provider resolution under an already-active provider registry, not missing xAI credentials or an incorrect Voice Call config shape.
Behavior Changes Beyond the Fix
These are deliberate behavior changes that go beyond the narrow xAI session-resolution bug. Calling them out explicitly so maintainers can accept them consciously:
Speech provider request collection filters
models.providerskeys to resolvable speech providers.collectRequestedSpeechProviderIdspreviously added everymodels.providerskey (chat-model providers such asanthropic) to the speech cold-load request set, which polluted the requested scope. It now keeps only the keys that resolve to a speech-provider plugin through manifest contracts, so shared model-provider auth such asmodels.providers.google.apiKey(Google TTS) stays requested and cold-loadable under a partial active speech registry, while unrelated chat model providers likeanthropicare excluded.Talk now reads
plugins.entries["@openclaw/voice-call"]streaming config. The scoped package entry id was previously ignored by Talk (onlyvoice-callwas read), while doctor/update tooling already treats both ids as the same plugin. Precedence when both entries define streaming config: the scoped entry'sproviderwins, andprovidersmaps are merged per key with the scoped entry overriding. A scoped entry withenabled: falseis ignored, so stale disabled scoped config cannot override an enabled legacy entry; the legacyvoice-callentry keeps its pre-existing read-regardless semantics. Impact: installs that still carry a stale scoped entry alongside the unscoped one can see the scoped values drive transcription provider selection after upgrade. Therealtimesection intentionally still reads onlyvoice-callso the realtime catalog does not advertise an active provider it cannot list.requestedProviderIdson the shared capability resolver is additive-only. With an active registry it cold-loads requested providers the registry is missing and merges them in; with no active registry the load stays unscoped. Requested ids never narrow which providers are visible, soautoSelectOrderfallback keeps seeing every installed provider.