mirror of
https://github.com/moltbot/moltbot.git
synced 2026-03-21 16:41:56 +00:00
fix(voice-call): accept externally-initiated Twilio outbound-api calls
Fixes #30900 — Calls initiated directly via the Twilio REST API (Direction=outbound-api) were rejected as "unknown call" because processEvent only auto-registered calls with direction=inbound. External outbound-api calls now get registered in the CallManager so the media stream is accepted. Inbound policy checks still only apply to true inbound calls. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
a5b81d1c13
commit
a1b4a0066b
@@ -235,6 +235,50 @@ describe("processEvent (functional)", () => {
|
||||
expect(ctx.activeCalls.size).toBe(0);
|
||||
});
|
||||
|
||||
it("auto-registers externally-initiated outbound-api calls", () => {
|
||||
const ctx = createContext();
|
||||
const event: NormalizedEvent = {
|
||||
id: "evt-external-1",
|
||||
type: "call.initiated",
|
||||
callId: "CA-external-123",
|
||||
providerCallId: "CA-external-123",
|
||||
timestamp: Date.now(),
|
||||
direction: "outbound",
|
||||
from: "+15550000000",
|
||||
to: "+15559876543",
|
||||
};
|
||||
|
||||
processEvent(ctx, event);
|
||||
|
||||
// Call should be registered in activeCalls and providerCallIdMap
|
||||
expect(ctx.activeCalls.size).toBe(1);
|
||||
expect(ctx.providerCallIdMap.get("CA-external-123")).toBeDefined();
|
||||
const call = [...ctx.activeCalls.values()][0];
|
||||
expect(call?.providerCallId).toBe("CA-external-123");
|
||||
expect(call?.from).toBe("+15550000000");
|
||||
expect(call?.to).toBe("+15559876543");
|
||||
});
|
||||
|
||||
it("does not reject externally-initiated outbound calls even with disabled inbound policy", () => {
|
||||
const { ctx, hangupCalls } = createRejectingInboundContext();
|
||||
const event: NormalizedEvent = {
|
||||
id: "evt-external-2",
|
||||
type: "call.initiated",
|
||||
callId: "CA-external-456",
|
||||
providerCallId: "CA-external-456",
|
||||
timestamp: Date.now(),
|
||||
direction: "outbound",
|
||||
from: "+15550000000",
|
||||
to: "+15559876543",
|
||||
};
|
||||
|
||||
processEvent(ctx, event);
|
||||
|
||||
// External outbound calls bypass inbound policy — they should be accepted
|
||||
expect(ctx.activeCalls.size).toBe(1);
|
||||
expect(hangupCalls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("deduplicates by dedupeKey even when event IDs differ", () => {
|
||||
const now = Date.now();
|
||||
const ctx = createContext();
|
||||
|
||||
@@ -104,8 +104,18 @@ export function processEvent(ctx: EventContext, event: NormalizedEvent): void {
|
||||
callIdOrProviderCallId: event.callId,
|
||||
});
|
||||
|
||||
if (!call && event.direction === "inbound" && event.providerCallId) {
|
||||
if (!shouldAcceptInbound(ctx.config, event.from)) {
|
||||
// Auto-register untracked calls arriving via webhook. This covers both
|
||||
// true inbound calls and externally-initiated outbound-api calls (e.g. calls
|
||||
// placed directly via the Twilio REST API pointing at our webhook URL).
|
||||
const isUnregisteredWebhookCall =
|
||||
!call &&
|
||||
event.providerCallId &&
|
||||
(event.direction === "inbound" || event.direction === "outbound");
|
||||
|
||||
if (isUnregisteredWebhookCall) {
|
||||
// Apply inbound policy for true inbound calls; external outbound-api calls
|
||||
// are implicitly trusted because the caller controls the webhook URL.
|
||||
if (event.direction === "inbound" && !shouldAcceptInbound(ctx.config, event.from)) {
|
||||
const pid = event.providerCallId;
|
||||
if (!ctx.provider) {
|
||||
console.warn(
|
||||
|
||||
Reference in New Issue
Block a user