@burdenoff/fe-libs 2026.1023.16 → 2026.1024.2
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/LiveAvatarStage.js +5 -1
- package/dist/shared/assistant/avatar/live/LiveAvatarTabView.js +28 -25
- package/dist/shared/assistant/avatar/live/avatarSessionClient.d.ts +17 -1
- package/dist/shared/assistant/avatar/live/avatarSessionClient.js +81 -64
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.d.ts +1 -1
- package/dist/shared/assistant/avatar/live/createLiveAvatarSeam.js +61 -50
- package/dist/shared/assistant/avatar/live/liveAvatarController.d.ts +25 -5
- package/dist/shared/assistant/avatar/live/liveAvatarController.js +166 -156
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.d.ts +5 -3
- package/dist/shared/assistant/avatar/live/liveAvatarStatus.js +4 -3
- package/dist/shared/assistant/avatar/useAvatarCopy.d.ts +9 -3
- package/dist/shared/assistant/avatar/useAvatarCopy.js +7 -1
- package/dist/shared/assistant/i18nManifest.d.ts +4 -0
- package/dist/shared/assistant/i18nManifest.js +4 -0
- package/package.json +1 -1
|
@@ -98,8 +98,18 @@ function j() {
|
|
|
98
98
|
function M(e) {
|
|
99
99
|
if (!(typeof window > "u")) return (t) => (window.addEventListener(e, t), () => window.removeEventListener(e, t));
|
|
100
100
|
}
|
|
101
|
-
function N(
|
|
102
|
-
|
|
101
|
+
function N() {
|
|
102
|
+
if (!(typeof window > "u" || typeof document > "u")) return (e) => {
|
|
103
|
+
let t = window, n = document, r = () => {
|
|
104
|
+
n.visibilityState === "visible" && e();
|
|
105
|
+
};
|
|
106
|
+
return n.addEventListener("visibilitychange", r), t.addEventListener("pageshow", e), () => {
|
|
107
|
+
n.removeEventListener("visibilitychange", r), t.removeEventListener("pageshow", e);
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function P(e = {}) {
|
|
112
|
+
let t = e.preferences ?? O, n = e.controller ?? {}, r = n.subscribeWorkspaceChange ?? M("burdenoff:workspace-changed"), i = n.subscribePageHide ?? M("pagehide"), a = n.subscribePageShow ?? N(), o = n.now ?? (() => Date.now()), u = p({
|
|
103
113
|
client: e.client ?? D(),
|
|
104
114
|
openRoom: e.openRoom ?? m,
|
|
105
115
|
scheduler: e.scheduler ?? s,
|
|
@@ -111,10 +121,11 @@ function N(e = {}) {
|
|
|
111
121
|
}),
|
|
112
122
|
startMeter: n.startMeter ?? ((e, t) => typeof MediaStream > "u" ? null : c(new MediaStream([e]), t)),
|
|
113
123
|
browserSupported: e.browserSupported ?? (() => w()),
|
|
114
|
-
now:
|
|
124
|
+
now: o,
|
|
115
125
|
newIdempotencyKey: n.newIdempotencyKey ?? (() => d()),
|
|
116
126
|
...r ? { subscribeWorkspaceChange: r } : {},
|
|
117
127
|
...i ? { subscribePageHide: i } : {},
|
|
128
|
+
...a ? { subscribePageShow: a } : {},
|
|
118
129
|
...n.idleMs === void 0 ? {} : { idleMs: n.idleMs },
|
|
119
130
|
...n.endBeforeDeadlineMs === void 0 ? {} : { endBeforeDeadlineMs: n.endBeforeDeadlineMs },
|
|
120
131
|
...n.connectTimeoutMs === void 0 ? {} : { connectTimeoutMs: n.connectTimeoutMs },
|
|
@@ -123,53 +134,53 @@ function N(e = {}) {
|
|
|
123
134
|
...n.stallMs === void 0 ? {} : { stallMs: n.stallMs },
|
|
124
135
|
...n.readinessProbe === void 0 ? {} : { readinessProbe: n.readinessProbe },
|
|
125
136
|
...e.onLog ? { onLog: e.onLog } : {}
|
|
126
|
-
}),
|
|
127
|
-
let i = v(
|
|
128
|
-
avatarVoices:
|
|
137
|
+
}), f = b(e.avatarVoices), T = e.avatarImages === void 0 ? null : _(e.avatarImages), E = e.avatarVoiceStore ?? k, P = () => E.getState(), F = (n, r) => {
|
|
138
|
+
let i = v(P(), {
|
|
139
|
+
avatarVoices: f,
|
|
129
140
|
avatarId: t.getState().avatarId,
|
|
130
141
|
...e.defaultAvatarVoiceMode ? { hostDefault: e.defaultAvatarVoiceMode } : {}
|
|
131
142
|
});
|
|
132
143
|
return i === null ? null : y(i, n, r.listVoices());
|
|
133
|
-
},
|
|
144
|
+
}, I = (e, t) => {
|
|
134
145
|
let n = {
|
|
135
146
|
...e,
|
|
136
147
|
voice: t
|
|
137
148
|
};
|
|
138
|
-
return n.audioOutput = x(
|
|
149
|
+
return n.audioOutput = x(u.createOutput(), () => {
|
|
139
150
|
n.voice = e.voice;
|
|
140
|
-
}, (e) =>
|
|
141
|
-
|
|
151
|
+
}, (e) => u.subscribe(() => {
|
|
152
|
+
u.getSnapshot().phase !== "ready" && e();
|
|
142
153
|
})), n;
|
|
143
154
|
};
|
|
144
155
|
return {
|
|
145
156
|
decorateSpeechEngine: (e) => {
|
|
146
157
|
let t = (t) => {
|
|
147
|
-
let n =
|
|
158
|
+
let n = F(t.lang, e), r = n === null ? t : {
|
|
148
159
|
...t,
|
|
149
160
|
voice: n
|
|
150
161
|
};
|
|
151
162
|
return {
|
|
152
163
|
voice: n,
|
|
153
|
-
target:
|
|
164
|
+
target: u.route(r, e)
|
|
154
165
|
};
|
|
155
166
|
}, n = null, r = () => {
|
|
156
167
|
let e = n;
|
|
157
168
|
n = null, e?.();
|
|
158
169
|
}, i = (t, r, i) => {
|
|
159
|
-
let
|
|
160
|
-
|
|
161
|
-
},
|
|
162
|
-
!
|
|
170
|
+
let a = !0, o = !1, s = () => void 0, c = () => {
|
|
171
|
+
a && (a = !1, n === c && (n = null), s());
|
|
172
|
+
}, l = () => o ? !1 : (o = !0, c(), !0), d = () => {
|
|
173
|
+
!a || !l() || (e.cancel(), i?.onError?.("output-left"));
|
|
163
174
|
};
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}), n =
|
|
175
|
+
s = u.subscribe(() => {
|
|
176
|
+
u.getSnapshot().phase !== "ready" && d();
|
|
177
|
+
}), n = c, r.audioOutput &&= A(r.audioOutput, d), r.fallback = !1, e.speak(t, r, {
|
|
167
178
|
...i,
|
|
168
179
|
onEnd: () => {
|
|
169
|
-
|
|
180
|
+
l() && i?.onEnd?.();
|
|
170
181
|
},
|
|
171
182
|
onError: (e) => {
|
|
172
|
-
|
|
183
|
+
l() && i?.onError?.(e);
|
|
173
184
|
}
|
|
174
185
|
});
|
|
175
186
|
};
|
|
@@ -179,26 +190,26 @@ function N(e = {}) {
|
|
|
179
190
|
listVoices: () => e.listVoices(),
|
|
180
191
|
subscribeVoices: (t) => e.subscribeVoices(t),
|
|
181
192
|
wouldSpeakOnAvatar: (e) => t(e).target === "avatar",
|
|
182
|
-
speak: (n,
|
|
193
|
+
speak: (n, a, o) => {
|
|
183
194
|
r();
|
|
184
|
-
let { voice:
|
|
185
|
-
if (
|
|
186
|
-
if (
|
|
187
|
-
e.cancel(),
|
|
195
|
+
let { voice: s, target: c } = t(a);
|
|
196
|
+
if (c !== "avatar") {
|
|
197
|
+
if (a.avatarOnly === !0) {
|
|
198
|
+
e.cancel(), o?.onError?.("output-left");
|
|
188
199
|
return;
|
|
189
200
|
}
|
|
190
|
-
e.speak(n,
|
|
201
|
+
e.speak(n, a, o);
|
|
191
202
|
return;
|
|
192
203
|
}
|
|
193
|
-
let
|
|
194
|
-
...
|
|
195
|
-
audioOutput:
|
|
196
|
-
} :
|
|
197
|
-
if (
|
|
198
|
-
i(n,
|
|
204
|
+
let l = s === null ? {
|
|
205
|
+
...a,
|
|
206
|
+
audioOutput: u.createOutput()
|
|
207
|
+
} : I(a, s);
|
|
208
|
+
if (a.avatarOnly === !0) {
|
|
209
|
+
i(n, l, o);
|
|
199
210
|
return;
|
|
200
211
|
}
|
|
201
|
-
e.speak(n,
|
|
212
|
+
e.speak(n, l, o);
|
|
202
213
|
},
|
|
203
214
|
cancel: () => {
|
|
204
215
|
r(), e.cancel();
|
|
@@ -206,7 +217,7 @@ function N(e = {}) {
|
|
|
206
217
|
};
|
|
207
218
|
},
|
|
208
219
|
Stage: ({ expanded: t, fallback: n }) => /* @__PURE__ */ C(g, {
|
|
209
|
-
controller:
|
|
220
|
+
controller: u,
|
|
210
221
|
expanded: t,
|
|
211
222
|
fallback: n,
|
|
212
223
|
...e.avatarNames ? { avatarNames: e.avatarNames } : {}
|
|
@@ -214,33 +225,33 @@ function N(e = {}) {
|
|
|
214
225
|
enabled: {
|
|
215
226
|
subscribe: (e) => t.subscribe(e),
|
|
216
227
|
getSnapshot: () => t.getState().avatarEnabled,
|
|
217
|
-
switchOff: () =>
|
|
218
|
-
voiceLive: (e) =>
|
|
228
|
+
switchOff: () => u.switchOff(),
|
|
229
|
+
voiceLive: (e) => u.setVoiceLive(e)
|
|
219
230
|
},
|
|
220
231
|
tab: {
|
|
221
232
|
offered: {
|
|
222
|
-
subscribe: (e) =>
|
|
223
|
-
getSnapshot: () =>
|
|
233
|
+
subscribe: (e) => u.subscribe(e),
|
|
234
|
+
getSnapshot: () => u.getSnapshot().tabOffered
|
|
224
235
|
},
|
|
225
236
|
ask: {
|
|
226
|
-
subscribe: (e) =>
|
|
227
|
-
getSnapshot: () => h(
|
|
237
|
+
subscribe: (e) => u.subscribe(e),
|
|
238
|
+
getSnapshot: () => h(u.getSnapshot(), o())
|
|
228
239
|
},
|
|
229
|
-
setOpen: (e) =>
|
|
230
|
-
heldByVoice: () =>
|
|
240
|
+
setOpen: (e) => u.setTabOpen(e),
|
|
241
|
+
heldByVoice: () => u.getSnapshot().heldByVoice,
|
|
231
242
|
View: (t) => /* @__PURE__ */ C(S, {
|
|
232
243
|
...t,
|
|
233
|
-
controller:
|
|
234
|
-
avatarVoices:
|
|
235
|
-
voiceStore:
|
|
244
|
+
controller: u,
|
|
245
|
+
avatarVoices: f,
|
|
246
|
+
voiceStore: E,
|
|
236
247
|
...e.avatarNames ? { avatarNames: e.avatarNames } : {},
|
|
237
|
-
...
|
|
248
|
+
...T ? { avatarImages: T } : {},
|
|
238
249
|
...e.defaultAvatarVoiceMode ? { defaultAvatarVoiceMode: e.defaultAvatarVoiceMode } : {}
|
|
239
250
|
})
|
|
240
251
|
},
|
|
241
|
-
controller:
|
|
242
|
-
dispose: () =>
|
|
252
|
+
controller: u,
|
|
253
|
+
dispose: () => u.dispose()
|
|
243
254
|
};
|
|
244
255
|
}
|
|
245
256
|
//#endregion
|
|
246
|
-
export {
|
|
257
|
+
export { P as createLiveAvatarSeam, w as isLiveAvatarBrowserSupported, T as liveAvatarAuthorization, E as liveAvatarWorkspaceAuthorization };
|
|
@@ -4,7 +4,7 @@ import { AvatarMeterHandle } from './avatarAudioMeter';
|
|
|
4
4
|
import { AvatarRoom, AvatarScheduler } from './avatarPorts';
|
|
5
5
|
import { AvatarTrackerConfig } from './avatarPlaybackTracker';
|
|
6
6
|
import { AvatarDecodedPiece, AvatarNotice, AvatarReplyOutputs } from './avatarReplyOutputs';
|
|
7
|
-
import { AvatarClientEndReason, AvatarSessionClient } from './avatarSessionClient';
|
|
7
|
+
import { AvatarBudgetScope, AvatarClientEndReason, AvatarSessionClient } from './avatarSessionClient';
|
|
8
8
|
import { AvatarReadinessProbeOptions } from './avatarTransport';
|
|
9
9
|
/** End after this long without a reply on the avatar while it is on (OD8, BACKEND-DESIGN §8.7). */
|
|
10
10
|
export declare const LIVE_AVATAR_IDLE_MS = 120000;
|
|
@@ -46,9 +46,9 @@ export interface LiveAvatarSnapshot {
|
|
|
46
46
|
readonly tabOffered: boolean;
|
|
47
47
|
/**
|
|
48
48
|
* After a "not now" refusal that said when (the server's Retry-After): the wall-clock ms a start may be tried again. Null otherwise.
|
|
49
|
-
* It goes with `problem`: cleared together, and both clear by themselves when the time comes
|
|
50
|
-
*
|
|
51
|
-
* earlier.
|
|
49
|
+
* It goes with `problem`: cleared together, and both clear by themselves when the time comes (its timer, or `recheckRetry` when the
|
|
50
|
+
* page is shown again after a system sleep made that timer late). A newer refusal (including a question that failed or was answered
|
|
51
|
+
* "not offered"), a workspace switch and a voice conversation starting outside the Avatar tab clear them earlier.
|
|
52
52
|
*/
|
|
53
53
|
readonly retryAt: number | null;
|
|
54
54
|
/** The avatar was turned on outside the tab during the voice conversation that is still live: closing the tab hands it back to Voice. */
|
|
@@ -66,6 +66,11 @@ export interface LiveAvatarSnapshot {
|
|
|
66
66
|
/** What the person must read before the avatar starts; null until the server said which version. */
|
|
67
67
|
readonly consentVersion: string | null;
|
|
68
68
|
readonly problem: AvatarProblem | null;
|
|
69
|
+
/**
|
|
70
|
+
* With the problem `budget-exhausted`, whose budget is used up when the server said (BOFF-9333): the person's own, their workspace's,
|
|
71
|
+
* or everyone's. Null otherwise: no scope sent (today's server), or another problem. It goes with `problem`, as `retryAt` does.
|
|
72
|
+
*/
|
|
73
|
+
readonly budgetScope: AvatarBudgetScope | null;
|
|
69
74
|
readonly notice: LiveAvatarNotice | null;
|
|
70
75
|
/** The browser blocks the avatar's sound; a tap on the stage (`resumeAudio`) lifts it. */
|
|
71
76
|
readonly audioBlocked: boolean;
|
|
@@ -112,11 +117,19 @@ export interface LiveAvatarControllerDeps {
|
|
|
112
117
|
readonly startMeter: (track: MediaStreamTrack, onChange: (audible: boolean) => void) => AvatarMeterHandle | null;
|
|
113
118
|
/** The browser can show the avatar at all (desktop Chromium first: GATE1B §10). */
|
|
114
119
|
readonly browserSupported: () => boolean;
|
|
115
|
-
/**
|
|
120
|
+
/**
|
|
121
|
+
* Wall-clock milliseconds: a refusal's retry time (`retryAt`), its lock and its re-check (`recheckRetry`); also the fallback for
|
|
122
|
+
* `endsAt` when the server announced no session length (the server's clock may differ).
|
|
123
|
+
*/
|
|
116
124
|
readonly now: () => number;
|
|
117
125
|
readonly newIdempotencyKey: () => string;
|
|
118
126
|
readonly subscribeWorkspaceChange?: (listener: () => void) => () => void;
|
|
119
127
|
readonly subscribePageHide?: (listener: () => void) => () => void;
|
|
128
|
+
/**
|
|
129
|
+
* The page is shown again (its document visible again, or shown from the back/forward cache): the listener is `recheckRetry`. The
|
|
130
|
+
* scheduler's monotonic clock does not count a system sleep, so after one a refusal's timer fires late; the wall clock (`now`) does.
|
|
131
|
+
*/
|
|
132
|
+
readonly subscribePageShow?: (listener: () => void) => () => void;
|
|
120
133
|
readonly idleMs?: number;
|
|
121
134
|
readonly endBeforeDeadlineMs?: number;
|
|
122
135
|
readonly connectTimeoutMs?: number;
|
|
@@ -152,6 +165,13 @@ export interface LiveAvatarController {
|
|
|
152
165
|
* time (`retryAt`) that has not come.
|
|
153
166
|
*/
|
|
154
167
|
confirm(): void;
|
|
168
|
+
/**
|
|
169
|
+
* BOFF-9333 UI-11: once the wall clock has reached a refusal's retry time (`retryAt`), clear the refusal now, as its timer does: the
|
|
170
|
+
* problem, whose budget it was, the time, and the timer with them. That timer runs on the scheduler's monotonic clock, which a system
|
|
171
|
+
* sleep stops (macOS, Linux), so after one it fires late. Runs when the page is shown again (`subscribePageShow`); a host with its own
|
|
172
|
+
* wake signal may call it too. With no time, or before it, it does nothing: nothing is cleared early, and the timer stays as it is.
|
|
173
|
+
*/
|
|
174
|
+
recheckRetry(): void;
|
|
155
175
|
/**
|
|
156
176
|
* The Avatar tab opened or closed (BOFF-9341). Open: the avatar may be asked for with no voice conversation, and an avatar already on
|
|
157
177
|
* is adopted; a question already in flight is asked again, choose only. Close: any question, choice or session ends as the person's
|