Skip to content

VAPI-3989: map Twilio Stream <Parameter> children to StreamParam - #28

Open
mramasubramanian-bw wants to merge 1 commit into
mainfrom
VAPI-3989/stream-parameter-to-streamparam
Open

mramasubramanian-bw wants to merge 1 commit into
mainfrom
VAPI-3989/stream-parameter-to-streamparam

Conversation

@mramasubramanian-bw

Copy link
Copy Markdown
Contributor

Summary

Twilio bots attach key/value context to a media stream with <Parameter> children on <Stream>. That is how most bots receive callSid, tenant, and similar values when the WebSocket opens. The translator read only the <Stream> attributes and ignored its children, so a Stream with two Parameters produced byte-identical BXML to one with none, no finding was raised, and the bot connected with an empty customParameters map.

Each <Parameter name value/> now becomes a nested <StreamParam name value/> under the emitted <StartStream>, in order. Bandwidth echoes those in its WebSocket start event as streamParams, and a new bridge helper maps that to the Twilio customParameters the bot expects.

Changes

Translator (src/translator/translate.ts)

  • <Parameter> children map to nested <StreamParam/> for both Connect (bidirectional) and Start (fork) streams. Values are XML-escaped by the builder.
  • Bandwidth allows at most 12 StreamParam per StartStream. Extras are dropped with a Stream warning that names the count. Twilio caps name plus value at 500 characters combined, so Bandwidth's 256 / 2048 per-attribute limits cannot be exceeded by valid TwiML and are not re-checked.
  • A <Parameter> missing name or value, or any non-Parameter child, is dropped with a warning instead of emitting BXML Bandwidth would reject.

Bridge (src/streams/bridge.ts)

  • New customParametersFromBwStart() maps Bandwidth's start event (streamParams, a flat name to value map) to the Twilio customParameters map the bridge already forwards in its own start message. Values are coerced to strings and malformed input yields an empty object.
  • Wiring a live Bandwidth source that calls it is VAPI-3991.

Docs: Stream matrix note and AGENTS.md.

Before / after

Input:

<Response><Connect><Stream url="wss://bot.test/ws">
  <Parameter name="callSid" value="CA123"/>
  <Parameter name="tenant" value="acme"/>
</Stream></Connect></Response>

Before:

<Response><StartStream name="connect-stream-1" destination="wss://bot.test/ws" mode="bidirectional" tracks="inbound"/><StopStream name="connect-stream-1" wait="true"/></Response>

After:

<Response><StartStream name="connect-stream-1" destination="wss://bot.test/ws" mode="bidirectional" tracks="inbound"><StreamParam name="callSid" value="CA123"/><StreamParam name="tenant" value="acme"/></StartStream><StopStream name="connect-stream-1" wait="true"/></Response>

Verification

  • npm run typecheck && npx vitest run: 44 files, 315 passed, 6 skipped.
  • New tests in test/translate-stream-conference.test.ts cover ordering, nesting inside StartStream, the fork case, escaping, the 12 cap, invalid Parameters, and unknown children.
  • New tests in test/streams-wire.test.ts push a Bandwidth-shaped start event through the mapper and assert the bot receives it as customParameters.

Reference: StartStream docs, StreamParam.

Twilio bots attach key/value context to a media stream with <Parameter>
children on <Stream>; that is how most bots receive callSid, tenant, and
similar values when the WebSocket opens. The translator read only the
<Stream> attributes and ignored its children, so a Stream with two
Parameters produced byte-identical BXML to one with none, no finding was
raised, and the bot connected with an empty customParameters map.

Translator:
- Each <Parameter name value/> becomes a nested <StreamParam name value/>
  under the emitted <StartStream>, in order, for both Connect (bidirectional)
  and Start (fork) streams. Attribute values are XML-escaped by the builder.
- Bandwidth allows at most 12 StreamParam per StartStream; extras are
  dropped with a Stream warning naming the count. Twilio caps name+value at
  500 chars combined, so Bandwidth's 256/2048 per-attribute limits cannot
  be exceeded by valid TwiML and are not re-checked.
- A <Parameter> missing name or value, or any non-Parameter child, is
  dropped with a warning instead of emitting BXML Bandwidth would reject.

Bridge:
- Add customParametersFromBwStart(), which maps Bandwidth's StartStream
  "start" event (streamParams: flat name->value map) to the Twilio
  customParameters map the bridge already forwards in its own "start"
  message. Values are coerced to strings; malformed input yields {}.
  Wiring a live Bandwidth source that calls it is VAPI-3991.

Docs: update the Stream matrix note and AGENTS.md. Tests cover ordering,
nesting inside StartStream, the fork case, escaping, the 12 cap, invalid
Parameters, unknown children, and the bridge mapper end to end.
@mramasubramanian-bw
mramasubramanian-bw requested review from a team as code owners September 22, 2026 00:01
@bwappsec

bwappsec commented Sep 22, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

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.

2 participants