惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
WordPress大学
WordPress大学
U
Unit 42
I
InfoQ
A
About on SuperTechFans
宝玉的分享
宝玉的分享
J
Java Code Geeks
博客园 - 司徒正美
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
G
Google Developers Blog
人人都是产品经理
人人都是产品经理
小众软件
小众软件
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Hugging Face - Blog
Hugging Face - Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
aimingoo的专栏
aimingoo的专栏
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
腾讯CDC
Recent Announcements
Recent Announcements

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
feat: add Telnyx Media Streaming for voice-call realtime ...
dynamite-bud · 2026-05-12 · via Recent Commits to openclaw:main

@@ -208,6 +208,23 @@ export class TelnyxProvider implements VoiceCallProvider {

208208

digits: data.payload?.digit || "",

209209

};

210210211+

case "call.streaming.started":

212+

case "call.streaming.stopped":

213+

// Informational. The realtime bridge tracks its own lifecycle via the

214+

// WebSocket; we acknowledge the webhook (200) but skip event emission

215+

// to avoid duplicate signal at the manager.

216+

return null;

217+218+

case "call.streaming.failed": {

219+

const reason = typeof data.payload?.reason === "string" ? data.payload.reason : undefined;

220+

return {

221+

...baseEvent,

222+

type: "call.error",

223+

error: `Telnyx streaming failed${reason ? `: ${reason}` : ""}`,

224+

retryable: false,

225+

};

226+

}

227+211228

default:

212229

return null;

213230

}

@@ -251,18 +268,24 @@ export class TelnyxProvider implements VoiceCallProvider {

251268

}

252269253270

/**

254-

* Initiate an outbound call via Telnyx API.

271+

* Initiate an outbound call via Telnyx API. When `input.streamUrl` is set,

272+

* the dial payload also opens a bidirectional Media Streaming session on

273+

* answer (PCMU 8 kHz), per the Telnyx documented "AI agent" pattern.

255274

*/

256275

async initiateCall(input: InitiateCallInput): Promise<InitiateCallResult> {

257-

const result = await this.apiRequest<TelnyxCallResponse>("/calls", {

276+

const body: Record<string, unknown> = {

258277

connection_id: this.connectionId,

259278

to: input.to,

260279

from: input.from,

261280

webhook_url: input.webhookUrl,

262281

webhook_url_method: "POST",

263282

client_state: Buffer.from(input.callId).toString("base64"),

264283

timeout_secs: 30,

265-

});

284+

...(input.streamUrl

285+

? buildTelnyxStreamingFields(input.streamUrl, input.streamAuthToken)

286+

: {}),

287+

};

288+

const result = await this.apiRequest<TelnyxCallResponse>("/calls", body);

266289267290

return {

268291

providerCallId: result.data.call_control_id,

@@ -282,12 +305,18 @@ export class TelnyxProvider implements VoiceCallProvider {

282305

}

283306284307

/**

285-

* Answer an inbound Telnyx Call Control leg.

308+

* Answer an inbound Telnyx Call Control leg. When `input.streamUrl` is set,

309+

* the answer action also attaches a bidirectional Media Streaming session

310+

* (PCMU 8 kHz), per the Telnyx canonical "answer-action inline" pattern.

286311

*/

287312

async answerCall(input: AnswerCallInput): Promise<void> {

288-

await this.apiRequest(`/calls/${input.providerCallId}/actions/answer`, {

313+

const body: Record<string, unknown> = {

289314

command_id: `openclaw-answer-${input.callId}`,

290-

});

315+

...(input.streamUrl

316+

? buildTelnyxStreamingFields(input.streamUrl, input.streamAuthToken)

317+

: {}),

318+

};

319+

await this.apiRequest(`/calls/${input.providerCallId}/actions/answer`, body);

291320

}

292321293322

/**

@@ -355,6 +384,28 @@ export class TelnyxProvider implements VoiceCallProvider {

355384

}

356385

}

357386387+

/**

388+

* Build the streaming-related fields for a Telnyx dial or answer-action

389+

* payload. PCMU 8 kHz mono only; bidirectional via RTP; target legs `"self"`

390+

* so the bot receives both inbound and outbound audio without the routing

391+

* gotcha that drops the call leg when `"opposite"` is configured.

392+

*/

393+

function buildTelnyxStreamingFields(

394+

streamUrl: string,

395+

streamAuthToken: string | undefined,

396+

): Record<string, unknown> {

397+

return {

398+

stream_url: streamUrl,

399+

stream_track: "inbound_track",

400+

stream_codec: "PCMU",

401+

stream_bidirectional_mode: "rtp",

402+

stream_bidirectional_codec: "PCMU",

403+

stream_bidirectional_sampling_rate: 8000,

404+

stream_bidirectional_target_legs: "self",

405+

...(streamAuthToken ? { stream_auth_token: streamAuthToken } : {}),

406+

};

407+

}

408+358409

// -----------------------------------------------------------------------------

359410

// Telnyx-specific types

360411

// -----------------------------------------------------------------------------