refactor(voice-call): reuse webhook path normalization (#99766)

This commit is contained in:
Dallin Romney
2026-07-04 10:53:07 -07:00
committed by GitHub
parent 3d3a29413a
commit d96db362bd
4 changed files with 10 additions and 36 deletions
+2 -2
View File
@@ -11,10 +11,10 @@ import {
canonicalizeMainSessionAlias,
type SessionScope,
} from "openclaw/plugin-sdk/session-store-runtime";
import { normalizeWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
import { z } from "zod";
import { TtsConfigSchema } from "../api.js";
import { deepMergeDefined } from "./deep-merge.js";
import { normalizePath } from "./path-utils.js";
import { DEFAULT_VOICE_CALL_REALTIME_INSTRUCTIONS } from "./realtime-defaults.js";
// -----------------------------------------------------------------------------
@@ -528,7 +528,7 @@ function cloneDefaultVoiceCallConfig(): VoiceCallConfig {
}
function defaultRealtimeStreamPathForServePath(servePath: string): string {
const normalized = normalizePath(servePath);
const normalized = normalizeWebhookPath(servePath);
if (normalized.endsWith("/webhook")) {
return `${normalized.slice(0, -"/webhook".length)}/stream/realtime`;
}
-12
View File
@@ -1,12 +0,0 @@
// Voice Call plugin module implements shared path normalization.
export function normalizePath(pathname: string): string {
const trimmed = pathname.trim();
if (!trimmed) {
return "/";
}
const prefixed = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
if (prefixed === "/") {
return prefixed;
}
return prefixed.endsWith("/") ? prefixed.slice(0, -1) : prefixed;
}
+4 -18
View File
@@ -15,6 +15,7 @@ import {
} from "openclaw/plugin-sdk/string-coerce-runtime";
import {
createWebhookInFlightLimiter,
normalizeWebhookPath,
WEBHOOK_BODY_READ_DEFAULTS,
} from "openclaw/plugin-sdk/webhook-ingress";
import {
@@ -631,23 +632,8 @@ export class VoiceCallWebhookServer {
}
}
private normalizeWebhookPathForMatch(pathname: string): string {
const trimmed = pathname.trim();
if (!trimmed) {
return "/";
}
const prefixed = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
if (prefixed === "/") {
return prefixed;
}
return prefixed.endsWith("/") ? prefixed.slice(0, -1) : prefixed;
}
private isWebhookPathMatch(requestPath: string, configuredPath: string): boolean {
return (
this.normalizeWebhookPathForMatch(requestPath) ===
this.normalizeWebhookPathForMatch(configuredPath)
);
return normalizeWebhookPath(requestPath) === normalizeWebhookPath(configuredPath);
}
/**
@@ -913,8 +899,8 @@ export class VoiceCallWebhookServer {
if (!pattern) {
return false;
}
const normalizedPattern = this.normalizeWebhookPathForMatch(pattern);
const normalizedPathname = this.normalizeWebhookPathForMatch(pathname);
const normalizedPattern = normalizeWebhookPath(pattern);
const normalizedPathname = normalizeWebhookPath(pathname);
if (normalizedPattern === "/") {
return true;
}
@@ -28,10 +28,10 @@ import {
} from "openclaw/plugin-sdk/realtime-voice";
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
import { normalizeWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
import WebSocket, { WebSocketServer } from "ws";
import type { VoiceCallRealtimeConfig } from "../config.js";
import type { CallManager } from "../manager.js";
import { normalizePath } from "../path-utils.js";
import type { VoiceCallProvider } from "../providers/base.js";
import type { CallRecord, NormalizedEvent } from "../types.js";
import type { WebhookResponsePayload } from "../webhook.types.js";
@@ -318,8 +318,8 @@ export class RealtimeCallHandler {
try {
const parsed = new URL(url);
this.publicOrigin = parsed.host;
const normalizedServePath = normalizePath(this.servePath);
const normalizedPublicPath = normalizePath(parsed.pathname);
const normalizedServePath = normalizeWebhookPath(this.servePath);
const normalizedPublicPath = normalizeWebhookPath(parsed.pathname);
const idx = normalizedPublicPath.indexOf(normalizedServePath);
this.publicPathPrefix = idx > 0 ? normalizedPublicPath.slice(0, idx) : "";
} catch {
@@ -329,7 +329,7 @@ export class RealtimeCallHandler {
}
getStreamPathPattern(): string {
return `${this.publicPathPrefix}${normalizePath(this.config.streamPath ?? "/voice/stream/realtime")}`;
return `${this.publicPathPrefix}${normalizeWebhookPath(this.config.streamPath ?? "/voice/stream/realtime")}`;
}
buildTwiMLPayload(req: http.IncomingMessage, params?: URLSearchParams): WebhookResponsePayload {