@voicethere/agent 0.7.11 → 0.7.13
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/agent.js +24 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +24 -2
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js.map +1 -1
- package/dist/runtime.d.ts +3 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +68 -1
- package/dist/runtime.js.map +1 -1
- package/dist/templates/echo/agent.js +26 -2
- package/dist/templates/echo-dc/agent.js +26 -2
- package/dist/templates/game-sync/agent.js +26 -2
- package/dist/templates/positional-tts/agent.js +26 -2
- package/dist/templates/recording-consent/agent.js +26 -2
- package/dist/templates/registry.d.ts.map +1 -1
- package/dist/templates/registry.js +2 -1
- package/dist/templates/registry.js.map +1 -1
- package/dist/templates/spatial-showcase/agent.js +498 -29
- package/dist/templates/voice-showcase/agent.js +26 -2
- package/dist/templates/voice-starter/agent.js +26 -2
- package/dist/templates/webhooks/agent.js +26 -2
- package/dist/templates/webhooks-redis/agent.js +26 -2
- package/package.json +4 -4
- package/templates/README.md +10 -10
- package/templates/spatial-showcase/agent.ts +404 -34
- package/templates/spatial-showcase/protocol.ts +82 -1
- package/templates/spatial-showcase/sine.ts +66 -0
|
@@ -8,6 +8,8 @@ const SHOWCASE_DEMOS = new Set<string>(["orbit", "soundboard", "proximity"]);
|
|
|
8
8
|
|
|
9
9
|
export const MAX_SAY_TEXT_LENGTH = 200;
|
|
10
10
|
export const MAX_XZ = 5;
|
|
11
|
+
export const ORBIT_SINE_MIN_FREQUENCY_HZ = 110;
|
|
12
|
+
export const ORBIT_SINE_MAX_FREQUENCY_HZ = 1760;
|
|
11
13
|
|
|
12
14
|
export type ShowcaseJoinMessage = {
|
|
13
15
|
type: "join";
|
|
@@ -22,6 +24,8 @@ export type ShowcaseOrbitSetMessage = {
|
|
|
22
24
|
periodSec?: number;
|
|
23
25
|
elevation?: number;
|
|
24
26
|
paused?: boolean;
|
|
27
|
+
frequencyHz?: number;
|
|
28
|
+
sinePlaying?: boolean;
|
|
25
29
|
};
|
|
26
30
|
|
|
27
31
|
export type ShowcaseOrbitSayMessage = {
|
|
@@ -30,6 +34,13 @@ export type ShowcaseOrbitSayMessage = {
|
|
|
30
34
|
text: string;
|
|
31
35
|
};
|
|
32
36
|
|
|
37
|
+
export type ShowcaseOrbitPlaceMessage = {
|
|
38
|
+
type: "orbit";
|
|
39
|
+
action: "place";
|
|
40
|
+
x: number;
|
|
41
|
+
z: number;
|
|
42
|
+
};
|
|
43
|
+
|
|
33
44
|
export type ShowcasePadMessage = {
|
|
34
45
|
type: "pad";
|
|
35
46
|
clipId: string;
|
|
@@ -49,6 +60,13 @@ export type ShowcasePadStatusMessage = {
|
|
|
49
60
|
playId: string;
|
|
50
61
|
};
|
|
51
62
|
|
|
63
|
+
export type ShowcasePadMoveMessage = {
|
|
64
|
+
type: "pad_move";
|
|
65
|
+
playId: string;
|
|
66
|
+
x: number;
|
|
67
|
+
z: number;
|
|
68
|
+
};
|
|
69
|
+
|
|
52
70
|
export type ShowcaseMoveMessage = {
|
|
53
71
|
type: "move";
|
|
54
72
|
x: number;
|
|
@@ -74,9 +92,11 @@ export type ShowcaseInbound =
|
|
|
74
92
|
| ShowcaseJoinMessage
|
|
75
93
|
| ShowcaseOrbitSetMessage
|
|
76
94
|
| ShowcaseOrbitSayMessage
|
|
95
|
+
| ShowcaseOrbitPlaceMessage
|
|
77
96
|
| ShowcasePadMessage
|
|
78
97
|
| ShowcasePadStopMessage
|
|
79
98
|
| ShowcasePadStatusMessage
|
|
99
|
+
| ShowcasePadMoveMessage
|
|
80
100
|
| ShowcaseMoveMessage
|
|
81
101
|
| ShowcaseMutePeerMessage
|
|
82
102
|
| ShowcaseLeaveMessage
|
|
@@ -98,6 +118,11 @@ export type ShowcaseOrbitPose = {
|
|
|
98
118
|
z: number;
|
|
99
119
|
};
|
|
100
120
|
|
|
121
|
+
export type ShowcaseOrbitSayStatus = {
|
|
122
|
+
type: "orbit_say_status";
|
|
123
|
+
status: "playing" | "ended";
|
|
124
|
+
};
|
|
125
|
+
|
|
101
126
|
export type ShowcasePadProgress = {
|
|
102
127
|
type: "pad_progress";
|
|
103
128
|
playId: string;
|
|
@@ -127,6 +152,7 @@ export type ShowcaseError = {
|
|
|
127
152
|
export type ShowcaseOutbound =
|
|
128
153
|
| ShowcaseAck
|
|
129
154
|
| ShowcaseOrbitPose
|
|
155
|
+
| ShowcaseOrbitSayStatus
|
|
130
156
|
| ShowcasePadProgress
|
|
131
157
|
| ShowcaseRoomState
|
|
132
158
|
| ShowcaseRoomFull
|
|
@@ -144,6 +170,12 @@ function isInXzRange(value: number): boolean {
|
|
|
144
170
|
return value >= -MAX_XZ && value <= MAX_XZ;
|
|
145
171
|
}
|
|
146
172
|
|
|
173
|
+
function isOrbitSineFrequencyHz(value: number): boolean {
|
|
174
|
+
return (
|
|
175
|
+
value >= ORBIT_SINE_MIN_FREQUENCY_HZ && value <= ORBIT_SINE_MAX_FREQUENCY_HZ
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
147
179
|
function isMixPlacement(value: unknown): value is MixPlacement {
|
|
148
180
|
return (
|
|
149
181
|
value === "center" ||
|
|
@@ -164,7 +196,9 @@ export function isShowcaseDemo(value: unknown): value is ShowcaseDemo {
|
|
|
164
196
|
return typeof value === "string" && SHOWCASE_DEMOS.has(value);
|
|
165
197
|
}
|
|
166
198
|
|
|
167
|
-
export function isShowcaseInbound(
|
|
199
|
+
export function isShowcaseInbound(
|
|
200
|
+
message: unknown,
|
|
201
|
+
): message is ShowcaseInbound {
|
|
168
202
|
return parseShowcaseMessage(message) !== null;
|
|
169
203
|
}
|
|
170
204
|
|
|
@@ -219,6 +253,19 @@ export function parseShowcaseMessage(message: unknown): ShowcaseInbound | null {
|
|
|
219
253
|
if (set.paused !== undefined && typeof set.paused !== "boolean") {
|
|
220
254
|
return null;
|
|
221
255
|
}
|
|
256
|
+
if (
|
|
257
|
+
set.frequencyHz !== undefined &&
|
|
258
|
+
(!isFiniteNumber(set.frequencyHz) ||
|
|
259
|
+
!isOrbitSineFrequencyHz(set.frequencyHz))
|
|
260
|
+
) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
if (
|
|
264
|
+
set.sinePlaying !== undefined &&
|
|
265
|
+
typeof set.sinePlaying !== "boolean"
|
|
266
|
+
) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
222
269
|
return {
|
|
223
270
|
type: "orbit",
|
|
224
271
|
action: "set",
|
|
@@ -226,8 +273,24 @@ export function parseShowcaseMessage(message: unknown): ShowcaseInbound | null {
|
|
|
226
273
|
...(set.periodSec !== undefined ? { periodSec: set.periodSec } : {}),
|
|
227
274
|
...(set.elevation !== undefined ? { elevation: set.elevation } : {}),
|
|
228
275
|
...(set.paused !== undefined ? { paused: set.paused } : {}),
|
|
276
|
+
...(set.frequencyHz !== undefined
|
|
277
|
+
? { frequencyHz: set.frequencyHz }
|
|
278
|
+
: {}),
|
|
279
|
+
...(set.sinePlaying !== undefined
|
|
280
|
+
? { sinePlaying: set.sinePlaying }
|
|
281
|
+
: {}),
|
|
229
282
|
};
|
|
230
283
|
}
|
|
284
|
+
if (orbit.action === "place") {
|
|
285
|
+
const place = message as ShowcaseOrbitPlaceMessage;
|
|
286
|
+
if (!isFiniteNumber(place.x) || !isInXzRange(place.x)) {
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
if (!isFiniteNumber(place.z) || !isInXzRange(place.z)) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return { type: "orbit", action: "place", x: place.x, z: place.z };
|
|
293
|
+
}
|
|
231
294
|
if (orbit.action === "say") {
|
|
232
295
|
const say = message as ShowcaseOrbitSayMessage;
|
|
233
296
|
if (
|
|
@@ -285,6 +348,24 @@ export function parseShowcaseMessage(message: unknown): ShowcaseInbound | null {
|
|
|
285
348
|
}
|
|
286
349
|
return { type: "pad_status", playId: status.playId.trim() };
|
|
287
350
|
}
|
|
351
|
+
case "pad_move": {
|
|
352
|
+
const padMove = message as ShowcasePadMoveMessage;
|
|
353
|
+
if (!isNonEmptyString(padMove.playId)) {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
if (!isFiniteNumber(padMove.x) || !isInXzRange(padMove.x)) {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
if (!isFiniteNumber(padMove.z) || !isInXzRange(padMove.z)) {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
type: "pad_move",
|
|
364
|
+
playId: padMove.playId.trim(),
|
|
365
|
+
x: padMove.x,
|
|
366
|
+
z: padMove.z,
|
|
367
|
+
};
|
|
368
|
+
}
|
|
288
369
|
case "move": {
|
|
289
370
|
const move = message as ShowcaseMoveMessage;
|
|
290
371
|
if (!isFiniteNumber(move.x) || !isInXzRange(move.x)) {
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** Inline orbit sine clip — 16 kHz mono s16le, decoded size under 64 KiB play cap. */
|
|
2
|
+
|
|
3
|
+
/** 2 s keeps loop-restart gaps infrequent; 16 kHz mono still fits under 64 KiB. */
|
|
4
|
+
export const ORBIT_SINE_DURATION_MS = 2000;
|
|
5
|
+
export const ORBIT_SINE_FREQUENCY_HZ = 440;
|
|
6
|
+
export const ORBIT_SINE_AMPLITUDE = 8000;
|
|
7
|
+
export const ORBIT_SINE_SAMPLE_RATE = 16_000;
|
|
8
|
+
export const ORBIT_SINE_INLINE_URL =
|
|
9
|
+
"https://example.com/inline-orbit-sine.wav";
|
|
10
|
+
|
|
11
|
+
/** Snap duration to an integer number of cycles so the clip loops at a zero crossing. */
|
|
12
|
+
export function orbitSineSampleCount(
|
|
13
|
+
durationMs = ORBIT_SINE_DURATION_MS,
|
|
14
|
+
frequencyHz = ORBIT_SINE_FREQUENCY_HZ,
|
|
15
|
+
sampleRate = ORBIT_SINE_SAMPLE_RATE,
|
|
16
|
+
): number {
|
|
17
|
+
const targetCycles = (durationMs / 1000) * frequencyHz;
|
|
18
|
+
const cycles = Math.max(1, Math.floor(targetCycles));
|
|
19
|
+
return Math.round((cycles * sampleRate) / frequencyHz);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Duration in ms for a clip built with {@link orbitSineSampleCount}. */
|
|
23
|
+
export function orbitSineClipDurationMs(
|
|
24
|
+
durationMs = ORBIT_SINE_DURATION_MS,
|
|
25
|
+
frequencyHz = ORBIT_SINE_FREQUENCY_HZ,
|
|
26
|
+
sampleRate = ORBIT_SINE_SAMPLE_RATE,
|
|
27
|
+
): number {
|
|
28
|
+
const numSamples = orbitSineSampleCount(durationMs, frequencyHz, sampleRate);
|
|
29
|
+
return (numSamples / sampleRate) * 1000;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Looping sine WAV as base64 for {@link play} inline bytes. */
|
|
33
|
+
export function buildOrbitSineInlineClipBase64(
|
|
34
|
+
durationMs = ORBIT_SINE_DURATION_MS,
|
|
35
|
+
frequencyHz = ORBIT_SINE_FREQUENCY_HZ,
|
|
36
|
+
amplitude = ORBIT_SINE_AMPLITUDE,
|
|
37
|
+
phaseRad = 0,
|
|
38
|
+
): string {
|
|
39
|
+
const sampleRate = ORBIT_SINE_SAMPLE_RATE;
|
|
40
|
+
const channels = 1;
|
|
41
|
+
const bytesPerSample = 2;
|
|
42
|
+
const numSamples = orbitSineSampleCount(durationMs, frequencyHz, sampleRate);
|
|
43
|
+
const dataSize = numSamples * channels * bytesPerSample;
|
|
44
|
+
const buffer = Buffer.alloc(44 + dataSize);
|
|
45
|
+
buffer.write("RIFF", 0);
|
|
46
|
+
buffer.writeUInt32LE(36 + dataSize, 4);
|
|
47
|
+
buffer.write("WAVE", 8);
|
|
48
|
+
buffer.write("fmt ", 12);
|
|
49
|
+
buffer.writeUInt32LE(16, 16);
|
|
50
|
+
buffer.writeUInt16LE(1, 20);
|
|
51
|
+
buffer.writeUInt16LE(channels, 22);
|
|
52
|
+
buffer.writeUInt32LE(sampleRate, 24);
|
|
53
|
+
buffer.writeUInt32LE(sampleRate * channels * bytesPerSample, 28);
|
|
54
|
+
buffer.writeUInt16LE(channels * bytesPerSample, 32);
|
|
55
|
+
buffer.writeUInt16LE(16, 34);
|
|
56
|
+
buffer.write("data", 36);
|
|
57
|
+
buffer.writeUInt32LE(dataSize, 40);
|
|
58
|
+
for (let i = 0; i < numSamples; i++) {
|
|
59
|
+
const t = i / sampleRate;
|
|
60
|
+
const sample = Math.round(
|
|
61
|
+
amplitude * Math.sin(2 * Math.PI * frequencyHz * t + phaseRad),
|
|
62
|
+
);
|
|
63
|
+
buffer.writeInt16LE(sample, 44 + i * 2);
|
|
64
|
+
}
|
|
65
|
+
return buffer.toString("base64");
|
|
66
|
+
}
|