@fabric-harness/sdk 1.11.0 → 1.12.0
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/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/model-pricing.d.ts +6 -0
- package/dist/model-pricing.d.ts.map +1 -1
- package/dist/model-pricing.js +17 -0
- package/dist/model-pricing.js.map +1 -1
- package/dist/model.d.ts +4 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js.map +1 -1
- package/dist/strict.d.ts +12 -0
- package/dist/strict.d.ts.map +1 -1
- package/dist/strict.js +5 -0
- package/dist/strict.js.map +1 -1
- package/dist/voice-pipeline.d.ts +49 -0
- package/dist/voice-pipeline.d.ts.map +1 -0
- package/dist/voice-pipeline.js +312 -0
- package/dist/voice-pipeline.js.map +1 -0
- package/dist/voice-stt-cartesia.d.ts +29 -0
- package/dist/voice-stt-cartesia.d.ts.map +1 -0
- package/dist/voice-stt-cartesia.js +160 -0
- package/dist/voice-stt-cartesia.js.map +1 -0
- package/dist/voice-stt-deepgram.d.ts +28 -0
- package/dist/voice-stt-deepgram.d.ts.map +1 -0
- package/dist/voice-stt-deepgram.js +174 -0
- package/dist/voice-stt-deepgram.js.map +1 -0
- package/dist/voice-stt.d.ts +72 -0
- package/dist/voice-stt.d.ts.map +1 -0
- package/dist/voice-stt.js +8 -0
- package/dist/voice-stt.js.map +1 -0
- package/dist/voice-tts-cartesia.d.ts +36 -0
- package/dist/voice-tts-cartesia.d.ts.map +1 -0
- package/dist/voice-tts-cartesia.js +159 -0
- package/dist/voice-tts-cartesia.js.map +1 -0
- package/dist/voice-tts-elevenlabs.d.ts +35 -0
- package/dist/voice-tts-elevenlabs.d.ts.map +1 -0
- package/dist/voice-tts-elevenlabs.js +163 -0
- package/dist/voice-tts-elevenlabs.js.map +1 -0
- package/dist/voice-tts.d.ts +50 -0
- package/dist/voice-tts.d.ts.map +1 -0
- package/dist/voice-tts.js +11 -0
- package/dist/voice-tts.js.map +1 -0
- package/dist/voice-ws-shared.d.ts +20 -0
- package/dist/voice-ws-shared.d.ts.map +1 -0
- package/dist/voice-ws-shared.js +42 -0
- package/dist/voice-ws-shared.js.map +1 -0
- package/package.json +8 -8
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ElevenLabs streaming TTS provider.
|
|
3
|
+
*
|
|
4
|
+
* Uses the WebSocket streaming endpoint
|
|
5
|
+
* (`wss://api.elevenlabs.io/v1/text-to-speech/:voiceId/stream-input`) so
|
|
6
|
+
* audio frames stream out as text arrives. PCM 16-bit little-endian at
|
|
7
|
+
* configurable sample rate; μ-law 8kHz available for telephony.
|
|
8
|
+
*
|
|
9
|
+
* Pricing: billed per character of input text. Rates registered in
|
|
10
|
+
* `model-pricing.ts` under provider `elevenlabs`.
|
|
11
|
+
*/
|
|
12
|
+
import { base64ToBytes, openVoiceWs, toError } from './voice-ws-shared.js';
|
|
13
|
+
const DEFAULT_BASE = 'wss://api.elevenlabs.io';
|
|
14
|
+
const DEFAULT_MODEL = 'eleven_turbo_v2_5';
|
|
15
|
+
const DEFAULT_VOICE = '21m00Tcm4TlvDq8ikWAM'; // 'Rachel' — ElevenLabs starter voice.
|
|
16
|
+
export class ElevenLabsTtsProvider {
|
|
17
|
+
name;
|
|
18
|
+
apiKey;
|
|
19
|
+
defaultVoice;
|
|
20
|
+
model;
|
|
21
|
+
baseUrl;
|
|
22
|
+
last;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
if (!options.apiKey)
|
|
25
|
+
throw new Error('ElevenLabsTtsProvider: apiKey is required.');
|
|
26
|
+
this.apiKey = options.apiKey;
|
|
27
|
+
this.defaultVoice = options.defaultVoice ?? DEFAULT_VOICE;
|
|
28
|
+
this.model = options.model ?? DEFAULT_MODEL;
|
|
29
|
+
this.baseUrl = options.baseUrl ?? DEFAULT_BASE;
|
|
30
|
+
this.name = options.name ?? 'elevenlabs';
|
|
31
|
+
}
|
|
32
|
+
lastUsage() {
|
|
33
|
+
return this.last;
|
|
34
|
+
}
|
|
35
|
+
synthesize(text, opts = {}) {
|
|
36
|
+
const voice = opts.voice ?? this.defaultVoice;
|
|
37
|
+
const format = opts.audioFormat ?? 'pcm16';
|
|
38
|
+
const sampleRate = opts.sampleRate ?? defaultSampleRate(format);
|
|
39
|
+
const startedAt = Date.now();
|
|
40
|
+
let totalBytes = 0;
|
|
41
|
+
const charCount = text.length;
|
|
42
|
+
const provider = this;
|
|
43
|
+
return {
|
|
44
|
+
[Symbol.asyncIterator]: async function* () {
|
|
45
|
+
const url = buildUrl(provider.baseUrl, voice, provider.model, format, sampleRate);
|
|
46
|
+
const ws = await openVoiceWs(url, { 'xi-api-key': provider.apiKey });
|
|
47
|
+
const queue = [];
|
|
48
|
+
const waiters = [];
|
|
49
|
+
let closed = false;
|
|
50
|
+
let errorMsg;
|
|
51
|
+
const push = (chunk) => {
|
|
52
|
+
if (closed)
|
|
53
|
+
return;
|
|
54
|
+
if (!chunk) {
|
|
55
|
+
closed = true;
|
|
56
|
+
while (waiters.length > 0)
|
|
57
|
+
waiters.shift()({ value: undefined, done: true });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
totalBytes += chunk.byteLength;
|
|
61
|
+
const w = waiters.shift();
|
|
62
|
+
if (w)
|
|
63
|
+
w({ value: chunk, done: false });
|
|
64
|
+
else
|
|
65
|
+
queue.push(chunk);
|
|
66
|
+
};
|
|
67
|
+
ws.addEventListener('message', (ev) => {
|
|
68
|
+
const raw = typeof ev.data === 'string' ? ev.data : ev.data?.toString?.() ?? '';
|
|
69
|
+
let payload;
|
|
70
|
+
try {
|
|
71
|
+
payload = JSON.parse(raw);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (typeof payload.audio === 'string' && payload.audio.length > 0) {
|
|
77
|
+
push(base64ToBytes(payload.audio));
|
|
78
|
+
}
|
|
79
|
+
if (payload.isFinal === true) {
|
|
80
|
+
push(undefined);
|
|
81
|
+
try {
|
|
82
|
+
ws.close();
|
|
83
|
+
}
|
|
84
|
+
catch { }
|
|
85
|
+
}
|
|
86
|
+
if (payload.error || payload.message) {
|
|
87
|
+
errorMsg = String(payload.error ?? payload.message);
|
|
88
|
+
push(undefined);
|
|
89
|
+
try {
|
|
90
|
+
ws.close();
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
ws.addEventListener('error', (ev) => {
|
|
96
|
+
errorMsg = toError(ev, 'ElevenLabs WS error').message;
|
|
97
|
+
push(undefined);
|
|
98
|
+
});
|
|
99
|
+
ws.addEventListener('close', () => push(undefined));
|
|
100
|
+
// Per ElevenLabs streaming protocol: send BOS with voice settings,
|
|
101
|
+
// then text chunk(s), then EOS (empty text).
|
|
102
|
+
ws.send(JSON.stringify({
|
|
103
|
+
text: ' ',
|
|
104
|
+
voice_settings: { stability: 0.5, similarity_boost: 0.8, ...(opts.speed !== undefined ? { speed: opts.speed } : {}) },
|
|
105
|
+
xi_api_key: provider.apiKey,
|
|
106
|
+
}));
|
|
107
|
+
ws.send(JSON.stringify({ text: text + ' ', try_trigger_generation: true }));
|
|
108
|
+
ws.send(JSON.stringify({ text: '' }));
|
|
109
|
+
opts.signal?.addEventListener('abort', () => { try {
|
|
110
|
+
ws.close();
|
|
111
|
+
}
|
|
112
|
+
catch { } push(undefined); }, { once: true });
|
|
113
|
+
try {
|
|
114
|
+
while (true) {
|
|
115
|
+
if (queue.length > 0) {
|
|
116
|
+
yield queue.shift();
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (closed)
|
|
120
|
+
break;
|
|
121
|
+
const next = await new Promise((resolve) => waiters.push(resolve));
|
|
122
|
+
if (next.done)
|
|
123
|
+
break;
|
|
124
|
+
yield next.value;
|
|
125
|
+
}
|
|
126
|
+
if (errorMsg)
|
|
127
|
+
throw new Error(`ElevenLabs TTS: ${errorMsg}`);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
provider.last = {
|
|
131
|
+
characters: charCount,
|
|
132
|
+
audioBytes: totalBytes,
|
|
133
|
+
durationMs: Date.now() - startedAt,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function buildUrl(base, voiceId, model, format, sampleRate) {
|
|
141
|
+
const outputFormat = formatToElevenLabs(format, sampleRate);
|
|
142
|
+
const params = new URLSearchParams({
|
|
143
|
+
model_id: model,
|
|
144
|
+
output_format: outputFormat,
|
|
145
|
+
});
|
|
146
|
+
return `${base}/v1/text-to-speech/${encodeURIComponent(voiceId)}/stream-input?${params.toString()}`;
|
|
147
|
+
}
|
|
148
|
+
function formatToElevenLabs(format, sampleRate) {
|
|
149
|
+
if (format === 'g711_ulaw')
|
|
150
|
+
return 'ulaw_8000';
|
|
151
|
+
if (format === 'g711_alaw')
|
|
152
|
+
return 'ulaw_8000'; // ElevenLabs ships ulaw only.
|
|
153
|
+
// pcm16 family — sample rate selectable: 8000/16000/22050/24000/44100.
|
|
154
|
+
const allowed = [8000, 16000, 22050, 24000, 44100];
|
|
155
|
+
const rate = allowed.includes(sampleRate) ? sampleRate : 24000;
|
|
156
|
+
return `pcm_${rate}`;
|
|
157
|
+
}
|
|
158
|
+
function defaultSampleRate(format) {
|
|
159
|
+
if (format === 'g711_ulaw' || format === 'g711_alaw')
|
|
160
|
+
return 8000;
|
|
161
|
+
return 24000;
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=voice-tts-elevenlabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voice-tts-elevenlabs.js","sourceRoot":"","sources":["../src/voice-tts-elevenlabs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-speech provider surface. fabric-harness ships ElevenLabs and
|
|
3
|
+
* Cartesia implementations; bring-your-own for on-prem TTS or unsupported
|
|
4
|
+
* vendors. Used by `PipelineVoiceProvider` to drive the audio-out side of
|
|
5
|
+
* STT→LLM→TTS voice agents.
|
|
6
|
+
*
|
|
7
|
+
* For monolithic realtime models that own audio in *and* out (OpenAI
|
|
8
|
+
* Realtime), use `OpenAIRealtimeVoiceProvider` directly — TTS is internal.
|
|
9
|
+
*/
|
|
10
|
+
import type { VoiceAudioFormat } from './voice.js';
|
|
11
|
+
export interface TtsSynthesisOptions {
|
|
12
|
+
/** Voice timbre / cloned-voice id. Provider-specific. */
|
|
13
|
+
voice?: string;
|
|
14
|
+
/** Audio format on the wire. Default `pcm16`. */
|
|
15
|
+
audioFormat?: VoiceAudioFormat;
|
|
16
|
+
/** Sample rate in Hz. Default 24000 for `pcm16`, 8000 for telephony codecs. */
|
|
17
|
+
sampleRate?: number;
|
|
18
|
+
/** Optional speaking-rate / speed multiplier (1.0 = default). */
|
|
19
|
+
speed?: number;
|
|
20
|
+
/** Abort signal — terminates an in-flight synthesis cleanly. */
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
export interface TtsSynthesisUsage {
|
|
24
|
+
/** Characters of input text submitted (used for billing rollup). */
|
|
25
|
+
characters: number;
|
|
26
|
+
/** Total bytes of audio emitted. */
|
|
27
|
+
audioBytes: number;
|
|
28
|
+
/** Wall-clock duration of the synthesis call in milliseconds. */
|
|
29
|
+
durationMs: number;
|
|
30
|
+
}
|
|
31
|
+
export interface TtsProvider {
|
|
32
|
+
/** Stable provider id used in cost telemetry, e.g. `elevenlabs`, `cartesia`. */
|
|
33
|
+
readonly name: string;
|
|
34
|
+
/**
|
|
35
|
+
* Synthesize a complete utterance. Yields raw audio frames in
|
|
36
|
+
* `opts.audioFormat` (default `pcm16`). The final iteration value is
|
|
37
|
+
* the usage rollup — read it from `provider.lastUsage()` when the
|
|
38
|
+
* iterator completes.
|
|
39
|
+
*/
|
|
40
|
+
synthesize(text: string, opts?: TtsSynthesisOptions): AsyncIterable<Uint8Array>;
|
|
41
|
+
/**
|
|
42
|
+
* Optional: streaming text input. The provider should chunk audio out
|
|
43
|
+
* incrementally as text arrives — useful for low-latency LLM-token-to-
|
|
44
|
+
* audio paths. Falls back to buffering + `synthesize()` if absent.
|
|
45
|
+
*/
|
|
46
|
+
synthesizeStream?(text: AsyncIterable<string>, opts?: TtsSynthesisOptions): AsyncIterable<Uint8Array>;
|
|
47
|
+
/** Last completed synthesis usage. Reset at the start of each call. */
|
|
48
|
+
lastUsage(): TtsSynthesisUsage | undefined;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=voice-tts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voice-tts.d.ts","sourceRoot":"","sources":["../src/voice-tts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,MAAM,WAAW,mBAAmB;IAClC,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IAChF;;;;OAIG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,mBAAmB,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACtG,uEAAuE;IACvE,SAAS,IAAI,iBAAiB,GAAG,SAAS,CAAC;CAC5C"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text-to-speech provider surface. fabric-harness ships ElevenLabs and
|
|
3
|
+
* Cartesia implementations; bring-your-own for on-prem TTS or unsupported
|
|
4
|
+
* vendors. Used by `PipelineVoiceProvider` to drive the audio-out side of
|
|
5
|
+
* STT→LLM→TTS voice agents.
|
|
6
|
+
*
|
|
7
|
+
* For monolithic realtime models that own audio in *and* out (OpenAI
|
|
8
|
+
* Realtime), use `OpenAIRealtimeVoiceProvider` directly — TTS is internal.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=voice-tts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voice-tts.js","sourceRoot":"","sources":["../src/voice-tts.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared WebSocket plumbing for voice STT/TTS providers. Uses the global
|
|
3
|
+
* `WebSocket` (Node 22+ + browsers) — no `ws` dependency.
|
|
4
|
+
*/
|
|
5
|
+
export interface VoiceWebSocket {
|
|
6
|
+
send(data: string | ArrayBuffer | Uint8Array): void;
|
|
7
|
+
close(code?: number, reason?: string): void;
|
|
8
|
+
addEventListener(type: 'message', listener: (ev: {
|
|
9
|
+
data: unknown;
|
|
10
|
+
}) => void): void;
|
|
11
|
+
addEventListener(type: 'error', listener: (ev: unknown) => void): void;
|
|
12
|
+
addEventListener(type: 'close', listener: (ev: unknown) => void): void;
|
|
13
|
+
addEventListener(type: 'open', listener: (ev: unknown) => void): void;
|
|
14
|
+
readyState: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function openVoiceWs(url: string, headers: Record<string, string>): Promise<VoiceWebSocket>;
|
|
17
|
+
export declare function toError(value: unknown, fallback: string): Error;
|
|
18
|
+
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
19
|
+
export declare function base64ToBytes(value: string): Uint8Array;
|
|
20
|
+
//# sourceMappingURL=voice-ws-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voice-ws-shared.d.ts","sourceRoot":"","sources":["../src/voice-ws-shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,GAAG,IAAI,CAAC;IACpD,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5C,gBAAgB,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACnF,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACvE,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACvE,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACtE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,cAAc,CAAC,CAYzB;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,KAAK,CAM/D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAKvD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAMvD"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared WebSocket plumbing for voice STT/TTS providers. Uses the global
|
|
3
|
+
* `WebSocket` (Node 22+ + browsers) — no `ws` dependency.
|
|
4
|
+
*/
|
|
5
|
+
export async function openVoiceWs(url, headers) {
|
|
6
|
+
const Impl = globalThis.WebSocket;
|
|
7
|
+
if (!Impl) {
|
|
8
|
+
throw new Error('Voice WS: global WebSocket not available. Use Node 22+ or polyfill.');
|
|
9
|
+
}
|
|
10
|
+
const ws = new Impl(url, { headers });
|
|
11
|
+
await new Promise((resolve, reject) => {
|
|
12
|
+
ws.addEventListener('open', () => resolve());
|
|
13
|
+
ws.addEventListener('error', (ev) => reject(toError(ev, 'WebSocket open failed')));
|
|
14
|
+
});
|
|
15
|
+
return ws;
|
|
16
|
+
}
|
|
17
|
+
export function toError(value, fallback) {
|
|
18
|
+
if (value instanceof Error)
|
|
19
|
+
return value;
|
|
20
|
+
if (value && typeof value === 'object' && 'message' in value) {
|
|
21
|
+
return new Error(String(value.message));
|
|
22
|
+
}
|
|
23
|
+
return new Error(fallback);
|
|
24
|
+
}
|
|
25
|
+
export function bytesToBase64(bytes) {
|
|
26
|
+
if (typeof Buffer !== 'undefined')
|
|
27
|
+
return Buffer.from(bytes).toString('base64');
|
|
28
|
+
let binary = '';
|
|
29
|
+
for (let i = 0; i < bytes.byteLength; i += 1)
|
|
30
|
+
binary += String.fromCharCode(bytes[i]);
|
|
31
|
+
return btoa(binary);
|
|
32
|
+
}
|
|
33
|
+
export function base64ToBytes(value) {
|
|
34
|
+
if (typeof Buffer !== 'undefined')
|
|
35
|
+
return new Uint8Array(Buffer.from(value, 'base64'));
|
|
36
|
+
const bin = atob(value);
|
|
37
|
+
const out = new Uint8Array(bin.length);
|
|
38
|
+
for (let i = 0; i < bin.length; i += 1)
|
|
39
|
+
out[i] = bin.charCodeAt(i);
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=voice-ws-shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"voice-ws-shared.js","sourceRoot":"","sources":["../src/voice-ws-shared.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,GAAW,EACX,OAA+B;IAE/B,MAAM,IAAI,GACP,UAAqF,CAAC,SAAS,CAAC;IACnG,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IACzF,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACtC,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;QAC7C,EAAE,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,EAAE,uBAAuB,CAAC,CAAC,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,KAAc,EAAE,QAAgB;IACtD,IAAI,KAAK,YAAY,KAAK;QAAE,OAAO,KAAK,CAAC;IACzC,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,SAAS,IAAK,KAAiC,EAAE,CAAC;QAC1F,OAAO,IAAI,KAAK,CAAC,MAAM,CAAE,KAA8B,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChF,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IACvF,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;IACvF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IACxB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabric-harness/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"description": "Headless TypeScript framework for building durable, deployable autonomous agents — core SDK.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Fabric",
|
|
@@ -60,6 +60,12 @@
|
|
|
60
60
|
"README.md",
|
|
61
61
|
"LICENSE"
|
|
62
62
|
],
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsc -p tsconfig.json",
|
|
65
|
+
"check": "tsc -b tsconfig.json",
|
|
66
|
+
"test": "vitest run",
|
|
67
|
+
"test:watch": "vitest"
|
|
68
|
+
},
|
|
63
69
|
"dependencies": {
|
|
64
70
|
"@mariozechner/pi-agent-core": "^0.72.1",
|
|
65
71
|
"@mariozechner/pi-ai": "^0.72.1",
|
|
@@ -77,11 +83,5 @@
|
|
|
77
83
|
"devDependencies": {
|
|
78
84
|
"@opentelemetry/api": "^1.9.1",
|
|
79
85
|
"vitest": "^4.1.5"
|
|
80
|
-
},
|
|
81
|
-
"scripts": {
|
|
82
|
-
"build": "tsc -p tsconfig.json",
|
|
83
|
-
"check": "tsc -b tsconfig.json",
|
|
84
|
-
"test": "vitest run",
|
|
85
|
-
"test:watch": "vitest"
|
|
86
86
|
}
|
|
87
|
-
}
|
|
87
|
+
}
|