@absolutejs/voice 0.0.22-beta.561 → 0.0.22-beta.563
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/core/types.d.ts +26 -0
- package/dist/index.js +56 -9
- package/dist/telephony/twilio.d.ts +14 -0
- package/dist/testing/index.js +56 -9
- package/package.json +155 -155
package/dist/core/types.d.ts
CHANGED
|
@@ -916,6 +916,32 @@ export type CreateVoiceSessionOptions<TContext = unknown, TSession extends Voice
|
|
|
916
916
|
fillerPhrases?: ReadonlyArray<string>;
|
|
917
917
|
/** Milliseconds after turn-commit before the filler fires. Default 250ms — short enough to feel instant, long enough to skip if the LLM is very fast. */
|
|
918
918
|
fillerDelayMs?: number;
|
|
919
|
+
/**
|
|
920
|
+
* Latency Theater — content-aware filler (Boardy parity move). When
|
|
921
|
+
* defined, the runtime calls `fillerFor({ userText, ... })` in parallel
|
|
922
|
+
* with the main LLM call to generate a brief acknowledgement of what the
|
|
923
|
+
* caller just said ("Freelance CFOs — interesting.", "Yeah, I hear you.").
|
|
924
|
+
* The runtime races the promise against `fillerForTimeoutMs` (default
|
|
925
|
+
* 600ms). If `fillerFor` returns a non-empty string in time, it's spoken
|
|
926
|
+
* INSTEAD of a random `fillerPhrases` entry. On timeout or null return,
|
|
927
|
+
* the runtime falls back to a static random phrase, so a slow / failed
|
|
928
|
+
* acknowledgement call never costs you the filler entirely.
|
|
929
|
+
*
|
|
930
|
+
* Return `null` (or an empty string) to explicitly skip filler for this
|
|
931
|
+
* turn — useful when `userText` is so short ("yes", "no", "okay") that
|
|
932
|
+
* acknowledging it back sounds robotic. Return throws are caught and
|
|
933
|
+
* treated as null.
|
|
934
|
+
*
|
|
935
|
+
* Cost-aware: callers typically wire this to a cheap nano/haiku model
|
|
936
|
+
* (gpt-4.1-nano, claude-haiku-4-5) that returns 2–5 words.
|
|
937
|
+
*/
|
|
938
|
+
fillerFor?: (input: {
|
|
939
|
+
sessionId: string;
|
|
940
|
+
turnId: string;
|
|
941
|
+
userText: string;
|
|
942
|
+
}) => Promise<string | null>;
|
|
943
|
+
/** Ceiling for the `fillerFor` call before we fall back to a static phrase. Default 600ms. */
|
|
944
|
+
fillerForTimeoutMs?: number;
|
|
919
945
|
/**
|
|
920
946
|
* Default spoken ack if the model returns ONLY tool calls (no text) and the
|
|
921
947
|
* turn isn't ending. Without this, the caller hears total silence after
|
package/dist/index.js
CHANGED
|
@@ -3852,7 +3852,7 @@ var createVoiceSession = (options) => {
|
|
|
3852
3852
|
};
|
|
3853
3853
|
const appendTurnLatencyStage = async (input) => appendTrace({
|
|
3854
3854
|
at: input.at,
|
|
3855
|
-
payload: { stage: input.stage },
|
|
3855
|
+
payload: { stage: input.stage, ...input.metadata ?? {} },
|
|
3856
3856
|
session: input.session,
|
|
3857
3857
|
turnId: input.turnId,
|
|
3858
3858
|
type: "turn_latency.stage"
|
|
@@ -3875,6 +3875,8 @@ var createVoiceSession = (options) => {
|
|
|
3875
3875
|
let fillerToken = 0;
|
|
3876
3876
|
const fillerPhrases = (options.fillerPhrases ?? []).filter((p) => typeof p === "string" && p.trim().length > 0);
|
|
3877
3877
|
const fillerDelayMs = options.fillerDelayMs ?? 250;
|
|
3878
|
+
const fillerFor = options.fillerFor;
|
|
3879
|
+
const fillerForTimeoutMs = options.fillerForTimeoutMs ?? 600;
|
|
3878
3880
|
const currentTurnAudio = [];
|
|
3879
3881
|
const pendingUserAttachments = [];
|
|
3880
3882
|
let fallbackAttemptsForCurrentTurn = 0;
|
|
@@ -4259,6 +4261,11 @@ var createVoiceSession = (options) => {
|
|
|
4259
4261
|
return;
|
|
4260
4262
|
}
|
|
4261
4263
|
activeTTSTurnId = undefined;
|
|
4264
|
+
appendTurnLatencyStage({
|
|
4265
|
+
metadata: { reason },
|
|
4266
|
+
stage: "tts_canceled",
|
|
4267
|
+
turnId: cancelledTurnId
|
|
4268
|
+
}).catch(() => {});
|
|
4262
4269
|
Promise.resolve(socket.clear?.()).catch(() => {});
|
|
4263
4270
|
if (!ttsAdapterSessionCanCancel(activeSession)) {
|
|
4264
4271
|
return;
|
|
@@ -4918,6 +4925,15 @@ var createVoiceSession = (options) => {
|
|
|
4918
4925
|
};
|
|
4919
4926
|
const handlePartial = async (transcript) => {
|
|
4920
4927
|
if (activeTTSTurnId !== undefined && transcript.text.trim()) {
|
|
4928
|
+
const triggeringText = transcript.text.trim();
|
|
4929
|
+
appendTurnLatencyStage({
|
|
4930
|
+
metadata: {
|
|
4931
|
+
partial: triggeringText.slice(0, 200),
|
|
4932
|
+
source: "stt_partial"
|
|
4933
|
+
},
|
|
4934
|
+
stage: "barge_in",
|
|
4935
|
+
turnId: activeTTSTurnId
|
|
4936
|
+
}).catch(() => {});
|
|
4921
4937
|
cancelActiveTTS("barge-in");
|
|
4922
4938
|
}
|
|
4923
4939
|
const session = await writeSession((session2) => {
|
|
@@ -5295,27 +5311,59 @@ var createVoiceSession = (options) => {
|
|
|
5295
5311
|
const injectedInstruction = liveOpsControl?.injectedInstruction?.trim();
|
|
5296
5312
|
const ttsStreamer = options.tts ? createTurnTTSStreamer(turn, session) : undefined;
|
|
5297
5313
|
if (fillerPhrases.length > 0 && options.tts && !ttsStreamer) {}
|
|
5298
|
-
if (fillerPhrases.length > 0 && options.tts) {
|
|
5314
|
+
if ((fillerPhrases.length > 0 || fillerFor) && options.tts) {
|
|
5299
5315
|
fillerToken += 1;
|
|
5300
5316
|
const myToken = fillerToken;
|
|
5301
5317
|
if (fillerTimer)
|
|
5302
5318
|
clearTimeout(fillerTimer);
|
|
5319
|
+
const fillerForPromise = fillerFor ? Promise.race([
|
|
5320
|
+
(async () => {
|
|
5321
|
+
try {
|
|
5322
|
+
const v = await fillerFor({
|
|
5323
|
+
sessionId: options.id,
|
|
5324
|
+
turnId: turn.id,
|
|
5325
|
+
userText: turn.text ?? ""
|
|
5326
|
+
});
|
|
5327
|
+
return v && v.trim().length > 0 ? v : null;
|
|
5328
|
+
} catch {
|
|
5329
|
+
return null;
|
|
5330
|
+
}
|
|
5331
|
+
})(),
|
|
5332
|
+
new Promise((resolve) => setTimeout(() => resolve(null), fillerForTimeoutMs))
|
|
5333
|
+
]) : null;
|
|
5303
5334
|
fillerTimer = setTimeout(() => {
|
|
5304
5335
|
fillerTimer = null;
|
|
5305
5336
|
if (myToken !== fillerToken)
|
|
5306
5337
|
return;
|
|
5307
5338
|
if (activeTTSTurnId === turn.id)
|
|
5308
5339
|
return;
|
|
5309
|
-
const phrase = fillerPhrases[Math.floor(Math.random() * fillerPhrases.length)] ?? "";
|
|
5310
|
-
if (!phrase)
|
|
5311
|
-
return;
|
|
5312
5340
|
runSerial("filler.send", async () => {
|
|
5313
5341
|
if (myToken !== fillerToken || activeTTSTurnId === turn.id)
|
|
5314
5342
|
return;
|
|
5343
|
+
let phrase = null;
|
|
5344
|
+
let source = "static";
|
|
5345
|
+
if (fillerForPromise) {
|
|
5346
|
+
phrase = await fillerForPromise;
|
|
5347
|
+
if (phrase)
|
|
5348
|
+
source = "fillerFor";
|
|
5349
|
+
if (myToken !== fillerToken || activeTTSTurnId === turn.id)
|
|
5350
|
+
return;
|
|
5351
|
+
}
|
|
5352
|
+
if (!phrase && fillerPhrases.length > 0) {
|
|
5353
|
+
phrase = fillerPhrases[Math.floor(Math.random() * fillerPhrases.length)] ?? null;
|
|
5354
|
+
source = "static";
|
|
5355
|
+
}
|
|
5356
|
+
if (!phrase)
|
|
5357
|
+
return;
|
|
5315
5358
|
const adapterSession = await ensureTTSSession();
|
|
5316
5359
|
if (!adapterSession)
|
|
5317
5360
|
return;
|
|
5318
5361
|
fillerActive = true;
|
|
5362
|
+
appendTurnLatencyStage({
|
|
5363
|
+
metadata: { phrase, source },
|
|
5364
|
+
stage: "filler_sent",
|
|
5365
|
+
turnId: turn.id
|
|
5366
|
+
}).catch(() => {});
|
|
5319
5367
|
try {
|
|
5320
5368
|
await adapterSession.send(phrase);
|
|
5321
5369
|
} catch {
|
|
@@ -5347,10 +5395,7 @@ var createVoiceSession = (options) => {
|
|
|
5347
5395
|
}, onTurnTimeoutMs);
|
|
5348
5396
|
});
|
|
5349
5397
|
try {
|
|
5350
|
-
committedOutput = await Promise.race([
|
|
5351
|
-
onTurnPromise,
|
|
5352
|
-
timeoutPromise
|
|
5353
|
-
]);
|
|
5398
|
+
committedOutput = await Promise.race([onTurnPromise, timeoutPromise]);
|
|
5354
5399
|
} finally {
|
|
5355
5400
|
if (timer)
|
|
5356
5401
|
clearTimeout(timer);
|
|
@@ -24720,6 +24765,8 @@ var createTwilioMediaStreamBridge = (socket, options) => {
|
|
|
24720
24765
|
...options.semanticTurnDetector ? { semanticTurnDetector: options.semanticTurnDetector } : {},
|
|
24721
24766
|
...options.fillerPhrases ? { fillerPhrases: options.fillerPhrases } : {},
|
|
24722
24767
|
...options.fillerDelayMs !== undefined ? { fillerDelayMs: options.fillerDelayMs } : {},
|
|
24768
|
+
...options.fillerFor ? { fillerFor: options.fillerFor } : {},
|
|
24769
|
+
...options.fillerForTimeoutMs !== undefined ? { fillerForTimeoutMs: options.fillerForTimeoutMs } : {},
|
|
24723
24770
|
...options.defaultSilentTurnAck !== undefined ? { defaultSilentTurnAck: options.defaultSilentTurnAck } : {},
|
|
24724
24771
|
...options.routeOnTurnTimeoutMs !== undefined ? { routeOnTurnTimeoutMs: options.routeOnTurnTimeoutMs } : {},
|
|
24725
24772
|
trace: options.trace,
|
|
@@ -132,6 +132,20 @@ export type TwilioMediaStreamBridgeOptions<TContext = unknown, TSession extends
|
|
|
132
132
|
fillerPhrases?: ReadonlyArray<string>;
|
|
133
133
|
/** Milliseconds after turn-commit before the filler fires. Default 250ms. */
|
|
134
134
|
fillerDelayMs?: number;
|
|
135
|
+
/**
|
|
136
|
+
* Content-aware filler (Latency Theater). Called in parallel with the
|
|
137
|
+
* main LLM turn; if it resolves within `fillerForTimeoutMs` the runtime
|
|
138
|
+
* speaks the result instead of a random `fillerPhrases` entry. Return
|
|
139
|
+
* `null` to skip filler for this turn. See CreateVoiceSessionOptions
|
|
140
|
+
* for full semantics.
|
|
141
|
+
*/
|
|
142
|
+
fillerFor?: (input: {
|
|
143
|
+
sessionId: string;
|
|
144
|
+
turnId: string;
|
|
145
|
+
userText: string;
|
|
146
|
+
}) => Promise<string | null>;
|
|
147
|
+
/** Cap on the `fillerFor` race before falling back to a static phrase. Default 600ms. */
|
|
148
|
+
fillerForTimeoutMs?: number;
|
|
135
149
|
/**
|
|
136
150
|
* Default spoken ack if the model returns ONLY tool calls (no text) and
|
|
137
151
|
* the turn isn't ending. Without this, the caller hears silence and
|
package/dist/testing/index.js
CHANGED
|
@@ -5723,7 +5723,7 @@ var createVoiceSession = (options) => {
|
|
|
5723
5723
|
};
|
|
5724
5724
|
const appendTurnLatencyStage = async (input) => appendTrace({
|
|
5725
5725
|
at: input.at,
|
|
5726
|
-
payload: { stage: input.stage },
|
|
5726
|
+
payload: { stage: input.stage, ...input.metadata ?? {} },
|
|
5727
5727
|
session: input.session,
|
|
5728
5728
|
turnId: input.turnId,
|
|
5729
5729
|
type: "turn_latency.stage"
|
|
@@ -5746,6 +5746,8 @@ var createVoiceSession = (options) => {
|
|
|
5746
5746
|
let fillerToken = 0;
|
|
5747
5747
|
const fillerPhrases = (options.fillerPhrases ?? []).filter((p) => typeof p === "string" && p.trim().length > 0);
|
|
5748
5748
|
const fillerDelayMs = options.fillerDelayMs ?? 250;
|
|
5749
|
+
const fillerFor = options.fillerFor;
|
|
5750
|
+
const fillerForTimeoutMs = options.fillerForTimeoutMs ?? 600;
|
|
5749
5751
|
const currentTurnAudio = [];
|
|
5750
5752
|
const pendingUserAttachments = [];
|
|
5751
5753
|
let fallbackAttemptsForCurrentTurn = 0;
|
|
@@ -6130,6 +6132,11 @@ var createVoiceSession = (options) => {
|
|
|
6130
6132
|
return;
|
|
6131
6133
|
}
|
|
6132
6134
|
activeTTSTurnId = undefined;
|
|
6135
|
+
appendTurnLatencyStage({
|
|
6136
|
+
metadata: { reason },
|
|
6137
|
+
stage: "tts_canceled",
|
|
6138
|
+
turnId: cancelledTurnId
|
|
6139
|
+
}).catch(() => {});
|
|
6133
6140
|
Promise.resolve(socket.clear?.()).catch(() => {});
|
|
6134
6141
|
if (!ttsAdapterSessionCanCancel(activeSession)) {
|
|
6135
6142
|
return;
|
|
@@ -6789,6 +6796,15 @@ var createVoiceSession = (options) => {
|
|
|
6789
6796
|
};
|
|
6790
6797
|
const handlePartial = async (transcript) => {
|
|
6791
6798
|
if (activeTTSTurnId !== undefined && transcript.text.trim()) {
|
|
6799
|
+
const triggeringText = transcript.text.trim();
|
|
6800
|
+
appendTurnLatencyStage({
|
|
6801
|
+
metadata: {
|
|
6802
|
+
partial: triggeringText.slice(0, 200),
|
|
6803
|
+
source: "stt_partial"
|
|
6804
|
+
},
|
|
6805
|
+
stage: "barge_in",
|
|
6806
|
+
turnId: activeTTSTurnId
|
|
6807
|
+
}).catch(() => {});
|
|
6792
6808
|
cancelActiveTTS("barge-in");
|
|
6793
6809
|
}
|
|
6794
6810
|
const session = await writeSession((session2) => {
|
|
@@ -7166,27 +7182,59 @@ var createVoiceSession = (options) => {
|
|
|
7166
7182
|
const injectedInstruction = liveOpsControl?.injectedInstruction?.trim();
|
|
7167
7183
|
const ttsStreamer = options.tts ? createTurnTTSStreamer(turn, session) : undefined;
|
|
7168
7184
|
if (fillerPhrases.length > 0 && options.tts && !ttsStreamer) {}
|
|
7169
|
-
if (fillerPhrases.length > 0 && options.tts) {
|
|
7185
|
+
if ((fillerPhrases.length > 0 || fillerFor) && options.tts) {
|
|
7170
7186
|
fillerToken += 1;
|
|
7171
7187
|
const myToken = fillerToken;
|
|
7172
7188
|
if (fillerTimer)
|
|
7173
7189
|
clearTimeout(fillerTimer);
|
|
7190
|
+
const fillerForPromise = fillerFor ? Promise.race([
|
|
7191
|
+
(async () => {
|
|
7192
|
+
try {
|
|
7193
|
+
const v = await fillerFor({
|
|
7194
|
+
sessionId: options.id,
|
|
7195
|
+
turnId: turn.id,
|
|
7196
|
+
userText: turn.text ?? ""
|
|
7197
|
+
});
|
|
7198
|
+
return v && v.trim().length > 0 ? v : null;
|
|
7199
|
+
} catch {
|
|
7200
|
+
return null;
|
|
7201
|
+
}
|
|
7202
|
+
})(),
|
|
7203
|
+
new Promise((resolve2) => setTimeout(() => resolve2(null), fillerForTimeoutMs))
|
|
7204
|
+
]) : null;
|
|
7174
7205
|
fillerTimer = setTimeout(() => {
|
|
7175
7206
|
fillerTimer = null;
|
|
7176
7207
|
if (myToken !== fillerToken)
|
|
7177
7208
|
return;
|
|
7178
7209
|
if (activeTTSTurnId === turn.id)
|
|
7179
7210
|
return;
|
|
7180
|
-
const phrase = fillerPhrases[Math.floor(Math.random() * fillerPhrases.length)] ?? "";
|
|
7181
|
-
if (!phrase)
|
|
7182
|
-
return;
|
|
7183
7211
|
runSerial("filler.send", async () => {
|
|
7184
7212
|
if (myToken !== fillerToken || activeTTSTurnId === turn.id)
|
|
7185
7213
|
return;
|
|
7214
|
+
let phrase = null;
|
|
7215
|
+
let source = "static";
|
|
7216
|
+
if (fillerForPromise) {
|
|
7217
|
+
phrase = await fillerForPromise;
|
|
7218
|
+
if (phrase)
|
|
7219
|
+
source = "fillerFor";
|
|
7220
|
+
if (myToken !== fillerToken || activeTTSTurnId === turn.id)
|
|
7221
|
+
return;
|
|
7222
|
+
}
|
|
7223
|
+
if (!phrase && fillerPhrases.length > 0) {
|
|
7224
|
+
phrase = fillerPhrases[Math.floor(Math.random() * fillerPhrases.length)] ?? null;
|
|
7225
|
+
source = "static";
|
|
7226
|
+
}
|
|
7227
|
+
if (!phrase)
|
|
7228
|
+
return;
|
|
7186
7229
|
const adapterSession = await ensureTTSSession();
|
|
7187
7230
|
if (!adapterSession)
|
|
7188
7231
|
return;
|
|
7189
7232
|
fillerActive = true;
|
|
7233
|
+
appendTurnLatencyStage({
|
|
7234
|
+
metadata: { phrase, source },
|
|
7235
|
+
stage: "filler_sent",
|
|
7236
|
+
turnId: turn.id
|
|
7237
|
+
}).catch(() => {});
|
|
7190
7238
|
try {
|
|
7191
7239
|
await adapterSession.send(phrase);
|
|
7192
7240
|
} catch {
|
|
@@ -7218,10 +7266,7 @@ var createVoiceSession = (options) => {
|
|
|
7218
7266
|
}, onTurnTimeoutMs);
|
|
7219
7267
|
});
|
|
7220
7268
|
try {
|
|
7221
|
-
committedOutput = await Promise.race([
|
|
7222
|
-
onTurnPromise,
|
|
7223
|
-
timeoutPromise
|
|
7224
|
-
]);
|
|
7269
|
+
committedOutput = await Promise.race([onTurnPromise, timeoutPromise]);
|
|
7225
7270
|
} finally {
|
|
7226
7271
|
if (timer)
|
|
7227
7272
|
clearTimeout(timer);
|
|
@@ -13310,6 +13355,8 @@ var createTwilioMediaStreamBridge = (socket, options) => {
|
|
|
13310
13355
|
...options.semanticTurnDetector ? { semanticTurnDetector: options.semanticTurnDetector } : {},
|
|
13311
13356
|
...options.fillerPhrases ? { fillerPhrases: options.fillerPhrases } : {},
|
|
13312
13357
|
...options.fillerDelayMs !== undefined ? { fillerDelayMs: options.fillerDelayMs } : {},
|
|
13358
|
+
...options.fillerFor ? { fillerFor: options.fillerFor } : {},
|
|
13359
|
+
...options.fillerForTimeoutMs !== undefined ? { fillerForTimeoutMs: options.fillerForTimeoutMs } : {},
|
|
13313
13360
|
...options.defaultSilentTurnAck !== undefined ? { defaultSilentTurnAck: options.defaultSilentTurnAck } : {},
|
|
13314
13361
|
...options.routeOnTurnTimeoutMs !== undefined ? { routeOnTurnTimeoutMs: options.routeOnTurnTimeoutMs } : {},
|
|
13315
13362
|
trace: options.trace,
|
package/package.json
CHANGED
|
@@ -1,157 +1,157 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
2
|
+
"name": "@absolutejs/voice",
|
|
3
|
+
"version": "0.0.22-beta.563",
|
|
4
|
+
"description": "Voice primitives and Elysia plugin for AbsoluteJS",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/absolutejs/voice.git"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"license": "CC BY-NC 4.0",
|
|
16
|
+
"author": "Alex Kahn",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "rm -rf dist && bun build ./src/index.ts ./src/client/index.ts ./src/react/index.ts ./src/vue/index.ts ./src/svelte/index.ts ./src/angular/index.ts ./src/testing/index.ts ./src/drizzle/index.ts --outdir dist --target bun --external elysia --external react --external vue --external @angular/core --external @absolutejs/absolute --external @absolutejs/ai --external @absolutejs/media --external drizzle-orm && bun build ./src/client/htmxBootstrap.ts --outdir dist/client --target browser --format esm && bun build ./src/embed/index.ts --outfile dist/embed/voice-widget.js --target browser --format iife --minify && bun build ./src/embed/index.ts --outdir dist/embed --target browser --format esm && tsc --emitDeclarationOnly --project tsconfig.json",
|
|
19
|
+
"config": "absolute config",
|
|
20
|
+
"format": "absolute prettier --write",
|
|
21
|
+
"knip": "knip",
|
|
22
|
+
"lint": "absolute eslint",
|
|
23
|
+
"release": "bun run format && bun run build && bun publish",
|
|
24
|
+
"test": "bun test ./test/*.test.ts",
|
|
25
|
+
"test:adapters": "bun test ./test/live/*.test.ts",
|
|
26
|
+
"test:assemblyai": "bun test ./test/live/assemblyai.live.test.ts",
|
|
27
|
+
"test:deepgram": "bun test ./test/live/deepgram.live.test.ts",
|
|
28
|
+
"test:elevenlabs": "bun test ./test/live/elevenlabs.live.test.ts",
|
|
29
|
+
"test:openai": "bun test ./test/live/openai.live.test.ts",
|
|
30
|
+
"typecheck": "absolute typecheck"
|
|
31
|
+
},
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"import": "./dist/index.js",
|
|
35
|
+
"types": "./dist/index.d.ts"
|
|
36
|
+
},
|
|
37
|
+
"./client": {
|
|
38
|
+
"browser": "./dist/client/index.js",
|
|
39
|
+
"import": "./dist/client/index.js",
|
|
40
|
+
"types": "./dist/client/index.d.ts"
|
|
41
|
+
},
|
|
42
|
+
"./react": {
|
|
43
|
+
"browser": "./dist/react/index.js",
|
|
44
|
+
"import": "./dist/react/index.js",
|
|
45
|
+
"types": "./dist/react/index.d.ts"
|
|
46
|
+
},
|
|
47
|
+
"./vue": {
|
|
48
|
+
"browser": "./dist/vue/index.js",
|
|
49
|
+
"import": "./dist/vue/index.js",
|
|
50
|
+
"types": "./dist/vue/index.d.ts"
|
|
51
|
+
},
|
|
52
|
+
"./svelte": {
|
|
53
|
+
"import": "./dist/svelte/index.js",
|
|
54
|
+
"types": "./dist/svelte/index.d.ts"
|
|
55
|
+
},
|
|
56
|
+
"./angular": {
|
|
57
|
+
"import": "./dist/angular/index.js",
|
|
58
|
+
"types": "./dist/angular/index.d.ts"
|
|
59
|
+
},
|
|
60
|
+
"./drizzle": {
|
|
61
|
+
"import": "./dist/drizzle/index.js",
|
|
62
|
+
"types": "./dist/drizzle/index.d.ts",
|
|
63
|
+
"default": "./dist/drizzle/index.js"
|
|
64
|
+
},
|
|
65
|
+
"./testing": {
|
|
66
|
+
"import": "./dist/testing/index.js",
|
|
67
|
+
"types": "./dist/testing/index.d.ts"
|
|
68
|
+
},
|
|
69
|
+
"./embed": {
|
|
70
|
+
"browser": "./dist/embed/index.js",
|
|
71
|
+
"import": "./dist/embed/index.js",
|
|
72
|
+
"types": "./dist/embed/index.d.ts"
|
|
73
|
+
},
|
|
74
|
+
"./embed/voice-widget.js": "./dist/embed/voice-widget.js"
|
|
75
|
+
},
|
|
76
|
+
"typesVersions": {
|
|
77
|
+
"*": {
|
|
78
|
+
"testing": [
|
|
79
|
+
"dist/testing/index.d.ts"
|
|
80
|
+
],
|
|
81
|
+
"client": [
|
|
82
|
+
"dist/client/index.d.ts"
|
|
83
|
+
],
|
|
84
|
+
"react": [
|
|
85
|
+
"dist/react/index.d.ts"
|
|
86
|
+
],
|
|
87
|
+
"svelte": [
|
|
88
|
+
"dist/svelte/index.d.ts"
|
|
89
|
+
],
|
|
90
|
+
"vue": [
|
|
91
|
+
"dist/vue/index.d.ts"
|
|
92
|
+
],
|
|
93
|
+
"angular": [
|
|
94
|
+
"dist/angular/index.d.ts"
|
|
95
|
+
],
|
|
96
|
+
"drizzle": [
|
|
97
|
+
"dist/drizzle/index.d.ts"
|
|
98
|
+
],
|
|
99
|
+
"embed": [
|
|
100
|
+
"dist/embed/index.d.ts"
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"peerDependencies": {
|
|
105
|
+
"@absolutejs/absolute": ">=0.19.0-beta.646",
|
|
106
|
+
"@absolutejs/ai": ">=0.0.5",
|
|
107
|
+
"@angular/core": ">=21.0.0",
|
|
108
|
+
"drizzle-orm": ">=0.36.0",
|
|
109
|
+
"elysia": ">=1.4.18",
|
|
110
|
+
"react": ">=19.0.0",
|
|
111
|
+
"vue": ">=3.5.0"
|
|
112
|
+
},
|
|
113
|
+
"peerDependenciesMeta": {
|
|
114
|
+
"@absolutejs/ai": {
|
|
115
|
+
"optional": true
|
|
116
|
+
},
|
|
117
|
+
"drizzle-orm": {
|
|
118
|
+
"optional": true
|
|
119
|
+
},
|
|
120
|
+
"@angular/core": {
|
|
121
|
+
"optional": true
|
|
122
|
+
},
|
|
123
|
+
"react": {
|
|
124
|
+
"optional": true
|
|
125
|
+
},
|
|
126
|
+
"vue": {
|
|
127
|
+
"optional": true
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"dependencies": {
|
|
131
|
+
"@absolutejs/media": "0.0.1-beta.19"
|
|
132
|
+
},
|
|
133
|
+
"devDependencies": {
|
|
134
|
+
"@absolutejs/absolute": "0.19.0-beta.1009",
|
|
135
|
+
"@absolutejs/ai": "0.0.5",
|
|
136
|
+
"@angular/core": "^21.0.0",
|
|
137
|
+
"@electric-sql/pglite": "^0.4.5",
|
|
138
|
+
"@eslint/js": "^10.0.1",
|
|
139
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
140
|
+
"@types/bun": "1.3.9",
|
|
141
|
+
"@types/react": "19.2.0",
|
|
142
|
+
"@typescript-eslint/parser": "^8.57.2",
|
|
143
|
+
"drizzle-orm": "0.44.7",
|
|
144
|
+
"elysia": "1.4.18",
|
|
145
|
+
"eslint": "^10.1.0",
|
|
146
|
+
"eslint-plugin-absolute": "0.11.0-beta.3",
|
|
147
|
+
"eslint-plugin-promise": "^7.2.1",
|
|
148
|
+
"eslint-plugin-security": "^4.0.0",
|
|
149
|
+
"globals": "^17.4.0",
|
|
150
|
+
"knip": "^6.14.1",
|
|
151
|
+
"prettier": "^3.4.0",
|
|
152
|
+
"react": "19.2.1",
|
|
153
|
+
"typescript": "^5.9.3",
|
|
154
|
+
"typescript-eslint": "^8.57.2",
|
|
155
|
+
"vue": "3.5.27"
|
|
156
|
+
}
|
|
157
157
|
}
|