@lawpath-tech/openclaw 2026.2.21-19 → 2026.2.21-20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agents-C9ij96eI.js → agents-C83RLKX2.js} +4 -4
- package/dist/{agents.config-PFAfbBID.js → agents.config-BVjazvnK.js} +1 -1
- package/dist/{agents.config-CBvMKGLh.js → agents.config-dnXbFv5H.js} +1 -1
- package/dist/{audio-preflight-omzaYFGD.js → audio-preflight-CLqoZYgI.js} +4 -4
- package/dist/{audio-preflight-CODznzqu.js → audio-preflight-Da7vejCH.js} +4 -4
- package/dist/{auth-choice-DH2T1E9c.js → auth-choice-BJNaxS-L.js} +1 -1
- package/dist/{auth-choice-CLiY8PdF.js → auth-choice-Hb6530su.js} +1 -1
- package/dist/{banner-CqQBBjKH.js → banner-dFAx4eE_.js} +1 -1
- package/dist/build-info.json +3 -3
- package/dist/bundled/boot-md/handler.js +6 -6
- package/dist/bundled/session-memory/handler.js +6 -6
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/{channel-options-e7Z9Smf2.js → channel-options--M8F-DHl.js} +1 -1
- package/dist/{channel-options-CLS27y1A.js → channel-options-D0Qjq83D.js} +1 -1
- package/dist/{channel-web-DHMbpU2p.js → channel-web-D8hSmcPF.js} +1 -1
- package/dist/{channels-cli-BDHLWbaU.js → channels-cli-6uwOEBM-.js} +4 -4
- package/dist/{channels-cli-CDwQerVi.js → channels-cli-BtZHPcBX.js} +4 -4
- package/dist/{chrome-BAv9fEiv.js → chrome-Bqbv_ZSj.js} +7 -7
- package/dist/{chrome-lRUqqgSD.js → chrome-CZuniMYN.js} +7 -7
- package/dist/{cli-BGJFLB0I.js → cli-CIImVBCM.js} +1 -1
- package/dist/{cli-C1nypCKP.js → cli-CijjdR37.js} +1 -1
- package/dist/{command-registry-pGuORBuB.js → command-registry-BtDC5Ll-.js} +9 -9
- package/dist/{completion-cli-Bf-Ojq_a.js → completion-cli-Bw5nZmTm.js} +2 -2
- package/dist/{completion-cli-C79-bpAx.js → completion-cli-CI6LWHg3.js} +1 -1
- package/dist/{config-cli-DLdH6zIF.js → config-cli-CgjgjWri.js} +1 -1
- package/dist/{config-cli-BcNHb4_E.js → config-cli-Dc0TQ1yE.js} +1 -1
- package/dist/{configure-BSt9S0yk.js → configure-CGqsSqXB.js} +3 -3
- package/dist/{configure-h1d7nrgR.js → configure-GUYUjx8A.js} +3 -3
- package/dist/{deliver-B2d2N8OJ.js → deliver-0ThKlzQo.js} +1 -1
- package/dist/{deliver-CLJRPnfx.js → deliver-CKH_FhS0.js} +1 -1
- package/dist/{doctor-completion-BB1f594d.js → doctor-completion-DgPc1rDZ.js} +1 -1
- package/dist/{doctor-completion-deY10x7w.js → doctor-completion-DipoVPSi.js} +1 -1
- package/dist/entry.js +1 -1
- package/dist/extensionAPI.js +6 -6
- package/dist/{gateway-cli-IziQis2t.js → gateway-cli-Ds3oN72Y.js} +8 -8
- package/dist/{gateway-cli-B-XwzYp2.js → gateway-cli-DuMINk2B.js} +8 -8
- package/dist/{health-DMrTgW8V.js → health-DQjqH1zU.js} +1 -1
- package/dist/{health-UmuJyu1Q.js → health-Dg0bAIKS.js} +1 -1
- package/dist/{hooks-cli-BparoMpt.js → hooks-cli-CEtCwdza.js} +2 -2
- package/dist/{hooks-cli-B6WCYLyG.js → hooks-cli-Cac2Ru8r.js} +2 -2
- package/dist/{image--DDZnw-F.js → image-88q3KE-C.js} +1 -1
- package/dist/{image-Ci28h-op.js → image-CxPjVob-.js} +1 -1
- package/dist/index.js +6 -6
- package/dist/llm-slug-generator.js +6 -6
- package/dist/{models-nhERae29.js → models-DnhANpnd.js} +2 -2
- package/dist/{models-cli-bfKNgoHD.js → models-cli-03noBf8W.js} +3 -3
- package/dist/{models-cli-BnbeEOCU.js → models-cli-CaP_rt4y.js} +2 -2
- package/dist/{onboard-D_VxXTXD.js → onboard-BMc-yUv5.js} +2 -2
- package/dist/{onboard-C3pJ0NU-.js → onboard-BZg2c27h.js} +2 -2
- package/dist/{onboard-channels-CyeyvIfw.js → onboard-channels-Lt2gG1e2.js} +1 -1
- package/dist/{onboard-channels-YvwszRaQ.js → onboard-channels-O6KvizE3.js} +1 -1
- package/dist/{onboarding-0zwx3Yv7.js → onboarding-CTgBlanm.js} +3 -3
- package/dist/{onboarding-D0_Q5m2W.js → onboarding-G28sv5Ms.js} +3 -3
- package/dist/{onboarding.finalize-CYb0_Q0z.js → onboarding.finalize-Cpt9Ymcn.js} +5 -5
- package/dist/{onboarding.finalize-CVeI23_g.js → onboarding.finalize-D2sylHDB.js} +6 -6
- package/dist/{pi-embedded-D7qD6fo-.js → pi-embedded-Dz24QZz9.js} +96 -17
- package/dist/{pi-embedded-CwQsXrVT.js → pi-embedded-ZvazjIyF.js} +96 -17
- package/dist/{pi-embedded-helpers-Cd0S0WfR.js → pi-embedded-helpers-B0Kht0I2.js} +4 -4
- package/dist/{pi-embedded-helpers-Ll4Lztu1.js → pi-embedded-helpers-CSE0v99A.js} +4 -4
- package/dist/{plugin-registry-83ThmVHf.js → plugin-registry-1pF4_jNl.js} +1 -1
- package/dist/{plugin-registry-D57lc9ob.js → plugin-registry-CHOacv01.js} +1 -1
- package/dist/plugin-sdk/{channel-web-XYtgc8aq.js → channel-web-BHNS_E7F.js} +1 -1
- package/dist/plugin-sdk/index.js +2 -2
- package/dist/plugin-sdk/plugins/runtime/types.d.ts +2 -0
- package/dist/plugin-sdk/{reply-BSOpvBX4.js → reply-DEepmBkT.js} +82 -3
- package/dist/plugin-sdk/tts/tts-core.d.ts +15 -0
- package/dist/plugin-sdk/tts/tts.d.ts +16 -0
- package/dist/plugin-sdk/{web-DiLYLsml.js → web-DBo-6RyH.js} +2 -2
- package/dist/{plugins-cli-BymsOcmR.js → plugins-cli-CflNTqmB.js} +2 -2
- package/dist/{plugins-cli-DOWA2F0z.js → plugins-cli-DW0TLzrq.js} +2 -2
- package/dist/{program-T05XIetU.js → program-DUkjf6lq.js} +7 -7
- package/dist/{program-context-CDmctW1L.js → program-context-C0-LzXoV.js} +17 -17
- package/dist/{prompt-select-styled-cR4-U64b.js → prompt-select-styled-CQUE1vow.js} +4 -4
- package/dist/{prompt-select-styled-BbzQhWF7.js → prompt-select-styled-CWNxdPrL.js} +4 -4
- package/dist/{provider-auth-helpers-BbnDoytN.js → provider-auth-helpers-D39L7fZC.js} +1 -1
- package/dist/{provider-auth-helpers-C4RNIRyy.js → provider-auth-helpers-bYUBBkmL.js} +1 -1
- package/dist/{push-apns-Dli4pG4y.js → push-apns-DGIqfAg5.js} +1 -1
- package/dist/{push-apns-DUeNpqyF.js → push-apns-Qfohz-Hs.js} +1 -1
- package/dist/{pw-ai-KrN0mqVH.js → pw-ai-D-_aGzdQ.js} +1 -1
- package/dist/{pw-ai-C-kqYO4L.js → pw-ai-S3cpSYOy.js} +1 -1
- package/dist/{register.agent-aY_6enDc.js → register.agent-BEM0_4uG.js} +5 -5
- package/dist/{register.agent-DNAtU5WP.js → register.agent-WQgVmACk.js} +6 -6
- package/dist/{register.configure-CwlwOMZ3.js → register.configure-CCpFmFPt.js} +6 -6
- package/dist/{register.configure-C_n9kIWJ.js → register.configure-CdW3aECy.js} +6 -6
- package/dist/{register.maintenance-DC40nnCm.js → register.maintenance-B8RZLSOe.js} +8 -8
- package/dist/{register.maintenance-Dddndcoo.js → register.maintenance-CM3QEdFz.js} +7 -7
- package/dist/{register.message-DiR6desB.js → register.message-BRLYHuVS.js} +2 -2
- package/dist/{register.message-CpEf0b15.js → register.message-XYm9NyDT.js} +2 -2
- package/dist/{register.onboard-bOeA39xj.js → register.onboard-BzAJbRpP.js} +4 -4
- package/dist/{register.onboard-VzVmqpEA.js → register.onboard-EwGHFUsd.js} +4 -4
- package/dist/{register.setup-CNLQzxl8.js → register.setup-33shhZje.js} +4 -4
- package/dist/{register.setup-D6iO5Xqa.js → register.setup-DpdZyiMv.js} +4 -4
- package/dist/{register.status-health-sessions-CoiaeduR.js → register.status-health-sessions-C8-iqepo.js} +3 -3
- package/dist/{register.status-health-sessions-BtJeTZnN.js → register.status-health-sessions-CK4f2nj_.js} +3 -3
- package/dist/{register.subclis-CFTYYdAQ.js → register.subclis-Mn68G5tp.js} +9 -9
- package/dist/{reply-Bv-RvRzs.js → reply-DuVUTFfT.js} +82 -3
- package/dist/{run-main-EzFOCEdp.js → run-main-CNB3qjRM.js} +14 -14
- package/dist/{runner-ChBxge-W.js → runner-D1eXJZ8T.js} +1 -1
- package/dist/{runner-Dq-qfrq7.js → runner-a43IsYad.js} +1 -1
- package/dist/{server-node-events-B9TqPvCI.js → server-node-events-B3o3P600.js} +2 -2
- package/dist/{server-node-events-syk21TN6.js → server-node-events-BPFwUGbS.js} +2 -2
- package/dist/{session-dirs-BAcQuXpY.js → session-dirs-Cw2efkey.js} +1 -1
- package/dist/{session-dirs-t0YpmrIL.js → session-dirs-DsU4kvIK.js} +1 -1
- package/dist/{status-keCWmejk.js → status-BSJIuIlN.js} +1 -1
- package/dist/{status-05251w21.js → status-BhHpKHQP.js} +2 -2
- package/dist/{status-BqDiXxwL.js → status-C2PvVLaW.js} +1 -1
- package/dist/{status-B8UVm7P3.js → status-CLKmcFCC.js} +2 -2
- package/dist/{subagent-registry-Lm4ps45z.js → subagent-registry-Da0a_Vka.js} +82 -3
- package/dist/{update-cli-BTF6TXGD.js → update-cli-BW3q5tFm.js} +7 -7
- package/dist/{update-cli-aW6jVJIJ.js → update-cli-D4EUMrX6.js} +8 -8
- package/dist/{web-BYZfljIx.js → web-BTbIFuWM.js} +2 -2
- package/dist/{web-BjxYv-hA.js → web-C7TQSVU0.js} +1 -1
- package/dist/{web-DPHo2cWX.js → web-CVSol55V.js} +6 -6
- package/dist/{web-Cs0IP-ZO.js → web-Y49Dumye.js} +6 -6
- package/extensions/voice-call/src/providers/twilio.ts +31 -13
- package/extensions/voice-call/src/response-generator.ts +3 -3
- package/extensions/voice-call/src/telephony-audio.ts +54 -0
- package/extensions/voice-call/src/telephony-tts.ts +40 -2
- package/package.json +1 -1
|
@@ -565,30 +565,48 @@ export class TwilioProvider implements VoiceCallProvider {
|
|
|
565
565
|
throw new Error("TTS provider and media stream handler required");
|
|
566
566
|
}
|
|
567
567
|
|
|
568
|
-
|
|
569
|
-
const CHUNK_SIZE = 160;
|
|
568
|
+
const CHUNK_SIZE = 160; // 20ms at 8kHz mu-law
|
|
570
569
|
const CHUNK_DELAY_MS = 20;
|
|
571
|
-
|
|
572
570
|
const handler = this.mediaStreamHandler;
|
|
573
571
|
const ttsProvider = this.ttsProvider;
|
|
572
|
+
|
|
574
573
|
await handler.queueTts(streamSid, async (signal) => {
|
|
575
|
-
//
|
|
574
|
+
// Try streaming TTS first (sends audio as chunks arrive from API)
|
|
575
|
+
if (ttsProvider.synthesizeForTelephonyStream) {
|
|
576
|
+
try {
|
|
577
|
+
let framesEmitted = 0;
|
|
578
|
+
const stream = ttsProvider.synthesizeForTelephonyStream(text);
|
|
579
|
+
for await (const muLawChunk of stream) {
|
|
580
|
+
if (signal.aborted) break;
|
|
581
|
+
for (const chunk of chunkAudio(muLawChunk, CHUNK_SIZE)) {
|
|
582
|
+
if (signal.aborted) break;
|
|
583
|
+
handler.sendAudio(streamSid, chunk);
|
|
584
|
+
framesEmitted++;
|
|
585
|
+
await new Promise((resolve) => setTimeout(resolve, CHUNK_DELAY_MS));
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
if (!signal.aborted && framesEmitted > 0) {
|
|
589
|
+
handler.sendMark(streamSid, `tts-${Date.now()}`);
|
|
590
|
+
}
|
|
591
|
+
return;
|
|
592
|
+
} catch (err) {
|
|
593
|
+
console.warn(
|
|
594
|
+
`[voice-call] Streaming TTS failed, falling back to buffered:`,
|
|
595
|
+
err instanceof Error ? err.message : err,
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Fallback: buffered TTS (full audio generated before sending)
|
|
576
601
|
const muLawAudio = await ttsProvider.synthesizeForTelephony(text);
|
|
577
602
|
for (const chunk of chunkAudio(muLawAudio, CHUNK_SIZE)) {
|
|
578
|
-
if (signal.aborted)
|
|
579
|
-
break;
|
|
580
|
-
}
|
|
603
|
+
if (signal.aborted) break;
|
|
581
604
|
handler.sendAudio(streamSid, chunk);
|
|
582
|
-
|
|
583
|
-
// Pace the audio to match real-time playback
|
|
584
605
|
await new Promise((resolve) => setTimeout(resolve, CHUNK_DELAY_MS));
|
|
585
|
-
if (signal.aborted)
|
|
586
|
-
break;
|
|
587
|
-
}
|
|
606
|
+
if (signal.aborted) break;
|
|
588
607
|
}
|
|
589
608
|
|
|
590
609
|
if (!signal.aborted) {
|
|
591
|
-
// Send a mark to track when audio finishes
|
|
592
610
|
handler.sendMark(streamSid, `tts-${Date.now()}`);
|
|
593
611
|
}
|
|
594
612
|
});
|
|
@@ -59,9 +59,9 @@ export async function generateVoiceResponse(
|
|
|
59
59
|
}
|
|
60
60
|
const cfg = coreConfig;
|
|
61
61
|
|
|
62
|
-
// Build voice-specific session key
|
|
63
|
-
|
|
64
|
-
const sessionKey = `voice:${
|
|
62
|
+
// Build voice-specific session key per call (not per phone number)
|
|
63
|
+
// so conversation history doesn't leak between separate calls
|
|
64
|
+
const sessionKey = `voice:${callId}`;
|
|
65
65
|
const agentId = "main";
|
|
66
66
|
|
|
67
67
|
// Resolve paths
|
|
@@ -67,6 +67,60 @@ export function chunkAudio(audio: Buffer, chunkSize = 160): Generator<Buffer, vo
|
|
|
67
67
|
})();
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Stateful incremental PCM-to-mulaw converter for streaming.
|
|
72
|
+
* Handles odd-byte chunk boundaries between calls.
|
|
73
|
+
*/
|
|
74
|
+
export type PcmToMulawStreamState = {
|
|
75
|
+
oddByte: number | null;
|
|
76
|
+
srcPosCarry: number;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export function createPcmToMulawStreamState(): PcmToMulawStreamState {
|
|
80
|
+
return { oddByte: null, srcPosCarry: 0 };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function convertPcmChunkToMulaw8k(
|
|
84
|
+
chunk: Buffer,
|
|
85
|
+
inputSampleRate: number,
|
|
86
|
+
state: PcmToMulawStreamState,
|
|
87
|
+
): Buffer {
|
|
88
|
+
let data = chunk;
|
|
89
|
+
if (state.oddByte !== null) {
|
|
90
|
+
data = Buffer.concat([Buffer.from([state.oddByte]), chunk]);
|
|
91
|
+
state.oddByte = null;
|
|
92
|
+
}
|
|
93
|
+
if (data.length % 2 !== 0) {
|
|
94
|
+
state.oddByte = data[data.length - 1]!;
|
|
95
|
+
data = data.subarray(0, data.length - 1);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (data.length === 0) return Buffer.alloc(0);
|
|
99
|
+
|
|
100
|
+
const inputSamples = data.length / 2;
|
|
101
|
+
const ratio = inputSampleRate / TELEPHONY_SAMPLE_RATE;
|
|
102
|
+
const outputSamples: number[] = [];
|
|
103
|
+
|
|
104
|
+
let srcPos = state.srcPosCarry;
|
|
105
|
+
while (srcPos < inputSamples) {
|
|
106
|
+
const srcIndex = Math.floor(srcPos);
|
|
107
|
+
const frac = srcPos - srcIndex;
|
|
108
|
+
const s0 = data.readInt16LE(srcIndex * 2);
|
|
109
|
+
const s1Index = Math.min(srcIndex + 1, inputSamples - 1);
|
|
110
|
+
const s1 = data.readInt16LE(s1Index * 2);
|
|
111
|
+
const sample = Math.round(s0 + frac * (s1 - s0));
|
|
112
|
+
outputSamples.push(linearToMulaw(clamp16(sample)));
|
|
113
|
+
srcPos += ratio;
|
|
114
|
+
}
|
|
115
|
+
state.srcPosCarry = srcPos - inputSamples;
|
|
116
|
+
|
|
117
|
+
const output = Buffer.alloc(outputSamples.length);
|
|
118
|
+
for (let i = 0; i < outputSamples.length; i++) {
|
|
119
|
+
output[i] = outputSamples[i]!;
|
|
120
|
+
}
|
|
121
|
+
return output;
|
|
122
|
+
}
|
|
123
|
+
|
|
70
124
|
function linearToMulaw(sample: number): number {
|
|
71
125
|
const BIAS = 132;
|
|
72
126
|
const CLIP = 32635;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import type { Readable } from "node:stream";
|
|
1
2
|
import type { VoiceCallTtsConfig } from "./config.js";
|
|
2
3
|
import type { CoreConfig } from "./core-bridge.js";
|
|
3
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
convertPcmToMulaw8k,
|
|
6
|
+
convertPcmChunkToMulaw8k,
|
|
7
|
+
createPcmToMulawStreamState,
|
|
8
|
+
} from "./telephony-audio.js";
|
|
4
9
|
|
|
5
10
|
export type TelephonyTtsRuntime = {
|
|
6
11
|
textToSpeechTelephony: (params: {
|
|
@@ -14,10 +19,18 @@ export type TelephonyTtsRuntime = {
|
|
|
14
19
|
provider?: string;
|
|
15
20
|
error?: string;
|
|
16
21
|
}>;
|
|
22
|
+
textToSpeechTelephonyStream?: (params: { text: string; cfg: CoreConfig }) => Promise<{
|
|
23
|
+
success: boolean;
|
|
24
|
+
stream?: ReadableStream<Uint8Array>;
|
|
25
|
+
sampleRate?: number;
|
|
26
|
+
cleanup?: () => void;
|
|
27
|
+
error?: string;
|
|
28
|
+
}>;
|
|
17
29
|
};
|
|
18
30
|
|
|
19
31
|
export type TelephonyTtsProvider = {
|
|
20
32
|
synthesizeForTelephony: (text: string) => Promise<Buffer>;
|
|
33
|
+
synthesizeForTelephonyStream?: (text: string) => AsyncGenerator<Buffer, void, unknown>;
|
|
21
34
|
};
|
|
22
35
|
|
|
23
36
|
const BLOCKED_MERGE_KEYS = new Set(["__proto__", "prototype", "constructor"]);
|
|
@@ -30,7 +43,7 @@ export function createTelephonyTtsProvider(params: {
|
|
|
30
43
|
const { coreConfig, ttsOverride, runtime } = params;
|
|
31
44
|
const mergedConfig = applyTtsOverride(coreConfig, ttsOverride);
|
|
32
45
|
|
|
33
|
-
|
|
46
|
+
const provider: TelephonyTtsProvider = {
|
|
34
47
|
synthesizeForTelephony: async (text: string) => {
|
|
35
48
|
const result = await runtime.textToSpeechTelephony({
|
|
36
49
|
text,
|
|
@@ -44,6 +57,31 @@ export function createTelephonyTtsProvider(params: {
|
|
|
44
57
|
return convertPcmToMulaw8k(result.audioBuffer, result.sampleRate);
|
|
45
58
|
},
|
|
46
59
|
};
|
|
60
|
+
|
|
61
|
+
if (runtime.textToSpeechTelephonyStream) {
|
|
62
|
+
const streamFn = runtime.textToSpeechTelephonyStream;
|
|
63
|
+
provider.synthesizeForTelephonyStream = async function* (text: string) {
|
|
64
|
+
const result = await streamFn({ text, cfg: mergedConfig });
|
|
65
|
+
if (!result.success || !result.stream || !result.sampleRate) {
|
|
66
|
+
throw new Error(result.error ?? "TTS streaming failed");
|
|
67
|
+
}
|
|
68
|
+
const state = createPcmToMulawStreamState();
|
|
69
|
+
const reader = result.stream.getReader();
|
|
70
|
+
try {
|
|
71
|
+
while (true) {
|
|
72
|
+
const { done, value } = await reader.read();
|
|
73
|
+
if (done) break;
|
|
74
|
+
const mulaw = convertPcmChunkToMulaw8k(Buffer.from(value), result.sampleRate, state);
|
|
75
|
+
if (mulaw.length > 0) yield mulaw;
|
|
76
|
+
}
|
|
77
|
+
} finally {
|
|
78
|
+
reader.releaseLock();
|
|
79
|
+
result.cleanup?.();
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return provider;
|
|
47
85
|
}
|
|
48
86
|
|
|
49
87
|
function applyTtsOverride(coreConfig: CoreConfig, override?: VoiceCallTtsConfig): CoreConfig {
|
package/package.json
CHANGED