mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 03:44:31 +00:00
chore: Run pnpm format:fix.
This commit is contained in:
@@ -50,9 +50,7 @@ export class MockProvider implements VoiceCallProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private normalizeEvent(
|
||||
evt: Partial<NormalizedEvent>,
|
||||
): NormalizedEvent | null {
|
||||
private normalizeEvent(evt: Partial<NormalizedEvent>): NormalizedEvent | null {
|
||||
if (!evt.type || !evt.callId) return null;
|
||||
|
||||
const base = {
|
||||
@@ -96,9 +94,7 @@ export class MockProvider implements VoiceCallProvider {
|
||||
}
|
||||
|
||||
case "call.silence": {
|
||||
const payload = evt as Partial<
|
||||
NormalizedEvent & { durationMs?: number }
|
||||
>;
|
||||
const payload = evt as Partial<NormalizedEvent & { durationMs?: number }>;
|
||||
return {
|
||||
...base,
|
||||
type: evt.type,
|
||||
@@ -116,9 +112,7 @@ export class MockProvider implements VoiceCallProvider {
|
||||
}
|
||||
|
||||
case "call.ended": {
|
||||
const payload = evt as Partial<
|
||||
NormalizedEvent & { reason?: EndReason }
|
||||
>;
|
||||
const payload = evt as Partial<NormalizedEvent & { reason?: EndReason }>;
|
||||
return {
|
||||
...base,
|
||||
type: evt.type,
|
||||
@@ -127,9 +121,7 @@ export class MockProvider implements VoiceCallProvider {
|
||||
}
|
||||
|
||||
case "call.error": {
|
||||
const payload = evt as Partial<
|
||||
NormalizedEvent & { error?: string; retryable?: boolean }
|
||||
>;
|
||||
const payload = evt as Partial<NormalizedEvent & { error?: string; retryable?: boolean }>;
|
||||
return {
|
||||
...base,
|
||||
type: evt.type,
|
||||
|
||||
@@ -103,8 +103,7 @@ export class PlivoProvider implements VoiceCallProvider {
|
||||
}
|
||||
|
||||
parseWebhookEvent(ctx: WebhookContext): ProviderWebhookParseResult {
|
||||
const flow =
|
||||
typeof ctx.query?.flow === "string" ? ctx.query.flow.trim() : "";
|
||||
const flow = typeof ctx.query?.flow === "string" ? ctx.query.flow.trim() : "";
|
||||
|
||||
const parsed = this.parseBody(ctx.rawBody);
|
||||
if (!parsed) {
|
||||
@@ -139,9 +138,7 @@ export class PlivoProvider implements VoiceCallProvider {
|
||||
|
||||
if (flow === "xml-listen") {
|
||||
const callId = this.getCallIdFromQuery(ctx);
|
||||
const pending = callId
|
||||
? this.pendingListenByCallId.get(callId)
|
||||
: undefined;
|
||||
const pending = callId ? this.pendingListenByCallId.get(callId) : undefined;
|
||||
if (callId) this.pendingListenByCallId.delete(callId);
|
||||
|
||||
const actionUrl = this.buildActionUrl(ctx, {
|
||||
@@ -180,10 +177,7 @@ export class PlivoProvider implements VoiceCallProvider {
|
||||
};
|
||||
}
|
||||
|
||||
private normalizeEvent(
|
||||
params: URLSearchParams,
|
||||
callIdOverride?: string,
|
||||
): NormalizedEvent | null {
|
||||
private normalizeEvent(params: URLSearchParams, callIdOverride?: string): NormalizedEvent | null {
|
||||
const callUuid = params.get("CallUUID") || "";
|
||||
const requestUuid = params.get("RequestUUID") || "";
|
||||
|
||||
@@ -329,11 +323,9 @@ export class PlivoProvider implements VoiceCallProvider {
|
||||
}
|
||||
|
||||
async playTts(input: PlayTtsInput): Promise<void> {
|
||||
const callUuid = this.requestUuidToCallUuid.get(input.providerCallId) ??
|
||||
input.providerCallId;
|
||||
const callUuid = this.requestUuidToCallUuid.get(input.providerCallId) ?? input.providerCallId;
|
||||
const webhookBase =
|
||||
this.callUuidToWebhookUrl.get(callUuid) ||
|
||||
this.callIdToWebhookUrl.get(input.callId);
|
||||
this.callUuidToWebhookUrl.get(callUuid) || this.callIdToWebhookUrl.get(input.callId);
|
||||
if (!webhookBase) {
|
||||
throw new Error("Missing webhook URL for this call (provider state missing)");
|
||||
}
|
||||
@@ -364,11 +356,9 @@ export class PlivoProvider implements VoiceCallProvider {
|
||||
}
|
||||
|
||||
async startListening(input: StartListeningInput): Promise<void> {
|
||||
const callUuid = this.requestUuidToCallUuid.get(input.providerCallId) ??
|
||||
input.providerCallId;
|
||||
const callUuid = this.requestUuidToCallUuid.get(input.providerCallId) ?? input.providerCallId;
|
||||
const webhookBase =
|
||||
this.callUuidToWebhookUrl.get(callUuid) ||
|
||||
this.callIdToWebhookUrl.get(input.callId);
|
||||
this.callUuidToWebhookUrl.get(callUuid) || this.callIdToWebhookUrl.get(input.callId);
|
||||
if (!webhookBase) {
|
||||
throw new Error("Missing webhook URL for this call (provider state missing)");
|
||||
}
|
||||
@@ -427,10 +417,7 @@ export class PlivoProvider implements VoiceCallProvider {
|
||||
</Response>`;
|
||||
}
|
||||
|
||||
private static xmlGetInputSpeech(params: {
|
||||
actionUrl: string;
|
||||
language?: string;
|
||||
}): string {
|
||||
private static xmlGetInputSpeech(params: { actionUrl: string; language?: string }): string {
|
||||
const language = params.language || "en-US";
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Response>
|
||||
|
||||
@@ -183,9 +183,7 @@ class OpenAIRealtimeSTTSession implements RealtimeSTTSession {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
this.reconnectAttempts >= OpenAIRealtimeSTTSession.MAX_RECONNECT_ATTEMPTS
|
||||
) {
|
||||
if (this.reconnectAttempts >= OpenAIRealtimeSTTSession.MAX_RECONNECT_ATTEMPTS) {
|
||||
console.error(
|
||||
`[RealtimeSTT] Max reconnect attempts (${OpenAIRealtimeSTTSession.MAX_RECONNECT_ATTEMPTS}) reached`,
|
||||
);
|
||||
@@ -193,9 +191,7 @@ class OpenAIRealtimeSTTSession implements RealtimeSTTSession {
|
||||
}
|
||||
|
||||
this.reconnectAttempts++;
|
||||
const delay =
|
||||
OpenAIRealtimeSTTSession.RECONNECT_DELAY_MS *
|
||||
2 ** (this.reconnectAttempts - 1);
|
||||
const delay = OpenAIRealtimeSTTSession.RECONNECT_DELAY_MS * 2 ** (this.reconnectAttempts - 1);
|
||||
console.log(
|
||||
`[RealtimeSTT] Reconnecting ${this.reconnectAttempts}/${OpenAIRealtimeSTTSession.MAX_RECONNECT_ATTEMPTS} in ${delay}ms...`,
|
||||
);
|
||||
|
||||
@@ -161,9 +161,7 @@ export class TelnyxProvider implements VoiceCallProvider {
|
||||
let callId = "";
|
||||
if (data.payload?.client_state) {
|
||||
try {
|
||||
callId = Buffer.from(data.payload.client_state, "base64").toString(
|
||||
"utf8",
|
||||
);
|
||||
callId = Buffer.from(data.payload.client_state, "base64").toString("utf8");
|
||||
} catch {
|
||||
// Fallback if not valid Base64
|
||||
callId = data.payload.client_state;
|
||||
@@ -312,13 +310,10 @@ export class TelnyxProvider implements VoiceCallProvider {
|
||||
* Start transcription (STT) via Telnyx.
|
||||
*/
|
||||
async startListening(input: StartListeningInput): Promise<void> {
|
||||
await this.apiRequest(
|
||||
`/calls/${input.providerCallId}/actions/transcription_start`,
|
||||
{
|
||||
command_id: crypto.randomUUID(),
|
||||
language: input.language || "en",
|
||||
},
|
||||
);
|
||||
await this.apiRequest(`/calls/${input.providerCallId}/actions/transcription_start`, {
|
||||
command_id: crypto.randomUUID(),
|
||||
language: input.language || "en",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -84,9 +84,7 @@ export class OpenAITTSProvider {
|
||||
this.instructions = config.instructions;
|
||||
|
||||
if (!this.apiKey) {
|
||||
throw new Error(
|
||||
"OpenAI API key required (set OPENAI_API_KEY or pass apiKey)",
|
||||
);
|
||||
throw new Error("OpenAI API key required (set OPENAI_API_KEY or pass apiKey)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,11 +213,7 @@ function linearToMulaw(sample: number): number {
|
||||
// Add bias and find segment
|
||||
sample += BIAS;
|
||||
let exponent = 7;
|
||||
for (
|
||||
let expMask = 0x4000;
|
||||
(sample & expMask) === 0 && exponent > 0;
|
||||
exponent--, expMask >>= 1
|
||||
) {
|
||||
for (let expMask = 0x4000; (sample & expMask) === 0 && exponent > 0; exponent--, expMask >>= 1) {
|
||||
// Find the segment (exponent)
|
||||
}
|
||||
|
||||
@@ -252,10 +246,7 @@ export function mulawToLinear(mulaw: number): number {
|
||||
* Chunk audio buffer into 20ms frames for streaming.
|
||||
* At 8kHz mono, 20ms = 160 samples = 160 bytes (mu-law).
|
||||
*/
|
||||
export function chunkAudio(
|
||||
audio: Buffer,
|
||||
chunkSize = 160,
|
||||
): Generator<Buffer, void, unknown> {
|
||||
export function chunkAudio(audio: Buffer, chunkSize = 160): Generator<Buffer, void, unknown> {
|
||||
return (function* () {
|
||||
for (let i = 0; i < audio.length; i += chunkSize) {
|
||||
yield audio.subarray(i, Math.min(i + chunkSize, audio.length));
|
||||
|
||||
@@ -12,10 +12,7 @@ function createProvider(): TwilioProvider {
|
||||
);
|
||||
}
|
||||
|
||||
function createContext(
|
||||
rawBody: string,
|
||||
query?: WebhookContext["query"],
|
||||
): WebhookContext {
|
||||
function createContext(rawBody: string, query?: WebhookContext["query"]): WebhookContext {
|
||||
return {
|
||||
headers: {},
|
||||
rawBody,
|
||||
|
||||
@@ -211,22 +211,16 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
/**
|
||||
* Parse Twilio direction to normalized format.
|
||||
*/
|
||||
private static parseDirection(
|
||||
direction: string | null,
|
||||
): "inbound" | "outbound" | undefined {
|
||||
private static parseDirection(direction: string | null): "inbound" | "outbound" | undefined {
|
||||
if (direction === "inbound") return "inbound";
|
||||
if (direction === "outbound-api" || direction === "outbound-dial")
|
||||
return "outbound";
|
||||
if (direction === "outbound-api" || direction === "outbound-dial") return "outbound";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert Twilio webhook params to normalized event format.
|
||||
*/
|
||||
private normalizeEvent(
|
||||
params: URLSearchParams,
|
||||
callIdOverride?: string,
|
||||
): NormalizedEvent | null {
|
||||
private normalizeEvent(params: URLSearchParams, callIdOverride?: string): NormalizedEvent | null {
|
||||
const callSid = params.get("CallSid") || "";
|
||||
|
||||
const baseEvent = {
|
||||
@@ -300,8 +294,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
if (!ctx) return TwilioProvider.EMPTY_TWIML;
|
||||
|
||||
const params = new URLSearchParams(ctx.rawBody);
|
||||
const type =
|
||||
typeof ctx.query?.type === "string" ? ctx.query.type.trim() : undefined;
|
||||
const type = typeof ctx.query?.type === "string" ? ctx.query.type.trim() : undefined;
|
||||
const isStatusCallback = type === "status";
|
||||
const callStatus = params.get("CallStatus");
|
||||
const direction = params.get("Direction");
|
||||
@@ -329,9 +322,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
// Conversation mode: return streaming TwiML immediately for outbound calls.
|
||||
if (isOutbound) {
|
||||
const streamUrl = this.getStreamUrl();
|
||||
return streamUrl
|
||||
? this.getStreamConnectXml(streamUrl)
|
||||
: TwilioProvider.PAUSE_TWIML;
|
||||
return streamUrl ? this.getStreamConnectXml(streamUrl) : TwilioProvider.PAUSE_TWIML;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,9 +335,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
// For inbound calls, answer immediately with stream
|
||||
if (direction === "inbound") {
|
||||
const streamUrl = this.getStreamUrl();
|
||||
return streamUrl
|
||||
? this.getStreamConnectXml(streamUrl)
|
||||
: TwilioProvider.PAUSE_TWIML;
|
||||
return streamUrl ? this.getStreamConnectXml(streamUrl) : TwilioProvider.PAUSE_TWIML;
|
||||
}
|
||||
|
||||
// For outbound calls, only connect to stream when call is in-progress
|
||||
@@ -355,9 +344,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
}
|
||||
|
||||
const streamUrl = this.getStreamUrl();
|
||||
return streamUrl
|
||||
? this.getStreamConnectXml(streamUrl)
|
||||
: TwilioProvider.PAUSE_TWIML;
|
||||
return streamUrl ? this.getStreamConnectXml(streamUrl) : TwilioProvider.PAUSE_TWIML;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,9 +361,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
const origin = url.origin;
|
||||
|
||||
// Convert https:// to wss:// for WebSocket
|
||||
const wsOrigin = origin
|
||||
.replace(/^https:\/\//, "wss://")
|
||||
.replace(/^http:\/\//, "ws://");
|
||||
const wsOrigin = origin.replace(/^https:\/\//, "wss://").replace(/^http:\/\//, "ws://");
|
||||
|
||||
// Append the stream path
|
||||
const path = this.options.streamPath.startsWith("/")
|
||||
@@ -433,10 +418,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
Timeout: "30",
|
||||
};
|
||||
|
||||
const result = await this.apiRequest<TwilioCallResponse>(
|
||||
"/Calls.json",
|
||||
params,
|
||||
);
|
||||
const result = await this.apiRequest<TwilioCallResponse>("/Calls.json", params);
|
||||
|
||||
this.callWebhookUrls.set(result.sid, url.toString());
|
||||
|
||||
@@ -489,9 +471,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
// Fall back to TwiML <Say> (may not work on all accounts)
|
||||
const webhookUrl = this.callWebhookUrls.get(input.providerCallId);
|
||||
if (!webhookUrl) {
|
||||
throw new Error(
|
||||
"Missing webhook URL for this call (provider state not initialized)",
|
||||
);
|
||||
throw new Error("Missing webhook URL for this call (provider state not initialized)");
|
||||
}
|
||||
|
||||
console.warn(
|
||||
@@ -517,10 +497,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
* Generates audio with core TTS, converts to mu-law, and streams via WebSocket.
|
||||
* Uses a queue to serialize playback and prevent overlapping audio.
|
||||
*/
|
||||
private async playTtsViaStream(
|
||||
text: string,
|
||||
streamSid: string,
|
||||
): Promise<void> {
|
||||
private async playTtsViaStream(text: string, streamSid: string): Promise<void> {
|
||||
if (!this.ttsProvider || !this.mediaStreamHandler) {
|
||||
throw new Error("TTS provider and media stream handler required");
|
||||
}
|
||||
@@ -556,9 +533,7 @@ export class TwilioProvider implements VoiceCallProvider {
|
||||
async startListening(input: StartListeningInput): Promise<void> {
|
||||
const webhookUrl = this.callWebhookUrls.get(input.providerCallId);
|
||||
if (!webhookUrl) {
|
||||
throw new Error(
|
||||
"Missing webhook URL for this call (provider state not initialized)",
|
||||
);
|
||||
throw new Error("Missing webhook URL for this call (provider state not initialized)");
|
||||
}
|
||||
|
||||
const twiml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
@@ -9,19 +9,16 @@ export async function twilioApiRequest<T = unknown>(params: {
|
||||
const bodyParams =
|
||||
params.body instanceof URLSearchParams
|
||||
? params.body
|
||||
: Object.entries(params.body).reduce<URLSearchParams>(
|
||||
(acc, [key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
for (const entry of value) {
|
||||
acc.append(key, entry);
|
||||
}
|
||||
} else if (typeof value === "string") {
|
||||
acc.append(key, value);
|
||||
: Object.entries(params.body).reduce<URLSearchParams>((acc, [key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
for (const entry of value) {
|
||||
acc.append(key, entry);
|
||||
}
|
||||
return acc;
|
||||
},
|
||||
new URLSearchParams(),
|
||||
);
|
||||
} else if (typeof value === "string") {
|
||||
acc.append(key, value);
|
||||
}
|
||||
return acc;
|
||||
}, new URLSearchParams());
|
||||
|
||||
const response = await fetch(`${params.baseUrl}${params.endpoint}`, {
|
||||
method: "POST",
|
||||
|
||||
@@ -11,8 +11,7 @@ export function verifyTwilioProviderWebhook(params: {
|
||||
}): WebhookVerificationResult {
|
||||
const result = verifyTwilioWebhook(params.ctx, params.authToken, {
|
||||
publicUrl: params.currentPublicUrl || undefined,
|
||||
allowNgrokFreeTierLoopbackBypass:
|
||||
params.options.allowNgrokFreeTierLoopbackBypass ?? false,
|
||||
allowNgrokFreeTierLoopbackBypass: params.options.allowNgrokFreeTierLoopbackBypass ?? false,
|
||||
skipVerification: params.options.skipVerification,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user