@runtypelabs/persona 4.25.0 → 4.26.1
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/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-Db61aI9J.d.cts → types-BwKTZhg9.d.cts} +14 -0
- package/dist/animations/{types-Db61aI9J.d.ts → types-BwKTZhg9.d.ts} +14 -0
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/animations-extra.d.cts +14 -0
- package/dist/animations-extra.d.ts +14 -0
- package/dist/approval-ui-QAKWNFNM.js +1 -0
- package/dist/approval-ui.cjs +2 -2
- package/dist/approval-ui.d.cts +186 -8
- package/dist/approval-ui.d.ts +186 -8
- package/dist/approval-ui.js +2 -2
- package/dist/{artifacts-ui-IGB5YKLO.js → artifacts-ui-NJGMM27I.js} +1 -1
- package/dist/artifacts-ui.cjs +4 -4
- package/dist/artifacts-ui.d.cts +186 -8
- package/dist/artifacts-ui.d.ts +186 -8
- package/dist/artifacts-ui.js +5 -5
- package/dist/chunk-2ANTRKTV.js +1 -0
- package/dist/chunk-4HPTPUC6.js +1 -0
- package/dist/chunk-6V3MNEKB.js +1 -0
- package/dist/chunk-GKPCIQPB.js +1 -0
- package/dist/chunk-HGUCGM3K.js +9 -0
- package/dist/chunk-IO5VVUKP.js +3 -0
- package/dist/chunk-J4J3Y2P2.js +1 -0
- package/dist/chunk-K6HKIP5K.js +1 -0
- package/dist/chunk-K7NA7G7J.js +1 -0
- package/dist/chunk-MXUTS3LB.js +1 -0
- package/dist/chunk-PDPVORUF.js +1 -0
- package/dist/chunk-QRKGQPU7.js +1 -0
- package/dist/chunk-S6PBWE75.js +1 -0
- package/dist/chunk-T7QM7YMF.js +1 -0
- package/dist/chunk-TR2H475E.js +1 -0
- package/dist/chunk-UPO4GUFC.js +1 -0
- package/dist/chunk-ZC66NAIR.js +1 -0
- package/dist/client-history-GOZWBDA5.js +1 -0
- package/dist/client-history.js +1 -0
- package/dist/client-stream-42FOI3EC.js +4 -0
- package/dist/client-stream.js +5 -0
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions-E7HJYWO6.js +161 -0
- package/dist/{context-mentions-inline-I2RDEBAK.js → context-mentions-inline-QVESLW55.js} +1 -1
- package/dist/context-mentions.cjs +7 -7
- package/dist/context-mentions.d.cts +186 -8
- package/dist/context-mentions.d.ts +186 -8
- package/dist/context-mentions.js +8 -8
- package/dist/event-stream-view-FOIJHFQO.js +1 -0
- package/dist/event-stream-view.cjs +1 -1
- package/dist/event-stream-view.d.cts +189 -31
- package/dist/event-stream-view.d.ts +189 -31
- package/dist/event-stream-view.js +1 -1
- package/dist/forms-ui.d.cts +227 -667
- package/dist/forms-ui.d.ts +227 -667
- package/dist/history-shell-QDQ44PSE.js +3 -0
- package/dist/history-shell.js +3 -0
- package/dist/{history-view-BD6OXLNA.js → history-view-NCFBI5GR.js} +2 -2
- package/dist/history-view.cjs +2 -2
- package/dist/history-view.d.cts +35 -1
- package/dist/history-view.d.ts +35 -1
- package/dist/history-view.js +2 -2
- package/dist/index.cjs +80 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +233 -738
- package/dist/index.d.ts +233 -738
- package/dist/index.global.js +3 -215
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +81 -75
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/launcher.global.js +3 -67
- package/dist/launcher.global.js.map +1 -1
- package/dist/markdown-parsers.js +22 -22
- package/dist/runtype-tts-entry-NFBVWR7N.js +1 -0
- package/dist/runtype-tts.js +1 -1
- package/dist/session-actions-ISSKSI66.js +1 -0
- package/dist/session-actions.js +1 -0
- package/dist/session-reconnect.d.cts +186 -8
- package/dist/session-reconnect.d.ts +186 -8
- package/dist/smart-dom-reader.cjs +13 -13
- package/dist/smart-dom-reader.d.cts +186 -8
- package/dist/smart-dom-reader.d.ts +186 -8
- package/dist/smart-dom-reader.js +11 -11
- package/dist/theme-editor-preview.cjs +116 -98
- package/dist/theme-editor-preview.d.cts +188 -8
- package/dist/theme-editor-preview.d.ts +188 -8
- package/dist/theme-editor-preview.js +49 -54
- package/dist/theme-editor.cjs +2 -2
- package/dist/theme-editor.d.cts +187 -23
- package/dist/theme-editor.d.ts +187 -23
- package/dist/theme-editor.js +2 -2
- package/dist/theme-reference.d.cts +14 -0
- package/dist/theme-reference.d.ts +14 -0
- package/dist/ui-extras-entry-WAYFKVNW.js +3 -0
- package/dist/ui-extras.js +72 -0
- package/dist/voice-runtime-XLU6YK2N.js +17 -0
- package/dist/voice-runtime.cjs +17 -1
- package/dist/voice-runtime.d.cts +11656 -232
- package/dist/voice-runtime.d.ts +11656 -232
- package/dist/voice-runtime.js +17 -1
- package/dist/voice-worklet-player.cjs +19 -4
- package/dist/voice-worklet-player.d.cts +9 -10
- package/dist/voice-worklet-player.d.ts +9 -10
- package/dist/voice-worklet-player.js +19 -4
- package/dist/webmcp-polyfill.js +1 -1
- package/dist/webmcp-runtime-V6ZWW3PI.js +6 -0
- package/dist/webmcp-runtime.cjs +2 -2
- package/dist/webmcp-runtime.d.cts +1 -33
- package/dist/webmcp-runtime.d.ts +1 -33
- package/dist/webmcp-runtime.js +2 -2
- package/dist/widget.css +1 -1
- package/package.json +11 -5
- package/src/approval-paused-tool-settle.test.ts +325 -0
- package/src/client-approve.test.ts +311 -0
- package/src/client-history-eager.ts +9 -0
- package/src/client-history-loader.ts +23 -0
- package/src/client-history.ts +579 -0
- package/src/client-resume.ts +177 -0
- package/src/client-stream-eager.ts +12 -0
- package/src/client-stream-loader.ts +25 -0
- package/src/client-stream.ts +1880 -0
- package/src/client.test.ts +31 -1
- package/src/client.ts +293 -2607
- package/src/components/approval-actions.test.ts +27 -0
- package/src/components/approval-actions.ts +27 -3
- package/src/components/message-bubble.test.ts +19 -0
- package/src/components/message-bubble.ts +2 -0
- package/src/components/registry.ts +6 -6
- package/src/components/tool-bubble.test.ts +9 -0
- package/src/components/tool-bubble.ts +1 -0
- package/src/history-shell-bundle.test.ts +54 -0
- package/src/history-shell-eager.ts +12 -0
- package/src/history-shell-loader.ts +27 -0
- package/src/history-shell.ts +2362 -0
- package/src/history-view-loader.ts +2 -0
- package/src/history-view.ts +3 -0
- package/src/index-core.ts +6 -0
- package/src/index-global.ts +90 -248
- package/src/index.ts +13 -0
- package/src/install.ts +6 -4
- package/src/internal/runtype-history-provider.test.ts +1 -0
- package/src/internal/runtype-history-provider.ts +28 -13
- package/src/plugins/registry.ts +8 -8
- package/src/session-actions-chunk.test.ts +55 -0
- package/src/session-actions-eager.ts +11 -0
- package/src/session-actions-loader.ts +37 -0
- package/src/session-actions.ts +909 -0
- package/src/session-history.test.ts +3 -1
- package/src/session.ts +895 -1538
- package/src/session.voice.test.ts +1171 -5
- package/src/styles/widget.css +58 -0
- package/src/theme-editor/state.ts +91 -91
- package/src/types.ts +204 -5
- package/src/ui-ask-user-sheet.ts +382 -0
- package/src/ui-extras-eager.ts +10 -0
- package/src/ui-extras-entry.ts +9 -0
- package/src/ui-extras-loader.ts +26 -0
- package/src/ui.artifact-rail-resize.test.ts +2 -1
- package/src/ui.ask-user-chunk.test.ts +93 -0
- package/src/ui.history-chunk.test.ts +2 -1
- package/src/ui.history-config-provider.test.ts +2 -1
- package/src/ui.history-confirm-fallback.test.ts +142 -0
- package/src/ui.history-controller.test.ts +2 -1
- package/src/ui.history-lifecycle.test.ts +2 -1
- package/src/ui.history-render-hooks.test.ts +2 -1
- package/src/ui.history-shell.test.ts +2 -1
- package/src/ui.rail-overlay.test.ts +2 -1
- package/src/ui.rail-resize.test.ts +2 -1
- package/src/ui.rail-trigger-pending.test.ts +2 -1
- package/src/ui.ts +340 -2770
- package/src/utils/attachment-manager.ts +67 -67
- package/src/utils/constants.ts +3 -0
- package/src/utils/context-mention-controller.ts +323 -323
- package/src/utils/context-mention-manager.ts +40 -40
- package/src/utils/context-mention-orchestrator.ts +28 -0
- package/src/utils/event-stream-buffer.ts +50 -50
- package/src/utils/event-stream-store.ts +43 -43
- package/src/utils/throughput-tracker.ts +34 -34
- package/src/utils/virtual-scroller.ts +67 -67
- package/src/utils/visitor-store.test.ts +50 -0
- package/src/utils/visitor-store.ts +23 -5
- package/src/voice/__fixtures__/voice-wire/README.md +1 -0
- package/src/voice/__fixtures__/voice-wire/client/cancel.json +3 -0
- package/src/voice/__fixtures__/voice-wire/client/context.json +4 -0
- package/src/voice/__fixtures__/voice-wire/client/delegation_result.json +6 -0
- package/src/voice/__fixtures__/voice-wire/client/delegation_update.json +6 -0
- package/src/voice/__fixtures__/voice-wire/client/ping.json +3 -0
- package/src/voice/__fixtures__/voice-wire/client/playback_progress.json +5 -0
- package/src/voice/__fixtures__/voice-wire/client/start.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/artifact.json +11 -0
- package/src/voice/__fixtures__/voice-wire/server/attached.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/audio_clear.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/audio_end.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_cancelled.json +5 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_completed.json +8 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_started.json +15 -0
- package/src/voice/__fixtures__/voice-wire/server/error.json +6 -0
- package/src/voice/__fixtures__/voice-wire/server/metrics.json +10 -0
- package/src/voice/__fixtures__/voice-wire/server/pong.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/session_config.json +16 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_final.json +7 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_interim.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_partial.json +6 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_update.json +10 -0
- package/src/voice/__fixtures__/voice-wire/server/warning.json +5 -0
- package/src/voice/audio-playback-manager.test.ts +57 -0
- package/src/voice/audio-playback-manager.ts +120 -98
- package/src/voice/browser-voice-provider.ts +37 -37
- package/src/voice/fallback-speech-engine.ts +22 -16
- package/src/voice/keyed-voice-transcript.ts +314 -0
- package/src/voice/mic-state-styles.ts +182 -0
- package/src/voice/read-aloud-controller.ts +46 -44
- package/src/voice/runtype-speech-engine.ts +35 -33
- package/src/voice/runtype-voice-provider.ts +680 -189
- package/src/voice/session-voice-wiring.ts +266 -0
- package/src/voice/voice-delegation.test.ts +71 -0
- package/src/voice/voice-delegation.ts +364 -0
- package/src/voice/voice-turn-tracker.ts +6 -6
- package/src/voice/voice.test.ts +1060 -8
- package/src/voice/worklet-playback-engine.test.ts +81 -0
- package/src/voice/worklet-playback-engine.ts +21 -3
- package/src/voice-runtime-loader.ts +4 -1
- package/src/voice-runtime.ts +7 -0
- package/src/webmcp-runtime-entry.ts +41 -39
- package/dist/approval-ui-3NMYNXBD.js +0 -1
- package/dist/chunk-5EIIHQLQ.js +0 -1
- package/dist/chunk-7CO4T5KB.js +0 -1
- package/dist/chunk-EFJBUH5F.js +0 -1
- package/dist/chunk-R2TMIMDI.js +0 -3
- package/dist/chunk-UTVLOTWB.js +0 -9
- package/dist/context-mentions-45MODWOY.js +0 -161
- package/dist/event-stream-view-GL3ADRY2.js +0 -1
- package/dist/runtype-tts-entry-UJAEF7NZ.js +0 -1
- package/dist/voice-runtime-7DA7MJH4.js +0 -1
- package/dist/webmcp-runtime-JI7T4QYF.js +0 -6
|
@@ -18,37 +18,39 @@ export type ReadAloudListener = (
|
|
|
18
18
|
) => void;
|
|
19
19
|
|
|
20
20
|
export class ReadAloudController {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
#engine: SpeechEngine | null = null;
|
|
22
|
+
#activeId: string | null = null;
|
|
23
|
+
#state: ReadAloudState = "idle";
|
|
24
|
+
#listeners = new Set<ReadAloudListener>();
|
|
25
25
|
// Bumped on every play/stop so a late async engine creation or a stale
|
|
26
26
|
// utterance callback from a superseded request can't mutate current state.
|
|
27
|
-
|
|
27
|
+
#generation = 0;
|
|
28
28
|
|
|
29
|
+
#resolveEngine: () => SpeechEngine | Promise<SpeechEngine> | null;
|
|
29
30
|
constructor(
|
|
30
|
-
|
|
31
|
-
) {
|
|
31
|
+
resolveEngine: () => SpeechEngine | Promise<SpeechEngine> | null
|
|
32
|
+
) {
|
|
33
|
+
this.#resolveEngine = resolveEngine;}
|
|
32
34
|
|
|
33
35
|
/** Whether the active engine supports pause/resume (vs. stop-only). */
|
|
34
36
|
get supportsPause(): boolean {
|
|
35
|
-
return this
|
|
37
|
+
return this.#engine?.supportsPause ?? true;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
/** Playback state for a message id (`idle` unless it's the active message). */
|
|
39
41
|
stateFor(id: string): ReadAloudState {
|
|
40
|
-
return this
|
|
42
|
+
return this.#activeId === id ? this.#state : "idle";
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
/** The message currently being read aloud, if any. */
|
|
44
46
|
activeMessageId(): string | null {
|
|
45
|
-
return this
|
|
47
|
+
return this.#activeId;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
/** Subscribe to state changes. Returns an unsubscribe function. */
|
|
49
51
|
onChange(listener: ReadAloudListener): () => void {
|
|
50
|
-
this
|
|
51
|
-
return () => this
|
|
52
|
+
this.#listeners.add(listener);
|
|
53
|
+
return () => this.#listeners.delete(listener);
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -57,22 +59,22 @@ export class ReadAloudController {
|
|
|
57
59
|
* start fresh when a different message is requested.
|
|
58
60
|
*/
|
|
59
61
|
toggle(id: string, request: SpeechRequest): void {
|
|
60
|
-
if (this
|
|
61
|
-
if (this
|
|
62
|
-
if (this
|
|
63
|
-
this
|
|
64
|
-
this
|
|
62
|
+
if (this.#activeId === id) {
|
|
63
|
+
if (this.#state === "playing") {
|
|
64
|
+
if (this.#engine?.supportsPause) {
|
|
65
|
+
this.#engine.pause();
|
|
66
|
+
this.#set(id, "paused");
|
|
65
67
|
} else {
|
|
66
68
|
this.stop();
|
|
67
69
|
}
|
|
68
70
|
return;
|
|
69
71
|
}
|
|
70
|
-
if (this
|
|
71
|
-
this
|
|
72
|
-
this
|
|
72
|
+
if (this.#state === "paused") {
|
|
73
|
+
this.#engine?.resume();
|
|
74
|
+
this.#set(id, "playing");
|
|
73
75
|
return;
|
|
74
76
|
}
|
|
75
|
-
if (this
|
|
77
|
+
if (this.#state === "loading") {
|
|
76
78
|
this.stop();
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
@@ -82,55 +84,55 @@ export class ReadAloudController {
|
|
|
82
84
|
|
|
83
85
|
/** Start (or restart) playback for a message, stopping any current playback. */
|
|
84
86
|
async play(id: string, request: SpeechRequest): Promise<void> {
|
|
85
|
-
const generation = ++this
|
|
86
|
-
this
|
|
87
|
-
this
|
|
87
|
+
const generation = ++this.#generation;
|
|
88
|
+
this.#engine?.stop();
|
|
89
|
+
this.#set(id, "loading");
|
|
88
90
|
|
|
89
91
|
try {
|
|
90
|
-
if (!this
|
|
91
|
-
const resolved = await this
|
|
92
|
-
if (generation !== this
|
|
92
|
+
if (!this.#engine) {
|
|
93
|
+
const resolved = await this.#resolveEngine();
|
|
94
|
+
if (generation !== this.#generation) return; // superseded mid-resolve
|
|
93
95
|
if (!resolved) {
|
|
94
|
-
this
|
|
96
|
+
this.#set(null, "idle");
|
|
95
97
|
return;
|
|
96
98
|
}
|
|
97
|
-
this
|
|
99
|
+
this.#engine = resolved;
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
this
|
|
102
|
+
this.#engine.speak(request, {
|
|
101
103
|
onStart: () => {
|
|
102
|
-
if (generation === this
|
|
104
|
+
if (generation === this.#generation) this.#set(id, "playing");
|
|
103
105
|
},
|
|
104
106
|
onEnd: () => {
|
|
105
|
-
if (generation === this
|
|
107
|
+
if (generation === this.#generation) this.#set(null, "idle");
|
|
106
108
|
},
|
|
107
109
|
onError: () => {
|
|
108
|
-
if (generation === this
|
|
110
|
+
if (generation === this.#generation) this.#set(null, "idle");
|
|
109
111
|
},
|
|
110
112
|
});
|
|
111
113
|
} catch {
|
|
112
|
-
if (generation === this
|
|
114
|
+
if (generation === this.#generation) this.#set(null, "idle");
|
|
113
115
|
}
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
/** Stop playback and return to idle. */
|
|
117
119
|
stop(): void {
|
|
118
|
-
this
|
|
119
|
-
this
|
|
120
|
-
this
|
|
120
|
+
this.#generation++;
|
|
121
|
+
this.#engine?.stop();
|
|
122
|
+
this.#set(null, "idle");
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
/** Drop the controller and its engine (called on widget teardown). */
|
|
124
126
|
destroy(): void {
|
|
125
127
|
this.stop();
|
|
126
|
-
this
|
|
127
|
-
this
|
|
128
|
-
this
|
|
128
|
+
this.#engine?.destroy?.();
|
|
129
|
+
this.#engine = null;
|
|
130
|
+
this.#listeners.clear();
|
|
129
131
|
}
|
|
130
132
|
|
|
131
|
-
|
|
132
|
-
this
|
|
133
|
-
this
|
|
134
|
-
for (const listener of this
|
|
133
|
+
#set(id: string | null, state: ReadAloudState): void {
|
|
134
|
+
this.#activeId = state === "idle" ? null : id;
|
|
135
|
+
this.#state = state;
|
|
136
|
+
for (const listener of this.#listeners) listener(this.#activeId, this.#state);
|
|
135
137
|
}
|
|
136
138
|
}
|
|
@@ -85,42 +85,44 @@ export class RuntypeSpeechEngine implements SpeechEngine {
|
|
|
85
85
|
// speechSynthesis.pause().
|
|
86
86
|
readonly supportsPause = true;
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
#player: PcmStreamPlayer | null = null;
|
|
89
|
+
#playerPromise: Promise<PcmStreamPlayer> | null = null;
|
|
90
90
|
// Bumped on every speak()/stop() so a superseded request's async callbacks and
|
|
91
91
|
// its in-flight stream read loop become no-ops.
|
|
92
|
-
|
|
92
|
+
#generation = 0;
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
readonly #opts: RuntypeSpeechEngineOptions;
|
|
95
|
+
constructor(opts: RuntypeSpeechEngineOptions) {
|
|
96
|
+
this.#opts = opts;}
|
|
95
97
|
|
|
96
98
|
// Create one player lazily (a worklet engine's addModule is async), then reuse
|
|
97
99
|
// it across speaks; flush() between replies clears the queue without tearing
|
|
98
100
|
// down the AudioContext. Defaults to the in-bundle AudioPlaybackManager.
|
|
99
|
-
|
|
100
|
-
return (this
|
|
101
|
-
this
|
|
102
|
-
? this
|
|
101
|
+
#ensurePlayer(): Promise<PcmStreamPlayer> {
|
|
102
|
+
return (this.#playerPromise ??= Promise.resolve(
|
|
103
|
+
this.#opts.createPlaybackEngine
|
|
104
|
+
? this.#opts.createPlaybackEngine()
|
|
103
105
|
: new AudioPlaybackManager(24000, {
|
|
104
|
-
prebufferMs: this
|
|
106
|
+
prebufferMs: this.#opts.prebufferMs ?? 200,
|
|
105
107
|
}),
|
|
106
|
-
).then((player) => (this
|
|
108
|
+
).then((player) => (this.#player = player)));
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
speak(request: SpeechRequest, callbacks: SpeechCallbacks): void {
|
|
110
|
-
const gen = ++this
|
|
112
|
+
const gen = ++this.#generation;
|
|
111
113
|
// Run the async fetch/stream without making speak() itself async — the
|
|
112
114
|
// widget surfaces the time until audio starts as the "loading" state.
|
|
113
|
-
void this
|
|
115
|
+
void this.#run(gen, request, callbacks);
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
|
|
118
|
+
async #run(
|
|
117
119
|
gen: number,
|
|
118
120
|
request: SpeechRequest,
|
|
119
121
|
callbacks: SpeechCallbacks,
|
|
120
122
|
): Promise<void> {
|
|
121
123
|
try {
|
|
122
|
-
const player = await this
|
|
123
|
-
if (gen !== this
|
|
124
|
+
const player = await this.#ensurePlayer();
|
|
125
|
+
if (gen !== this.#generation) return; // superseded while the worklet booted
|
|
124
126
|
player.flush(); // drop any prior playback (and its callbacks)
|
|
125
127
|
player.resume(); // clear a prior pause so this reply isn't stuck suspended
|
|
126
128
|
|
|
@@ -130,14 +132,14 @@ export class RuntypeSpeechEngine implements SpeechEngine {
|
|
|
130
132
|
// no onStarted and an immediate onFinished, so the UI skips straight back
|
|
131
133
|
// to idle without a phantom "playing".
|
|
132
134
|
player.onStarted(() => {
|
|
133
|
-
if (gen === this
|
|
135
|
+
if (gen === this.#generation) callbacks.onStart?.();
|
|
134
136
|
});
|
|
135
137
|
player.onFinished(() => {
|
|
136
|
-
if (gen === this
|
|
138
|
+
if (gen === this.#generation) callbacks.onEnd?.();
|
|
137
139
|
});
|
|
138
140
|
|
|
139
|
-
const url = `${normalizeHost(this
|
|
140
|
-
this
|
|
141
|
+
const url = `${normalizeHost(this.#opts.host)}/v1/agents/${encodeURIComponent(
|
|
142
|
+
this.#opts.agentId,
|
|
141
143
|
)}/speak`;
|
|
142
144
|
const res = await fetch(url, {
|
|
143
145
|
method: "POST",
|
|
@@ -145,21 +147,21 @@ export class RuntypeSpeechEngine implements SpeechEngine {
|
|
|
145
147
|
"Content-Type": "application/json",
|
|
146
148
|
// Match Runtype's client-token auth convention. Never placed in the
|
|
147
149
|
// URL/query string.
|
|
148
|
-
Authorization: `Bearer ${this
|
|
150
|
+
Authorization: `Bearer ${this.#opts.clientToken}`,
|
|
149
151
|
},
|
|
150
152
|
body: JSON.stringify({
|
|
151
153
|
text: request.text,
|
|
152
|
-
voice: request.voice ?? this
|
|
154
|
+
voice: request.voice ?? this.#opts.voice,
|
|
153
155
|
format: "pcm",
|
|
154
156
|
}),
|
|
155
157
|
});
|
|
156
|
-
if (gen !== this
|
|
158
|
+
if (gen !== this.#generation) return; // superseded while awaiting headers
|
|
157
159
|
if (!res.ok || !res.body) throw new Error(await describeError(res));
|
|
158
160
|
|
|
159
161
|
const reader = res.body.getReader();
|
|
160
162
|
for (;;) {
|
|
161
163
|
const { done, value } = await reader.read();
|
|
162
|
-
if (gen !== this
|
|
164
|
+
if (gen !== this.#generation) {
|
|
163
165
|
// A newer speak()/stop() won — stop pulling and release the stream.
|
|
164
166
|
await reader.cancel().catch(() => {});
|
|
165
167
|
return;
|
|
@@ -170,31 +172,31 @@ export class RuntypeSpeechEngine implements SpeechEngine {
|
|
|
170
172
|
|
|
171
173
|
player.markStreamEnd();
|
|
172
174
|
} catch (err) {
|
|
173
|
-
if (gen !== this
|
|
175
|
+
if (gen !== this.#generation) return; // error from a superseded request
|
|
174
176
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
175
|
-
this
|
|
177
|
+
this.#opts.onError?.(error); // surface the reason (log, telemetry, …)
|
|
176
178
|
callbacks.onError?.(error); // and let the widget (or fallback) react
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
|
|
180
182
|
pause(): void {
|
|
181
|
-
this
|
|
183
|
+
this.#player?.pause();
|
|
182
184
|
}
|
|
183
185
|
|
|
184
186
|
resume(): void {
|
|
185
|
-
this
|
|
187
|
+
this.#player?.resume();
|
|
186
188
|
}
|
|
187
189
|
|
|
188
190
|
stop(): void {
|
|
189
|
-
this
|
|
190
|
-
this
|
|
191
|
+
this.#generation++; // invalidate any in-flight stream + pending onFinished
|
|
192
|
+
this.#player?.flush();
|
|
191
193
|
}
|
|
192
194
|
|
|
193
195
|
destroy(): void {
|
|
194
|
-
this
|
|
195
|
-
void this
|
|
196
|
-
this
|
|
197
|
-
this
|
|
196
|
+
this.#generation++;
|
|
197
|
+
void this.#player?.destroy();
|
|
198
|
+
this.#player = null;
|
|
199
|
+
this.#playerPromise = null;
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
|