fix(telephony): inbound + handoff metadata parity (Plivo extra_headers, Telnyx client_state)#180
Merged
Merged
Conversation
…s, Telnyx client_state)
Two parity bugs in how call context flows through the telephony layer:
- Plivo extra_headers were parsed only for caller/callee recovery and
otherwise dropped, so resolve_agent_prompt and on_call_start both got an
empty custom_params and {placeholder} variables from inbound metadata never
resolved on Plivo calls. Now parsed unconditionally and forwarded as
custom_params (X-PH-caller/X-PH-callee re-exposed as caller/callee),
mirroring Twilio's <Parameter> channel. The TS Plivo bridge never read
extra_headers at all; it now passes the same customParams to handleCallStart
(new parsePlivoExtraHeaders / plivoInboundCustomParams helpers).
- Telnyx transfer client_state was implemented at the adapter layer but
unreachable (no public option fed it). Exposed as an opt-in clientState on
the programmatic transfer surface (CallControl.transfer /
TransferCallOptions -> TelnyxBridge.transferCall), base64-encoded into the
transfer body so context survives a handoff. Optional with no default ->
cold-transfer body stays byte-identical; Twilio/Plivo ignore it; the LLM
transfer_call tool schema is unchanged.
Both SDKs, with authentic tests (real start-frame parse, real prompt
resolution, carrier REST mocked only at the fetch/httpx boundary).
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
Implementation
extra_headers→ prompt +on_call_start(Fixed). Headers on the Plivostartframe were parsed only for caller/callee recovery and otherwise dropped, soresolve_agent_promptandon_call_startboth received an emptycustom_params—{placeholder}variables sourced from inbound metadata never resolved on Plivo. Now parsed unconditionally and forwarded ascustom_params(internalX-PH-caller/X-PH-calleemarkers re-exposed ascaller/callee), matching Twilio's<Parameter>channel. The TypeScript Plivo bridge never readextra_headersat all; it now passes the samecustomParamsintohandleCallStart.libraries/python/getpatter/telephony/plivo.pylibraries/typescript/src/providers/plivo-adapter.ts(newparsePlivoExtraHeaders/plivoInboundCustomParams),libraries/typescript/src/server.tsclient_state(Added, opt-in). The capability existed at the adapter layer in both SDKs but was unreachable (no public option fed it). Exposed as an opt-inclient_state/clientStateon the programmatic transfer surface (CallControl.transfer/TransferCallOptions→TelnyxBridge.transferCall), base64-encoded into the transfer body so call context can survive a handoff. Optional with no default → the cold-transfer request body stays byte-identical for callers that don't set it; Twilio/Plivo ignore it; the LLMtransfer_calltool schema is unchanged (an opaque state string is a developer concern, not an LLM one).libraries/python/getpatter/models.py(CallControl.transfer,_invoke_transfer_fn)libraries/typescript/src/types.ts(TransferCallOptions),libraries/typescript/src/server.ts(TelnyxBridge.transferCall)Breaking change?
No. Both changes are opt-in and backward compatible: Plivo behaviour only gains previously-dropped data; the new
clientStatetransfer option is optional with no default, so the cold-transfer request body is byte-identical when unset.Test plan
pytest tests/— 2664 passed, 8 skipped, 2 xfailednpm test(2112 passed, 9 skipped) +npm run lint(clean) +npm run build(success)Tests are authentic: real Plivo
start-frame parsing, real prompt resolution, carrier REST mocked only at thefetch/httpxboundary. Added:test_plivo_handler_unit.py,test_warm_transfer_unit.py(Python);plivo.test.ts,warm-transfer.mocked.test.ts(TypeScript).Docs updates
N/A in this PR (the new opt-in
clientStatetransfer option could get a one-line mention in the transfer docs as a follow-up).