@burdenoff/fe-libs 2026.1016.1 → 2026.1016.3
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/shared/assistant/avatar/live/AvatarFace.d.ts +13 -0
- package/dist/shared/assistant/avatar/live/AvatarFace.js +46 -0
- package/dist/shared/assistant/avatar/live/LiveAvatarTabView.d.ts +2 -0
- package/dist/shared/assistant/avatar/live/LiveAvatarTabView.js +172 -145
- package/dist/shared/assistant/avatar/live/avatarFaces.d.ts +31 -0
- package/dist/shared/assistant/avatar/live/avatarFaces.js +33 -0
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.d.ts +12 -0
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.js +142 -75
- package/dist/shared/assistant/avatar/live/liveAvatarController.d.ts +5 -0
- package/dist/shared/assistant/avatar/live/liveAvatarController.js +3 -1
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.d.ts +14 -0
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.js +11 -2
- package/dist/shared/assistant/avatar/useAvatarCopy.d.ts +42 -0
- package/dist/shared/assistant/avatar/useAvatarCopy.js +113 -75
- package/dist/shared/assistant/i18nManifest.d.ts +28 -0
- package/dist/shared/assistant/i18nManifest.js +28 -0
- package/dist/shared/assistant/index.d.ts +8 -0
- package/dist/shared/assistant/speech/replySpeechRequests.d.ts +84 -0
- package/dist/shared/assistant/speech/replySpeechRequests.js +70 -0
- package/dist/shared/assistant/speech/routingSpeechEngine.js +2 -1
- package/dist/shared/assistant/speech/types.d.ts +28 -1
- package/dist/shared/assistant/ui/AIAssistantPanel.js +128 -119
- package/dist/shared/assistant/ui/AssistantChatArea.js +1572 -1430
- package/dist/shared/assistant/ui/AssistantSpeechProvider.js +235 -191
- package/dist/shared/assistant/ui/assistantLiveAvatarSeam.d.ts +40 -0
- package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.d.ts +6 -0
- package/dist/shared/assistant/ui/avatar/AssistantAvatarTab.js +99 -52
- package/dist/shared/assistant/ui/avatar/AvatarTabAskBox.d.ts +8 -0
- package/dist/shared/assistant/ui/avatar/AvatarTabAskBox.js +87 -0
- package/dist/shared/assistant/ui/avatar/AvatarTabLastExchange.d.ts +13 -0
- package/dist/shared/assistant/ui/avatar/AvatarTabLastExchange.js +97 -0
- package/dist/shared/assistant/ui/avatar/avatarAskGate.d.ts +104 -0
- package/dist/shared/assistant/ui/avatar/avatarAskGate.js +39 -0
- package/dist/shared/assistant/ui/avatar/avatarTabDraft.d.ts +17 -0
- package/dist/shared/assistant/ui/avatar/avatarTabDraft.js +22 -0
- package/dist/shared/assistant/ui/avatar/avatarTabExchange.d.ts +47 -0
- package/dist/shared/assistant/ui/avatar/avatarTabExchange.js +50 -0
- package/dist/shared/assistant/ui/panelOverlays.d.ts +8 -1
- package/dist/shared/assistant/ui/panelOverlays.js +1 -1
- package/dist/shared/providers/shell/I18nProvider.js +3 -3
- package/dist/shared-assistant.js +260 -252
- package/package.json +1 -1
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import { ensureWorkspaceToken as e, getStoredAuthToken as t, getStoredWorkspaceId as n, resolveGatewayUrl as r } from "../../../graphql/fetch.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
2
|
+
import { isOutputRefusal as i } from "../../speech/pieceSink.js";
|
|
3
|
+
import { readSpeechEngineConfig as a } from "../../speech/createSpeechEngine.js";
|
|
4
|
+
import { useAvatarPreferencesStore as o } from "../avatarPreferences.js";
|
|
5
|
+
import { realAvatarScheduler as s } from "./avatarPorts.js";
|
|
6
|
+
import { startAvatarAudioMeter as c } from "./avatarAudioMeter.js";
|
|
7
|
+
import { decodeMp3ToPcm16k as l } from "./avatarAudioDecode.js";
|
|
8
|
+
import { avatarApiBaseFromTtsEndpoint as u, avatarIdempotencyKey as d, createAvatarSessionClient as f } from "./avatarSessionClient.js";
|
|
9
|
+
import { createLiveAvatarController as p } from "./liveAvatarController.js";
|
|
10
|
+
import { openLiveKitAvatarRoom as m } from "./liveKitAvatarRoom.js";
|
|
11
|
+
import { liveAvatarAskState as h } from "./liveAvatarStatus.js";
|
|
12
|
+
import { LiveAvatarStageView as g } from "./LiveAvatarStage.js";
|
|
13
|
+
import { sanitizeAvatarImages as _ } from "./avatarFaces.js";
|
|
14
|
+
import { avatarSpeakerFor as v, hostedAvatarVoice as y, liveAvatarVoicesFrom as b, restoreVoiceWhenOutputLeaves as x } from "./avatarVoice.js";
|
|
15
|
+
import { LiveAvatarTabView as S } from "./LiveAvatarTabView.js";
|
|
16
|
+
import { jsx as C } from "react/jsx-runtime";
|
|
14
17
|
//#region src/shared/assistant/avatar/live/createLiveAvatarSeam.tsx
|
|
15
|
-
function
|
|
18
|
+
function w(e = globalThis) {
|
|
16
19
|
let t = e;
|
|
17
20
|
if (typeof t.RTCPeerConnection != "function" || typeof t.OfflineAudioContext != "function" || typeof t.AudioContext != "function" || typeof t.MediaStream != "function") return !1;
|
|
18
21
|
let n = t.navigator, r = n?.userAgentData;
|
|
@@ -23,14 +26,14 @@ function x(e = globalThis) {
|
|
|
23
26
|
let i = n?.userAgent ?? "";
|
|
24
27
|
return /\b(?:Chrome|Chromium)\//.test(i) && !/\b(?:Edg|OPR|SamsungBrowser)\/|Mobile|Android|iPhone|iPad/.test(i);
|
|
25
28
|
}
|
|
26
|
-
function
|
|
27
|
-
let e =
|
|
29
|
+
function T() {
|
|
30
|
+
let e = a().getHeaders?.() ?? {};
|
|
28
31
|
for (let [t, n] of Object.entries(e)) if (t.toLowerCase() === "authorization" && typeof n == "string" && n.trim() !== "") return n.trim();
|
|
29
32
|
let n = t();
|
|
30
33
|
return n ? `Bearer ${n}` : null;
|
|
31
34
|
}
|
|
32
|
-
async function
|
|
33
|
-
let i = n(), a =
|
|
35
|
+
async function E(t) {
|
|
36
|
+
let i = n(), a = T(), o = a?.replace(/^Bearer\s+/i, "") ?? null;
|
|
34
37
|
if (!i || !o) return null;
|
|
35
38
|
let s = t.refused?.replace(/^Bearer\s+/i, ""), c = await e({
|
|
36
39
|
url: r("workspace"),
|
|
@@ -39,60 +42,77 @@ async function C(t) {
|
|
|
39
42
|
currentQuery: "liveAvatarSession",
|
|
40
43
|
...t.fresh ? { issuanceGuard: {
|
|
41
44
|
identityKey: "liveAvatarSession",
|
|
42
|
-
isCurrent: () => n() === i &&
|
|
45
|
+
isCurrent: () => n() === i && T() === a,
|
|
43
46
|
accepts: (e, t) => e !== s && t === i
|
|
44
47
|
} } : {}
|
|
45
48
|
});
|
|
46
49
|
return c ? `Bearer ${c}` : null;
|
|
47
50
|
}
|
|
48
|
-
function
|
|
51
|
+
function D() {
|
|
49
52
|
let e = null;
|
|
50
53
|
return () => {
|
|
51
|
-
let t = typeof location > "u" ? void 0 : location.href, n =
|
|
54
|
+
let t = typeof location > "u" ? void 0 : location.href, n = u(a().endpoint, t);
|
|
52
55
|
return n === null ? null : (e?.base !== n && (e = {
|
|
53
56
|
base: n,
|
|
54
|
-
client:
|
|
57
|
+
client: f({
|
|
55
58
|
baseUrl: n,
|
|
56
|
-
getAuthorization:
|
|
57
|
-
getWorkspaceAuthorization:
|
|
59
|
+
getAuthorization: T,
|
|
60
|
+
getWorkspaceAuthorization: E
|
|
58
61
|
})
|
|
59
62
|
}), e.client);
|
|
60
63
|
};
|
|
61
64
|
}
|
|
62
|
-
var
|
|
63
|
-
getState: () =>
|
|
64
|
-
setAvatarEnabled: (e) =>
|
|
65
|
-
setAvatarId: (e) =>
|
|
66
|
-
subscribe: (e) =>
|
|
67
|
-
},
|
|
68
|
-
getState: () =>
|
|
69
|
-
subscribe: (e) =>
|
|
70
|
-
setVoiceMode: (e) =>
|
|
71
|
-
setAvatarSpeaker: (e) =>
|
|
65
|
+
var O = {
|
|
66
|
+
getState: () => o.getState(),
|
|
67
|
+
setAvatarEnabled: (e) => o.getState().setAvatarEnabled(e),
|
|
68
|
+
setAvatarId: (e) => o.getState().setAvatarId(e),
|
|
69
|
+
subscribe: (e) => o.subscribe(() => e())
|
|
70
|
+
}, k = {
|
|
71
|
+
getState: () => o.getState(),
|
|
72
|
+
subscribe: (e) => o.subscribe(() => e()),
|
|
73
|
+
setVoiceMode: (e) => o.getState().setVoiceMode(e),
|
|
74
|
+
setAvatarSpeaker: (e) => o.getState().setAvatarSpeaker(e)
|
|
72
75
|
};
|
|
73
|
-
function
|
|
76
|
+
function A(e, t) {
|
|
77
|
+
let n = (e) => {
|
|
78
|
+
i(e) || t();
|
|
79
|
+
};
|
|
80
|
+
return {
|
|
81
|
+
write: (t, r, i) => {
|
|
82
|
+
let a = e.write(t, r, i);
|
|
83
|
+
return a.then(void 0, n), a;
|
|
84
|
+
},
|
|
85
|
+
drain: () => {
|
|
86
|
+
let t = e.drain();
|
|
87
|
+
return t.then(void 0, n), t;
|
|
88
|
+
},
|
|
89
|
+
retract: (t) => e.retract(t),
|
|
90
|
+
cancel: () => e.cancel()
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function j() {
|
|
74
94
|
if (typeof document > "u") return null;
|
|
75
95
|
let e = document.createElement("audio");
|
|
76
96
|
return e.autoplay = !0, e.hidden = !0, e.setAttribute("data-testid", "assistant-live-avatar-audio"), document.body.appendChild(e), e;
|
|
77
97
|
}
|
|
78
|
-
function
|
|
98
|
+
function M(e) {
|
|
79
99
|
if (!(typeof window > "u")) return (t) => (window.addEventListener(e, t), () => window.removeEventListener(e, t));
|
|
80
100
|
}
|
|
81
|
-
function
|
|
82
|
-
let t = e.preferences ??
|
|
83
|
-
client: e.client ??
|
|
84
|
-
openRoom: e.openRoom ??
|
|
85
|
-
scheduler: e.scheduler ??
|
|
101
|
+
function N(e = {}) {
|
|
102
|
+
let t = e.preferences ?? O, n = e.controller ?? {}, r = n.subscribeWorkspaceChange ?? M("burdenoff:workspace-changed"), i = n.subscribePageHide ?? M("pagehide"), a = p({
|
|
103
|
+
client: e.client ?? D(),
|
|
104
|
+
openRoom: e.openRoom ?? m,
|
|
105
|
+
scheduler: e.scheduler ?? s,
|
|
86
106
|
preferences: t,
|
|
87
|
-
decode: n.decode ?? ((e, t) =>
|
|
88
|
-
createAudioElement: n.createAudioElement ??
|
|
107
|
+
decode: n.decode ?? ((e, t) => l(e, { signal: t })),
|
|
108
|
+
createAudioElement: n.createAudioElement ?? j,
|
|
89
109
|
releaseAudioElement: n.releaseAudioElement ?? ((e) => {
|
|
90
110
|
e.srcObject = null, e.remove();
|
|
91
111
|
}),
|
|
92
|
-
startMeter: n.startMeter ?? ((e, t) => typeof MediaStream > "u" ? null :
|
|
93
|
-
browserSupported: e.browserSupported ?? (() =>
|
|
112
|
+
startMeter: n.startMeter ?? ((e, t) => typeof MediaStream > "u" ? null : c(new MediaStream([e]), t)),
|
|
113
|
+
browserSupported: e.browserSupported ?? (() => w()),
|
|
94
114
|
now: n.now ?? (() => Date.now()),
|
|
95
|
-
newIdempotencyKey: n.newIdempotencyKey ?? (() =>
|
|
115
|
+
newIdempotencyKey: n.newIdempotencyKey ?? (() => d()),
|
|
96
116
|
...r ? { subscribeWorkspaceChange: r } : {},
|
|
97
117
|
...i ? { subscribePageHide: i } : {},
|
|
98
118
|
...n.idleMs === void 0 ? {} : { idleMs: n.idleMs },
|
|
@@ -103,47 +123,89 @@ function k(e = {}) {
|
|
|
103
123
|
...n.stallMs === void 0 ? {} : { stallMs: n.stallMs },
|
|
104
124
|
...n.readinessProbe === void 0 ? {} : { readinessProbe: n.readinessProbe },
|
|
105
125
|
...e.onLog ? { onLog: e.onLog } : {}
|
|
106
|
-
}),
|
|
107
|
-
let i =
|
|
108
|
-
avatarVoices:
|
|
126
|
+
}), o = b(e.avatarVoices), u = e.avatarImages === void 0 ? null : _(e.avatarImages), f = e.avatarVoiceStore ?? k, T = () => f.getState(), E = (n, r) => {
|
|
127
|
+
let i = v(T(), {
|
|
128
|
+
avatarVoices: o,
|
|
109
129
|
avatarId: t.getState().avatarId,
|
|
110
130
|
...e.defaultAvatarVoiceMode ? { hostDefault: e.defaultAvatarVoiceMode } : {}
|
|
111
131
|
});
|
|
112
|
-
return i === null ? null :
|
|
113
|
-
},
|
|
132
|
+
return i === null ? null : y(i, n, r.listVoices());
|
|
133
|
+
}, N = (e, t) => {
|
|
114
134
|
let n = {
|
|
115
135
|
...e,
|
|
116
136
|
voice: t
|
|
117
137
|
};
|
|
118
|
-
return n.audioOutput =
|
|
138
|
+
return n.audioOutput = x(a.createOutput(), () => {
|
|
119
139
|
n.voice = e.voice;
|
|
120
140
|
}, (e) => a.subscribe(() => {
|
|
121
141
|
a.getSnapshot().phase !== "ready" && e();
|
|
122
142
|
})), n;
|
|
123
143
|
};
|
|
124
144
|
return {
|
|
125
|
-
decorateSpeechEngine: (e) =>
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
speak: (t, n, r) => {
|
|
131
|
-
let i = C(n.lang, e), o = i === null ? n : {
|
|
132
|
-
...n,
|
|
133
|
-
voice: i
|
|
145
|
+
decorateSpeechEngine: (e) => {
|
|
146
|
+
let t = (t) => {
|
|
147
|
+
let n = E(t.lang, e), r = n === null ? t : {
|
|
148
|
+
...t,
|
|
149
|
+
voice: n
|
|
134
150
|
};
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
151
|
+
return {
|
|
152
|
+
voice: n,
|
|
153
|
+
target: a.route(r, e)
|
|
154
|
+
};
|
|
155
|
+
}, n = null, r = () => {
|
|
156
|
+
let e = n;
|
|
157
|
+
n = null, e?.();
|
|
158
|
+
}, i = (t, r, i) => {
|
|
159
|
+
let o = !0, s = !1, c = () => void 0, l = () => {
|
|
160
|
+
o && (o = !1, n === l && (n = null), c());
|
|
161
|
+
}, u = () => s ? !1 : (s = !0, l(), !0), d = () => {
|
|
162
|
+
!o || !u() || (e.cancel(), i?.onError?.("output-left"));
|
|
163
|
+
};
|
|
164
|
+
c = a.subscribe(() => {
|
|
165
|
+
a.getSnapshot().phase !== "ready" && d();
|
|
166
|
+
}), n = l, r.audioOutput &&= A(r.audioOutput, d), r.fallback = !1, e.speak(t, r, {
|
|
167
|
+
...i,
|
|
168
|
+
onEnd: () => {
|
|
169
|
+
u() && i?.onEnd?.();
|
|
170
|
+
},
|
|
171
|
+
onError: (e) => {
|
|
172
|
+
u() && i?.onError?.(e);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
id: e.id,
|
|
178
|
+
isSupported: () => e.isSupported(),
|
|
179
|
+
listVoices: () => e.listVoices(),
|
|
180
|
+
subscribeVoices: (t) => e.subscribeVoices(t),
|
|
181
|
+
wouldSpeakOnAvatar: (e) => t(e).target === "avatar",
|
|
182
|
+
speak: (n, o, s) => {
|
|
183
|
+
r();
|
|
184
|
+
let { voice: c, target: l } = t(o);
|
|
185
|
+
if (l !== "avatar") {
|
|
186
|
+
if (o.avatarOnly === !0) {
|
|
187
|
+
e.cancel(), s?.onError?.("output-left");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
e.speak(n, o, s);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
let u = c === null ? {
|
|
194
|
+
...o,
|
|
195
|
+
audioOutput: a.createOutput()
|
|
196
|
+
} : N(o, c);
|
|
197
|
+
if (o.avatarOnly === !0) {
|
|
198
|
+
i(n, u, s);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
e.speak(n, u, s);
|
|
202
|
+
},
|
|
203
|
+
cancel: () => {
|
|
204
|
+
r(), e.cancel();
|
|
138
205
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
} : k(n, i), r);
|
|
143
|
-
},
|
|
144
|
-
cancel: () => e.cancel()
|
|
145
|
-
}),
|
|
146
|
-
Stage: ({ expanded: t, fallback: n }) => /* @__PURE__ */ b(m, {
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
Stage: ({ expanded: t, fallback: n }) => /* @__PURE__ */ C(g, {
|
|
147
209
|
controller: a,
|
|
148
210
|
expanded: t,
|
|
149
211
|
fallback: n,
|
|
@@ -160,14 +222,19 @@ function k(e = {}) {
|
|
|
160
222
|
subscribe: (e) => a.subscribe(e),
|
|
161
223
|
getSnapshot: () => a.getSnapshot().tabOffered
|
|
162
224
|
},
|
|
225
|
+
ask: {
|
|
226
|
+
subscribe: (e) => a.subscribe(e),
|
|
227
|
+
getSnapshot: () => h(a.getSnapshot())
|
|
228
|
+
},
|
|
163
229
|
setOpen: (e) => a.setTabOpen(e),
|
|
164
230
|
heldByVoice: () => a.getSnapshot().heldByVoice,
|
|
165
|
-
View: (t) => /* @__PURE__ */
|
|
231
|
+
View: (t) => /* @__PURE__ */ C(S, {
|
|
166
232
|
...t,
|
|
167
233
|
controller: a,
|
|
168
|
-
avatarVoices:
|
|
169
|
-
voiceStore:
|
|
234
|
+
avatarVoices: o,
|
|
235
|
+
voiceStore: f,
|
|
170
236
|
...e.avatarNames ? { avatarNames: e.avatarNames } : {},
|
|
237
|
+
...u ? { avatarImages: u } : {},
|
|
171
238
|
...e.defaultAvatarVoiceMode ? { defaultAvatarVoiceMode: e.defaultAvatarVoiceMode } : {}
|
|
172
239
|
})
|
|
173
240
|
},
|
|
@@ -176,4 +243,4 @@ function k(e = {}) {
|
|
|
176
243
|
};
|
|
177
244
|
}
|
|
178
245
|
//#endregion
|
|
179
|
-
export {
|
|
246
|
+
export { N as createLiveAvatarSeam, w as isLiveAvatarBrowserSupported, T as liveAvatarAuthorization, E as liveAvatarWorkspaceAuthorization };
|
|
@@ -52,6 +52,11 @@ export interface LiveAvatarSnapshot {
|
|
|
52
52
|
/** The avatar was turned on outside the tab during the voice conversation that is still live: closing the tab hands it back to Voice. */
|
|
53
53
|
readonly heldByVoice: boolean;
|
|
54
54
|
readonly phase: LiveAvatarPhase;
|
|
55
|
+
/**
|
|
56
|
+
* ★ BOFF-9360 (critic m1): the session's time limit is near (10 s before the server's end). The phase is still `ready` and a reply
|
|
57
|
+
* in flight finishes on the avatar, but no new reply goes to it, and the session ends between replies. False in every other phase.
|
|
58
|
+
*/
|
|
59
|
+
readonly closing: boolean;
|
|
55
60
|
/** The avatars the server offers, from the last availability answer. */
|
|
56
61
|
readonly avatars: readonly string[];
|
|
57
62
|
/** The avatar the next session starts with. */
|
|
@@ -11,6 +11,7 @@ var s = 12e4, c = 1e4, l = 8e3, ee = 5e3, u = 2e4, d = 1e3, f = {
|
|
|
11
11
|
retryAt: null,
|
|
12
12
|
heldByVoice: !1,
|
|
13
13
|
phase: "off",
|
|
14
|
+
closing: !1,
|
|
14
15
|
avatars: [],
|
|
15
16
|
selectedAvatarId: null,
|
|
16
17
|
consentVersion: null,
|
|
@@ -189,6 +190,7 @@ function g(s) {
|
|
|
189
190
|
keepalive: t.keepalive === !0
|
|
190
191
|
}).catch(() => void 0)), V({
|
|
191
192
|
phase: "off",
|
|
193
|
+
closing: !1,
|
|
192
194
|
audioBlocked: !1,
|
|
193
195
|
videoReady: !1,
|
|
194
196
|
...t.problem === void 0 ? v.problem !== null && m.has(v.problem) ? { problem: null } : {} : { problem: t.problem },
|
|
@@ -364,7 +366,7 @@ function g(s) {
|
|
|
364
366
|
}), G();
|
|
365
367
|
let _ = S > 0 ? u + S - ee - c.now() : f.endsAt - s.now(), v = Math.max(0, _ - d);
|
|
366
368
|
F = c.setTimeout(() => {
|
|
367
|
-
F = null, T === a && (w = !0, W.isBusy() || K("user", { notice: "time-limit" }));
|
|
369
|
+
F = null, T === a && (w = !0, V({ closing: !0 }), W.isBusy() || K("user", { notice: "time-limit" }));
|
|
368
370
|
}, v);
|
|
369
371
|
}
|
|
370
372
|
function Y(t) {
|
|
@@ -1,4 +1,18 @@
|
|
|
1
|
+
import { LiveAvatarAskState } from '../../ui/assistantLiveAvatarSeam';
|
|
1
2
|
import { AvatarCopy } from '../useAvatarCopy';
|
|
2
3
|
import { LiveAvatarSnapshot } from './liveAvatarController';
|
|
4
|
+
/**
|
|
5
|
+
* ★ BOFF-9360: whether the avatar can take a typed question's answer now, as the Avatar tab's ask box reads it
|
|
6
|
+
* (`LiveAvatarTabSeam.ask`). Pure, from the snapshot alone: it never asks `route()`, which has side effects.
|
|
7
|
+
* - `ready`: on, and nothing in the way;
|
|
8
|
+
* - `sound-blocked`: on, but the browser blocks its sound until a tap on the frame lifts it (critic m1);
|
|
9
|
+
* - `ending`: stopping, or near its time limit (`closing`), so no new reply goes to it (critic m1);
|
|
10
|
+
* - `starting`: being started or joined;
|
|
11
|
+
* - `locked`: off after a "not now" refusal that said when (`retryAt`): Turn on waits for that time (critic m11);
|
|
12
|
+
* - `off`: off, or being set up (checking, choosing).
|
|
13
|
+
* A device voice (no hosted voice to animate) is not predicted here: the route says so per reply, and the tab's
|
|
14
|
+
* status line already explains it (`needs-hosted-voice`).
|
|
15
|
+
*/
|
|
16
|
+
export declare function liveAvatarAskState(snapshot: LiveAvatarSnapshot): LiveAvatarAskState;
|
|
3
17
|
/** The words for the avatar's state line: what went wrong, what it is doing, or null. `now`: wall-clock ms, for the retry time. */
|
|
4
18
|
export declare function liveAvatarStatusText(snapshot: LiveAvatarSnapshot, copy: AvatarCopy, now?: number): string | null;
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
//#region src/shared/assistant/avatar/live/liveAvatarStatus.ts
|
|
2
|
-
function e(e
|
|
2
|
+
function e(e) {
|
|
3
|
+
switch (e.phase) {
|
|
4
|
+
case "ready": return e.closing ? "ending" : e.audioBlocked ? "sound-blocked" : "ready";
|
|
5
|
+
case "starting":
|
|
6
|
+
case "connecting": return "starting";
|
|
7
|
+
case "ending": return "ending";
|
|
8
|
+
default: return e.retryAt === null ? "off" : "locked";
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
function t(e, t, n = Date.now()) {
|
|
3
12
|
if (e.problem === "playback-blocked" && e.audioBlocked) return null;
|
|
4
13
|
let r = e.voiceLive;
|
|
5
14
|
if (e.problem !== null) {
|
|
@@ -18,4 +27,4 @@ function e(e, t, n = Date.now()) {
|
|
|
18
27
|
}
|
|
19
28
|
}
|
|
20
29
|
//#endregion
|
|
21
|
-
export { e as liveAvatarStatusText };
|
|
30
|
+
export { e as liveAvatarAskState, t as liveAvatarStatusText };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AvatarAskBlocker } from '../ui/avatar/avatarAskGate';
|
|
1
2
|
import { VoiceStartBlocker } from '../ui/voice/voiceStartGate';
|
|
2
3
|
/** What the person can be told went wrong; the adapter maps server codes onto these. */
|
|
3
4
|
export type AvatarProblem = 'unavailable' | 'not-ready' | 'already-running' | 'capacity' | 'rate-limited' | 'paused'
|
|
@@ -62,6 +63,47 @@ export interface AvatarCopy {
|
|
|
62
63
|
voiceStartBlocked: (blocker: VoiceStartBlocker) => string;
|
|
63
64
|
/** Said with a lasting reason: the avatar can be turned on, but it is asked by voice only. */
|
|
64
65
|
askNeedsVoice: string;
|
|
66
|
+
/**
|
|
67
|
+
* ★ BOFF-9360: the Avatar tab's typed questions. Said while the avatar is off with voice blocked for a reason that
|
|
68
|
+
* lasts, and typing open: the line `askNeedsVoice` was before typing existed (critic M3).
|
|
69
|
+
*/
|
|
70
|
+
askByTyping: string;
|
|
71
|
+
/** Said while the avatar is off, when neither typing nor voice can ask here (critic M3): turning it on is of no use. */
|
|
72
|
+
askNothing: string;
|
|
73
|
+
/** The ask box's textarea: its label, placeholder and keyboard hint. */
|
|
74
|
+
askLabel: string;
|
|
75
|
+
askPlaceholder: string;
|
|
76
|
+
askHint: string;
|
|
77
|
+
/** Send, as the composer names it (`chatInput.send`). */
|
|
78
|
+
askSend: string;
|
|
79
|
+
/** Why Send is off, in the gate's order (`avatarAskBlocker`); null for a live voice conversation (the box is hidden). */
|
|
80
|
+
askBlocked: (blocker: AvatarAskBlocker) => string | null;
|
|
81
|
+
/** A file dropped or pasted on the box is not taken. */
|
|
82
|
+
askNoFiles: string;
|
|
83
|
+
/** Before the first question of this opening. */
|
|
84
|
+
askEmpty: string;
|
|
85
|
+
/** The last exchange: its section's name and its two visible labels. */
|
|
86
|
+
askExchangeLabel: string;
|
|
87
|
+
askYouAsked: string;
|
|
88
|
+
askAnswer: string;
|
|
89
|
+
/** Which conversation the question went into (critic m9). */
|
|
90
|
+
askAskedIn: (title: string) => string;
|
|
91
|
+
askShowAll: string;
|
|
92
|
+
askShowLess: string;
|
|
93
|
+
/** While the answer is on its way: the voice session's own "Thinking…". */
|
|
94
|
+
askThinking: string;
|
|
95
|
+
/** What became of the answer's audio: never a claim that it was heard. */
|
|
96
|
+
askNotSpoken: string;
|
|
97
|
+
/** The avatar stopped part way (Turn off, the time limit, the avatar leaving): part of it was read, not all. */
|
|
98
|
+
askCut: string;
|
|
99
|
+
askNotHeard: string;
|
|
100
|
+
askFailed: string;
|
|
101
|
+
/** A failed turn whose question could not go back into the box (newer words were typed there): it is in Chat. */
|
|
102
|
+
askFailedInChat: string;
|
|
103
|
+
askAlsoInChat: string;
|
|
104
|
+
/** Stop reading the answer: the transcript's own words (`message.stopSpeaking*`). */
|
|
105
|
+
askStop: string;
|
|
106
|
+
askStopShort: string;
|
|
65
107
|
/** Why hands-free interrupt is off while the avatar is on (the pilot rule), and that it stays off after: the session's notice, and its control's reason. */
|
|
66
108
|
handsFreeOff: string;
|
|
67
109
|
/**
|