@burdenoff/fe-libs 2026.1003.1 → 2026.1003.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.
Files changed (61) hide show
  1. package/dist/chrome/mobileTabBar/selectTabs.d.ts.map +1 -1
  2. package/dist/chrome/mobileTabBar/selectTabs.js +9 -8
  3. package/dist/chrome/sideNavigation/NavItemRenderer.d.ts.map +1 -1
  4. package/dist/chrome/sideNavigation/NavItemRenderer.js +62 -61
  5. package/dist/shared/assistant/conversation.d.ts +20 -6
  6. package/dist/shared/assistant/conversation.d.ts.map +1 -1
  7. package/dist/shared/assistant/history/historyMapping.d.ts.map +1 -1
  8. package/dist/shared/assistant/history/historyMapping.js +43 -24
  9. package/dist/shared/assistant/i18nManifest.d.ts +9 -0
  10. package/dist/shared/assistant/i18nManifest.d.ts.map +1 -1
  11. package/dist/shared/assistant/i18nManifest.js +9 -0
  12. package/dist/shared/assistant/index.d.ts +4 -0
  13. package/dist/shared/assistant/index.d.ts.map +1 -1
  14. package/dist/shared/assistant/localUiCommandCopy.d.ts +28 -0
  15. package/dist/shared/assistant/localUiCommandCopy.d.ts.map +1 -1
  16. package/dist/shared/assistant/localUiCommandCopy.js +54 -1
  17. package/dist/shared/assistant/localUiCommands.d.ts +33 -3
  18. package/dist/shared/assistant/localUiCommands.d.ts.map +1 -1
  19. package/dist/shared/assistant/localUiCommands.js +110 -59
  20. package/dist/shared/assistant/prewarm.d.ts +71 -0
  21. package/dist/shared/assistant/prewarm.d.ts.map +1 -1
  22. package/dist/shared/assistant/prewarm.js +49 -2
  23. package/dist/shared/assistant/speech/speechFeed.d.ts +63 -0
  24. package/dist/shared/assistant/speech/speechFeed.d.ts.map +1 -0
  25. package/dist/shared/assistant/speech/speechFeed.js +40 -0
  26. package/dist/shared/assistant/turnTimeline.d.ts +22 -2
  27. package/dist/shared/assistant/turnTimeline.d.ts.map +1 -1
  28. package/dist/shared/assistant/turnTimeline.js +18 -1
  29. package/dist/shared/assistant/turnTimingReport.d.ts.map +1 -1
  30. package/dist/shared/assistant/turnTimingReport.js +5 -4
  31. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  32. package/dist/shared/assistant/ui/AssistantChatArea.js +1096 -914
  33. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts +18 -1
  34. package/dist/shared/assistant/ui/AssistantMarkdownRenderer.d.ts.map +1 -1
  35. package/dist/shared/assistant/ui/AssistantSpeechProvider.d.ts.map +1 -1
  36. package/dist/shared/assistant/ui/AssistantSpeechProvider.js +198 -169
  37. package/dist/shared/assistant/ui/assistantOverlayState.d.ts +2 -1
  38. package/dist/shared/assistant/ui/assistantOverlayState.d.ts.map +1 -1
  39. package/dist/shared/assistant/ui/assistantOverlayState.js +1 -7
  40. package/dist/shared/assistant/ui/useVoiceSession.d.ts.map +1 -1
  41. package/dist/shared/assistant/ui/useVoiceSession.js +165 -153
  42. package/dist/shared/assistant/uiActions/backStack.d.ts +35 -0
  43. package/dist/shared/assistant/uiActions/backStack.d.ts.map +1 -0
  44. package/dist/shared/assistant/uiActions/backStack.js +28 -0
  45. package/dist/shared/assistant/uiActions/navigateAction.d.ts +41 -0
  46. package/dist/shared/assistant/uiActions/navigateAction.d.ts.map +1 -0
  47. package/dist/shared/assistant/uiActions/navigateAction.js +40 -0
  48. package/dist/shared/assistant/uiActions/navigationOutcome.d.ts +52 -0
  49. package/dist/shared/assistant/uiActions/navigationOutcome.d.ts.map +1 -0
  50. package/dist/shared/assistant/uiActions/navigationOutcome.js +61 -0
  51. package/dist/shared/assistant/voice/speakableText.d.ts +16 -1
  52. package/dist/shared/assistant/voice/speakableText.d.ts.map +1 -1
  53. package/dist/shared/assistant/voice/speakableText.js +116 -102
  54. package/dist/shared/assistant/voice/voiceSession.d.ts +12 -0
  55. package/dist/shared/assistant/voice/voiceSession.d.ts.map +1 -1
  56. package/dist/shared/assistant/voice/voiceSession.js +6 -0
  57. package/dist/shared/navigation/navTargetPath.d.ts +23 -0
  58. package/dist/shared/navigation/navTargetPath.d.ts.map +1 -0
  59. package/dist/shared/navigation/navTargetPath.js +6 -0
  60. package/dist/shared-assistant.js +154 -150
  61. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"useVoiceSession.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/useVoiceSession.ts"],"names":[],"mappings":"AAUA,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGpE,OAAO,EAgBL,KAAK,oBAAoB,EAE1B,MAAM,uBAAuB,CAAC;AAsC/B;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAC5B,SAAS,GAAG,eAAe,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAEvE;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;CAC7B;AAMD,UAAU,OAAO;IACf,+EAA+E;IAC/E;;;;;;;OAOG;IACH,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM;IACtB;;;OAGG;IACH,MAAM,EAAE,eAAe,KACpB,IAAI,CAAC;IACV;;;;OAIG;IACH,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,OAAO;;IA+uBtE,qEAAqE;;IAErE;;;;;;;OAOG;;IAEH,+DAA+D;;IAE/D;;;;;;;OAOG;;IAIH,0EAA0E;;IAE1E,6DAA6D;;IAE7D,sDAAsD;;;;uCApEvC,MAAM;;;IA2ErB,0EAA0E;qBAhqB1C,iBAAiB;IAkqBjD;;;OAGG;+BAhrBuC,OAAO;IAkrBjD;;;OAGG;0BA/oBE,iBAAiB;EA2qB3B"}
1
+ {"version":3,"file":"useVoiceSession.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/ui/useVoiceSession.ts"],"names":[],"mappings":"AAUA,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIpE,OAAO,EAgBL,KAAK,oBAAoB,EAE1B,MAAM,uBAAuB,CAAC;AAsC/B;;;;;;;;GAQG;AACH,MAAM,MAAM,kBAAkB,GAC5B,SAAS,GAAG,eAAe,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAEvE;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;CAC7B;AAMD,UAAU,OAAO;IACf,+EAA+E;IAC/E;;;;;;;OAOG;IACH,QAAQ,EAAE,CACR,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM;IACtB;;;OAGG;IACH,MAAM,EAAE,eAAe,KACpB,IAAI,CAAC;IACV;;;;OAIG;IACH,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACjD,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,OAAO;;IA4xBtE,qEAAqE;;IAErE;;;;;;;OAOG;;IAEH,+DAA+D;;IAE/D;;;;;;;OAOG;;IAIH,0EAA0E;;IAE1E,6DAA6D;;IAE7D,sDAAsD;;;;uCApEvC,MAAM;;;IA2ErB,0EAA0E;qBAtsB1C,iBAAiB;IAwsBjD;;;OAGG;+BAttBuC,OAAO;IAwtBjD;;;OAGG;0BArrBE,iBAAiB;EAitB3B"}
@@ -1,164 +1,176 @@
1
1
  import { useVoiceInput as e } from "../voice/useVoiceInput.js";
2
- import { INITIAL_SESSION as t, INTERRUPT_MAX_MS as ee, NOTHING_HEARD as n, SILENCE_SUBMIT_MS as te, advanceHeardClock as ne, isCapturing as r, isSubmittable as re, planListeningHold as ie, planReplyConsumption as ae, planVoiceAnnouncement as oe, spokenSoFar as i, voiceSessionReducer as se } from "../voice/voiceSession.js";
2
+ import { speechFeed as t } from "../speech/speechFeed.js";
3
+ import { INITIAL_SESSION as n, INTERRUPT_MAX_MS as ee, NOTHING_HEARD as r, SILENCE_SUBMIT_MS as te, advanceHeardClock as ne, isCapturing as i, isSubmittable as re, planListeningHold as ie, planReplyConsumption as ae, planVoiceAnnouncement as oe, spokenSoFar as a, voiceSessionReducer as se } from "../voice/voiceSession.js";
3
4
  import { captionChunks as ce } from "../voice/speechPlayback.js";
4
- import { turnClockMs as a } from "../turnTimeline.js";
5
+ import { turnClockMs as o } from "../turnTimeline.js";
5
6
  import { useAssistantSpeech as le } from "./AssistantSpeechProvider.js";
6
- import { useCallback as o, useEffect as s, useLayoutEffect as ue, useMemo as de, useReducer as fe, useRef as c, useState as l } from "react";
7
+ import { useCallback as s, useEffect as c, useLayoutEffect as ue, useMemo as de, useReducer as fe, useRef as l, useState as u } from "react";
7
8
  //#region src/shared/assistant/ui/useVoiceSession.ts
8
9
  var pe = 4e3, me = 2500, he = 5e3, ge = 12e3, _e = "data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YQAAAAA=";
9
- function u({ onSubmit: u, latestReply: d, language: ve }) {
10
- let f = c(null), [p, m] = fe(o((e, t) => se(e, t, f.current), []), t), h = le(), { setSessionSpeaking: g, setSessionMicOpen: _, speakingMessageId: v, stop: y } = h, ye = c(h.toggle), b = h.toggle;
10
+ function d({ onSubmit: d, latestReply: f, language: ve }) {
11
+ let p = l(null), [m, h] = fe(s((e, t) => se(e, t, p.current), []), n), g = le(), { setSessionSpeaking: _, setSessionMicOpen: v, speakingMessageId: y, stop: b } = g, x = l(g.toggle), S = g.toggle;
11
12
  ue(() => {
12
- ye.current = b;
13
- }, [b]);
14
- let x = c(null), S = c({}), C = c(n), w = c(null), T = c(!1), [E, D] = l(null), [O, k] = l(!1), [A, j] = l(!1), M = c(p);
15
- M.current = p;
16
- let N = c([]), P = c(null), F = c(!1), I = o(() => {
17
- N.current = [], P.current = null, F.current = !1;
18
- }, []), L = o(() => {
13
+ x.current = S;
14
+ }, [S]);
15
+ let C = l(null), w = l({}), T = l(r), E = l(null), D = l(!1), O = l(null), [k, A] = u(null), [j, M] = u(!1), [N, P] = u(!1), F = l(m);
16
+ F.current = m;
17
+ let I = l([]), L = l(null), R = l(!1), z = s(() => {
18
+ I.current = [], L.current = null, R.current = !1;
19
+ }, []), B = s(() => {
19
20
  for (;;) {
20
- let e = N.current.shift();
21
+ let e = I.current.shift();
21
22
  if (!e) return !1;
22
23
  if (!(e.stillWanted && !e.stillWanted())) {
23
- P.current = e, f.current = f.current ? `${f.current} ${e.text}` : e.text;
24
+ L.current = e, p.current = p.current ? `${p.current} ${e.text}` : e.text;
24
25
  try {
25
- ye.current(e.id, e.text, e.lang);
26
+ x.current(e.id, e.text, e.lang);
26
27
  } catch {
27
- P.current = null;
28
+ L.current = null;
28
29
  continue;
29
30
  }
30
31
  return !0;
31
32
  }
32
33
  }
33
- }, []), R = c(!1), z = o((e) => {
34
+ }, []), V = l(!1), H = s((e) => {
34
35
  let t = ie({
35
36
  requested: e,
36
- held: R.current,
37
- muted: M.current.muted
37
+ held: V.current,
38
+ muted: F.current.muted
38
39
  });
39
- R.current = t.held, t.mute !== null && m({
40
+ V.current = t.held, t.mute !== null && h({
40
41
  type: "mute",
41
42
  muted: t.mute
42
43
  });
43
- }, []), B = o((e) => {
44
- let t = oe(M.current);
45
- t !== "drop" && (P.current?.id === e.id || N.current.some((t) => t.id === e.id) || (N.current.push(e), t === "start" && !F.current && (F.current = !0, m({ type: "announce" }))));
46
- }, []), V = o((e) => {
47
- if (M.current.phase !== "thinking") {
48
- B(e);
44
+ }, []), U = s((e) => {
45
+ let t = oe(F.current);
46
+ t !== "drop" && (L.current?.id === e.id || I.current.some((t) => t.id === e.id) || (I.current.push(e), t === "start" && !R.current && (R.current = !0, h({ type: "announce" }))));
47
+ }, []), W = s((e) => {
48
+ if (F.current.phase !== "thinking") {
49
+ U(e);
49
50
  return;
50
51
  }
51
- N.current.push(e), F.current = !0, m({ type: "answered-locally" });
52
- }, [B]), H = c(d);
53
- H.current = d, s(() => {
54
- if (p.phase === "speaking") {
55
- f.current = d?.text ?? null;
52
+ I.current.push(e), R.current = !0, h({ type: "answered-locally" });
53
+ }, [U]), G = l(f);
54
+ G.current = f, c(() => {
55
+ if (m.phase === "speaking") {
56
+ let e = O.current;
57
+ p.current = e && E.current === e.id && f?.id !== e.id ? e.text : f?.text ?? null;
56
58
  return;
57
59
  }
58
- if (f.current === null) return;
60
+ if (p.current === null) return;
59
61
  let e = setTimeout(() => {
60
- f.current = null;
62
+ p.current = null;
61
63
  }, me);
62
64
  return () => clearTimeout(e);
63
- }, [p.phase, d]);
64
- let U = o((e, t) => {
65
- m({
65
+ }, [m.phase, f]);
66
+ let K = s((e, t) => {
67
+ h({
66
68
  type: "speech",
67
69
  transcript: e,
68
70
  final: t
69
71
  });
70
- }, []), W = c(0), G = o(() => {
71
- I(), y(), W.current = Date.now(), k(!0), m({ type: "interrupt" });
72
- }, [y, I]), K = e({
73
- onFinalize: o((e) => U(e, !0), [U]),
72
+ }, []), q = l(0), J = s(() => {
73
+ z(), b(), q.current = Date.now(), M(!0), h({ type: "interrupt" });
74
+ }, [b, z]), Y = e({
75
+ onFinalize: s((e) => K(e, !0), [K]),
74
76
  language: ve
75
77
  });
76
- s(() => {
77
- K.interim && U(K.interim, !1);
78
- }, [K.interim, U]), s(() => {
79
- if (x.current && clearTimeout(x.current), j(!1), C.current = ne(C.current, p, a()), p.phase !== "listening" || p.muted || !re(i(p))) return;
80
- let e = setTimeout(() => j(!0), 800), t = a();
81
- return x.current = setTimeout(() => {
82
- S.current = {
83
- speechEnded: C.current.at ?? t,
78
+ c(() => {
79
+ Y.interim && K(Y.interim, !1);
80
+ }, [Y.interim, K]), c(() => {
81
+ if (C.current && clearTimeout(C.current), P(!1), T.current = ne(T.current, m, o()), m.phase !== "listening" || m.muted || !re(a(m))) return;
82
+ let e = setTimeout(() => P(!0), 800), t = o();
83
+ return C.current = setTimeout(() => {
84
+ w.current = {
85
+ speechEnded: T.current.at ?? t,
84
86
  graceStarted: t,
85
- graceEnded: a()
86
- }, m({ type: "silence" });
87
+ graceEnded: o()
88
+ }, h({ type: "silence" });
87
89
  }, te), () => {
88
- clearTimeout(e), x.current && clearTimeout(x.current);
90
+ clearTimeout(e), C.current && clearTimeout(C.current);
89
91
  };
90
- }, [p]), s(() => {
91
- if (!O) return;
92
- let e = Date.now() - W.current, t = K.isListening ? Math.max(0, 500 - e) : Math.max(0, ee - e), n = setTimeout(() => k(!1), t);
92
+ }, [m]), c(() => {
93
+ if (!j) return;
94
+ let e = Date.now() - q.current, t = Y.isListening ? Math.max(0, 500 - e) : Math.max(0, ee - e), n = setTimeout(() => M(!1), t);
93
95
  return () => clearTimeout(n);
94
- }, [O, K.isListening]);
95
- let q = c("");
96
- p.phase === "listening" && (q.current = i(p)), s(() => {
97
- if (p.phase !== "thinking") return;
98
- _(!1), I();
99
- let e = q.current.trim();
100
- e && u(e, J.current ?? `vs-orphan-${Date.now().toString(36)}`, S.current), S.current = {}, C.current = n;
101
- }, [p.phase]), s(() => {
102
- let e = ae(d?.id, p.phase, w.current);
103
- e.claim && (w.current = d?.id ?? null, e.advance && d && m({
96
+ }, [j, Y.isListening]);
97
+ let X = l("");
98
+ m.phase === "listening" && (X.current = a(m)), c(() => {
99
+ if (m.phase !== "thinking") return;
100
+ v(!1), z();
101
+ let e = X.current.trim();
102
+ e && d(e, Z.current ?? `vs-orphan-${Date.now().toString(36)}`, w.current), w.current = {}, T.current = r;
103
+ }, [m.phase]), c(() => {
104
+ let e = ae(f?.id, m.phase, E.current);
105
+ e.claim && (E.current = f?.id ?? null, e.advance && f && h({
104
106
  type: "reply",
105
- text: d.text
107
+ text: f.text
106
108
  }));
107
- }, [d, p.phase]), s(() => {
108
- let e = v !== null;
109
- T.current && !e && (P.current = null, (M.current.phase !== "speaking" || !L()) && m({ type: "speech-ended" })), T.current = e;
110
- }, [v, L]), s(() => {
111
- p.phase !== "listening" && D((e) => e === "nothing-heard" ? null : e);
112
- }, [p.phase]), s(() => {
113
- if (p.phase !== "speaking" || v !== null) return;
109
+ }, [f, m.phase]), c(() => {
110
+ if (y === null || m.phase !== "thinking" || E.current === y) return;
111
+ let e = t.peek(y);
112
+ !e || e.channel !== "voice" || e.voiceSessionId === void 0 || e.voiceSessionId !== Z.current || (E.current = y, O.current = {
113
+ id: y,
114
+ text: e.text
115
+ }, h({
116
+ type: "reply-audio-started",
117
+ replyId: y
118
+ }));
119
+ }, [y, m.phase]), c(() => {
120
+ let e = y !== null;
121
+ D.current && !e && (L.current = null, (F.current.phase !== "speaking" || !B()) && h({ type: "speech-ended" })), D.current = e;
122
+ }, [y, B]), c(() => {
123
+ m.phase !== "listening" && A((e) => e === "nothing-heard" ? null : e);
124
+ }, [m.phase]), c(() => {
125
+ if (m.phase !== "speaking" || y !== null) return;
114
126
  let e = setTimeout(() => {
115
- T.current || (I(), m({ type: "speech-ended" }));
127
+ D.current || (z(), h({ type: "speech-ended" }));
116
128
  }, pe);
117
129
  return () => clearTimeout(e);
118
130
  }, [
119
- p.phase,
120
- v,
121
- I
122
- ]), s(() => {
123
- let e = r(p);
124
- _(e), e ? K.isActive || K.start("auto") : K.isActive && K.stop();
131
+ m.phase,
132
+ y,
133
+ z
134
+ ]), c(() => {
135
+ let e = i(m);
136
+ v(e), e ? Y.isActive || Y.start("auto") : Y.isActive && Y.stop();
125
137
  }, [
126
- p,
127
- K,
128
- _
129
- ]), s(() => {
130
- p.phase !== "speaking" || !F.current || (F.current = !1, L() || m({ type: "speech-ended" }));
131
- }, [p.phase, L]), s(() => {
132
- K.error === "not-allowed" || K.error === "audio-capture" ? m({
138
+ m,
139
+ Y,
140
+ v
141
+ ]), c(() => {
142
+ m.phase !== "speaking" || !R.current || (R.current = !1, B() || h({ type: "speech-ended" }));
143
+ }, [m.phase, B]), c(() => {
144
+ Y.error === "not-allowed" || Y.error === "audio-capture" ? h({
133
145
  type: "fail",
134
146
  error: "mic-denied"
135
- }) : K.error === "language-not-supported" ? m({
147
+ }) : Y.error === "language-not-supported" ? h({
136
148
  type: "fail",
137
149
  error: "no-speech-support"
138
- }) : K.error === "network" ? D("network") : K.error === "unknown" && D("recognition-failed");
139
- }, [K.error]), s(() => {
140
- K.error !== null || !K.isListening || D((e) => e === "network" || e === "recognition-failed" ? null : e);
141
- }, [K.error, K.isListening]), s(() => {
142
- if (K.isListening && D((e) => e === "not-capturing" ? null : e), !r(p) || K.isListening) return;
143
- let e = setTimeout(() => D("not-capturing"), he);
150
+ }) : Y.error === "network" ? A("network") : Y.error === "unknown" && A("recognition-failed");
151
+ }, [Y.error]), c(() => {
152
+ Y.error !== null || !Y.isListening || A((e) => e === "network" || e === "recognition-failed" ? null : e);
153
+ }, [Y.error, Y.isListening]), c(() => {
154
+ if (Y.isListening && A((e) => e === "not-capturing" ? null : e), !i(m) || Y.isListening) return;
155
+ let e = setTimeout(() => A("not-capturing"), he);
144
156
  return () => clearTimeout(e);
145
- }, [p, K.isListening]), s(() => {
146
- if (p.phase !== "listening" || p.muted || !K.isListening || i(p) !== "") return;
147
- let e = setTimeout(() => D("nothing-heard"), ge);
157
+ }, [m, Y.isListening]), c(() => {
158
+ if (m.phase !== "listening" || m.muted || !Y.isListening || a(m) !== "") return;
159
+ let e = setTimeout(() => A("nothing-heard"), ge);
148
160
  return () => clearTimeout(e);
149
- }, [p, K.isListening]), s(() => {
150
- i(p) !== "" && D(null);
151
- }, [p]);
152
- let J = c(null), Y = o(() => {
153
- if (k(!1), j(!1), I(), R.current = !1, !K.isSupported) {
154
- m({
161
+ }, [m, Y.isListening]), c(() => {
162
+ a(m) !== "" && A(null);
163
+ }, [m]);
164
+ let Z = l(null), Q = s(() => {
165
+ if (M(!1), P(!1), z(), V.current = !1, !Y.isSupported) {
166
+ h({
155
167
  type: "fail",
156
168
  error: "no-speech-support"
157
169
  });
158
170
  return;
159
171
  }
160
- if (h.isBlocked) {
161
- m({
172
+ if (g.isBlocked) {
173
+ h({
162
174
  type: "fail",
163
175
  error: "no-voice-support"
164
176
  });
@@ -177,63 +189,63 @@ function u({ onSubmit: u, latestReply: d, language: ve }) {
177
189
  e.volume = 0, e.play().catch(() => {});
178
190
  }
179
191
  } catch {}
180
- g(!0), D(null), w.current = H.current?.id ?? null, J.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, m({ type: "start" });
192
+ _(!0), A(null), E.current = G.current?.id ?? null, O.current = null, Z.current = `vs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`, h({ type: "start" });
181
193
  }, [
182
- K.isSupported,
183
- h.isBlocked,
184
- g,
185
- I
186
- ]), X = o(() => {
187
- k(!1), j(!1), I(), R.current = !1, J.current = null, m({ type: "end" }), y(), g(!1);
194
+ Y.isSupported,
195
+ g.isBlocked,
196
+ _,
197
+ z
198
+ ]), $ = s(() => {
199
+ M(!1), P(!1), z(), V.current = !1, Z.current = null, h({ type: "end" }), b(), _(!1);
188
200
  }, [
189
- y,
190
- g,
191
- I
192
- ]), Z = o((e) => J.current === e, []), Q = o(() => {
193
- m({
201
+ b,
202
+ _,
203
+ z
204
+ ]), ye = s((e) => Z.current === e, []), be = s(() => {
205
+ h({
194
206
  type: "mute",
195
- muted: !M.current.muted
207
+ muted: !F.current.muted
196
208
  });
197
209
  }, []);
198
- s(() => () => {
199
- g(!1), _(!1);
200
- }, [g, _]);
201
- let $ = ce(h.spokenChunks, p.phase, v);
210
+ c(() => () => {
211
+ _(!1), v(!1);
212
+ }, [_, v]);
213
+ let xe = ce(g.spokenChunks, m.phase, y);
202
214
  return de(() => ({
203
- session: p,
204
- notice: E,
205
- spokenChunks: $,
206
- capturing: K.isListening,
207
- active: p.phase !== "idle" && (p.phase !== "ended" || p.error !== null),
208
- interrupting: O,
209
- awaitingEndpoint: A,
210
- available: K.isSupported && !h.isBlocked,
211
- start: Y,
212
- end: X,
213
- isCurrentSession: Z,
214
- toggleMute: Q,
215
- interrupt: G,
216
- announce: B,
217
- holdListening: z,
218
- answerLocally: V
215
+ session: m,
216
+ notice: k,
217
+ spokenChunks: xe,
218
+ capturing: Y.isListening,
219
+ active: m.phase !== "idle" && (m.phase !== "ended" || m.error !== null),
220
+ interrupting: j,
221
+ awaitingEndpoint: N,
222
+ available: Y.isSupported && !g.isBlocked,
223
+ start: Q,
224
+ end: $,
225
+ isCurrentSession: ye,
226
+ toggleMute: be,
227
+ interrupt: J,
228
+ announce: U,
229
+ holdListening: H,
230
+ answerLocally: W
219
231
  }), [
220
- p,
221
- E,
222
- O,
223
- A,
224
- K.isListening,
225
- K.isSupported,
226
- h.isBlocked,
227
- $,
228
- Y,
229
- X,
230
- Z,
232
+ m,
233
+ k,
234
+ j,
235
+ N,
236
+ Y.isListening,
237
+ Y.isSupported,
238
+ g.isBlocked,
239
+ xe,
231
240
  Q,
232
- G,
233
- B,
234
- z,
235
- V
241
+ $,
242
+ ye,
243
+ be,
244
+ J,
245
+ U,
246
+ H,
247
+ W
236
248
  ]);
237
249
  }
238
250
  //#endregion
239
- export { u as useVoiceSession };
251
+ export { d as useVoiceSession };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ★ BOFF-8060 (N1a, R2): what "go back" undoes — the assistant's OWN last
3
+ * navigation, never the browser history (`history.back()` can leave the app).
4
+ *
5
+ * Tab-scoped and memory-only: it survives closing and reopening the panel (a
6
+ * module singleton, not component state) and is never persisted. Pathnames
7
+ * only, so no filter or search query is kept anywhere.
8
+ */
9
+ export interface BackEntry {
10
+ fromPath: string;
11
+ toPath: string;
12
+ /** The assistant reply that announced the move. */
13
+ replyMessageId: string;
14
+ at: number;
15
+ }
16
+ export declare const BACK_STACK_CAPACITY = 10;
17
+ export interface BackStack {
18
+ push: (entry: BackEntry) => void;
19
+ top: () => BackEntry | null;
20
+ pop: () => BackEntry | null;
21
+ clear: () => void;
22
+ size: () => number;
23
+ }
24
+ export declare function createBackStack(capacity?: number): BackStack;
25
+ /** The panel's stack: one per tab. */
26
+ export declare const assistantBackStack: BackStack;
27
+ /**
28
+ * Can "go back" be carried out right now? Only when the person is still on the
29
+ * page the assistant took them to AND that move's reply is the newest assistant
30
+ * message on the surface the command came from. Otherwise "go back" is an
31
+ * ordinary sentence ("want to go back and change step 2?") and reaches the
32
+ * model.
33
+ */
34
+ export declare function isBackRunnable(stack: Pick<BackStack, "top">, currentPath: string, newestAssistantMessageId: string | null): boolean;
35
+ //# sourceMappingURL=backStack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backStack.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/backStack.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,eAAO,MAAM,mBAAmB,KAAK,CAAC;AAEtC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACjC,GAAG,EAAE,MAAM,SAAS,GAAG,IAAI,CAAC;IAC5B,GAAG,EAAE,MAAM,SAAS,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,wBAAgB,eAAe,CAAC,QAAQ,SAAsB,GAAG,SAAS,CAkBzE;AAED,sCAAsC;AACtC,eAAO,MAAM,kBAAkB,EAAE,SAA6B,CAAC;AAE/D;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAC7B,WAAW,EAAE,MAAM,EACnB,wBAAwB,EAAE,MAAM,GAAG,IAAI,GACtC,OAAO,CAIT"}
@@ -0,0 +1,28 @@
1
+ import { pathnameOf as e } from "./navigationOutcome.js";
2
+ //#region src/shared/assistant/uiActions/backStack.ts
3
+ var t = 10;
4
+ function n(t = 10) {
5
+ let n = [];
6
+ return {
7
+ push: (r) => {
8
+ n.push({
9
+ ...r,
10
+ fromPath: e(r.fromPath),
11
+ toPath: e(r.toPath)
12
+ }), n.length > t && (n = n.slice(n.length - t));
13
+ },
14
+ top: () => n[n.length - 1] ?? null,
15
+ pop: () => n.pop() ?? null,
16
+ clear: () => {
17
+ n = [];
18
+ },
19
+ size: () => n.length
20
+ };
21
+ }
22
+ var r = n();
23
+ function i(t, n, r) {
24
+ let i = t.top();
25
+ return !i || r === null ? !1 : i.replyMessageId === r && i.toPath === e(n);
26
+ }
27
+ //#endregion
28
+ export { t as BACK_STACK_CAPACITY, r as assistantBackStack, n as createBackStack, i as isBackRunnable };
@@ -0,0 +1,41 @@
1
+ import { AssistantNavigateAction, AssistantNavigateOutcome, AssistantNavigateVia } from '../conversation';
2
+ import { LocalDestination } from '../localUiCommands';
3
+ import { NavigationOutcome } from './navigationOutcome';
4
+ /** The server keeps a `localAction` of at most 1024 bytes; stay well inside it. */
5
+ export declare const NAVIGATE_RECORD_BUDGET_BYTES = 900;
6
+ export declare function outcomeStatus(outcome: NavigationOutcome): AssistantNavigateOutcome;
7
+ /**
8
+ * ★ BOFF-8060 (N1a): the history record of a navigation.
9
+ *
10
+ * `path` is the registry path; `landedPath` is a PATHNAME ONLY. A record that
11
+ * would not fit the budget loses `landedPath` first (it is the evidence, not
12
+ * the identity), so the record is never rejected for size.
13
+ */
14
+ export declare function buildNavigateAction(input: {
15
+ destinationId: string;
16
+ path: string;
17
+ alreadyHere: boolean;
18
+ via: AssistantNavigateVia;
19
+ outcome?: NavigationOutcome;
20
+ }): AssistantNavigateAction;
21
+ /** The registry label of the page at `path` (its target or its own path), or null. */
22
+ export declare function labelForPath(destinations: readonly LocalDestination[], path: string): string | null;
23
+ /** The registry entry at `path`, or null. */
24
+ export declare function destinationForPath(destinations: readonly LocalDestination[], path: string): LocalDestination | null;
25
+ interface SurfaceMessage {
26
+ id: string;
27
+ role: string;
28
+ metadata?: ({
29
+ voice?: boolean;
30
+ voiceSessionId?: string;
31
+ } & Record<string, unknown>) | undefined;
32
+ }
33
+ /**
34
+ * The newest assistant message on the surface a command came from: the chat
35
+ * thread for a typed one, that voice session's spoken turns for a spoken one.
36
+ * A typed command never acts on a voice-only reply the chat view does not
37
+ * show, and a spoken one never acts on a chat reply.
38
+ */
39
+ export declare function newestAssistantOnSurface(messages: readonly SurfaceMessage[], voiceSessionId: string | undefined): string | null;
40
+ export {};
41
+ //# sourceMappingURL=navigateAction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigateAction.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/navigateAction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAiB,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAEzE,mFAAmF;AACnF,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAQhD,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,wBAAwB,CAElF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE;IACzC,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,OAAO,CAAC;IACrB,GAAG,EAAE,oBAAoB,CAAC;IAC1B,OAAO,CAAC,EAAE,iBAAiB,CAAC;CAC7B,GAAG,uBAAuB,CAgB1B;AAED,sFAAsF;AACtF,wBAAgB,YAAY,CAC1B,YAAY,EAAE,SAAS,gBAAgB,EAAE,EACzC,IAAI,EAAE,MAAM,GACX,MAAM,GAAG,IAAI,CAOf;AAED,6CAA6C;AAC7C,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,SAAS,gBAAgB,EAAE,EACzC,IAAI,EAAE,MAAM,GACX,gBAAgB,GAAG,IAAI,CAQzB;AAED,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,CAAC;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;CACjG;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,SAAS,cAAc,EAAE,EACnC,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,MAAM,GAAG,IAAI,CAYf"}
@@ -0,0 +1,40 @@
1
+ import { isCurrentPath as e } from "../localUiCommands.js";
2
+ import { pathnameOf as t } from "./navigationOutcome.js";
3
+ //#region src/shared/assistant/uiActions/navigateAction.ts
4
+ var n = 900, r = 256, i = 128, a = (e) => new TextEncoder().encode(JSON.stringify(e)).length, o = (e) => e.length <= r ? e : t(e).slice(0, r);
5
+ function s(e) {
6
+ return e.status;
7
+ }
8
+ function c(e) {
9
+ let n = e.outcome && "landedPath" in e.outcome ? t(e.outcome.landedPath) : void 0, c = {
10
+ kind: "navigate",
11
+ destinationId: e.destinationId.length <= i ? e.destinationId : "",
12
+ path: o(e.path),
13
+ alreadyHere: e.alreadyHere,
14
+ via: e.via,
15
+ ...e.outcome ? { outcome: s(e.outcome) } : {}
16
+ }, l = n !== void 0 && n.length <= r ? {
17
+ ...c,
18
+ landedPath: n
19
+ } : c;
20
+ return a(l) <= 900 ? l : c;
21
+ }
22
+ function l(t, n) {
23
+ return t.find((t) => [t.path, ...t.aliases ?? []].some((t) => e(t, n)))?.label ?? null;
24
+ }
25
+ function u(t, n) {
26
+ return t.find((t) => [t.path, ...t.aliases ?? []].some((t) => e(t, n))) ?? null;
27
+ }
28
+ function d(e, t) {
29
+ for (let n = e.length - 1; n >= 0; --n) {
30
+ let r = e[n];
31
+ if (!r || r.role !== "assistant") continue;
32
+ let i = r.metadata?.voice === !0;
33
+ if (t === void 0) {
34
+ if (!i) return r.id;
35
+ } else if (i && r.metadata?.voiceSessionId === t) return r.id;
36
+ }
37
+ return null;
38
+ }
39
+ //#endregion
40
+ export { n as NAVIGATE_RECORD_BUDGET_BYTES, c as buildNavigateAction, u as destinationForPath, l as labelForPath, d as newestAssistantOnSurface, s as outcomeStatus };
@@ -0,0 +1,52 @@
1
+ import { AssistantNavigate } from '../ui/AssistantMarkdownRenderer';
2
+ /**
3
+ * ★ BOFF-8060 (N1a, C7): never claim success before the landing is checked.
4
+ *
5
+ * `navigate(path)` only HANDS the path to the product's router; the router may
6
+ * redirect it, refuse it, or never get there. The panel used to answer "Opened
7
+ * X." in the same tick, so a parent entry that redirected to a shell-less login
8
+ * page was announced as opened while the person watched the panel disappear.
9
+ *
10
+ * Pure: the clock, the timer, the location and the shell-less predicate are
11
+ * injected, so it is tested with a fake clock and no DOM.
12
+ */
13
+ export type NavigationRefusal = "unsaved-changes" | "not-routable" | "no-router";
14
+ export type NavigationOutcome = {
15
+ status: "arrived";
16
+ landedPath: string;
17
+ } | {
18
+ status: "redirected";
19
+ landedPath: string;
20
+ } | {
21
+ status: "new-tab";
22
+ } | {
23
+ status: "refused";
24
+ reason: NavigationRefusal;
25
+ } | {
26
+ status: "unconfirmed";
27
+ };
28
+ export interface NavigationDeps {
29
+ /** The current pathname + search. */
30
+ readPath: () => string;
31
+ /** Milliseconds, monotonic enough to measure a window. */
32
+ now: () => number;
33
+ /** Run `fn` once, `ms` from now. A TIMER, never requestAnimationFrame (it stops in a hidden tab). */
34
+ schedule: (fn: () => void, ms: number) => void;
35
+ /** Is this path rendered WITHOUT the shell that hosts the panel? */
36
+ isShellLess: (path: string) => boolean;
37
+ }
38
+ /** Poll interval, quiet window and ceiling (ms). */
39
+ export declare const NAVIGATION_POLL_MS = 50;
40
+ export declare const NAVIGATION_QUIET_MS = 250;
41
+ export declare const NAVIGATION_CEILING_MS = 1500;
42
+ /** The path without query or hash, and without a trailing slash. */
43
+ export declare function pathnameOf(value: string): string;
44
+ /**
45
+ * Hand `path` to `navigate`, then watch where the location settles.
46
+ *
47
+ * Polls every 50 ms and stops when the location has been unchanged for 250 ms
48
+ * or 1.5 s have passed. A throttled background timer still fires (at about one
49
+ * second), so the worst case ends by about 2.5 s.
50
+ */
51
+ export declare function runNavigation(navigate: AssistantNavigate | null, path: string, deps: NavigationDeps): Promise<NavigationOutcome>;
52
+ //# sourceMappingURL=navigationOutcome.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigationOutcome.d.ts","sourceRoot":"","sources":["../../../../src/shared/assistant/uiActions/navigationOutcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAA2B,MAAM,iCAAiC,CAAC;AAGlG;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG,cAAc,GAAG,WAAW,CAAC;AAEjF,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC5C;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAChD;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,QAAQ,EAAE,MAAM,MAAM,CAAC;IACvB,0DAA0D;IAC1D,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,qGAAqG;IACrG,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,oEAAoE;IACpE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CACxC;AAED,oDAAoD;AACpD,eAAO,MAAM,kBAAkB,KAAK,CAAC;AACrC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAE1C,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIhD;AA2BD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,iBAAiB,GAAG,IAAI,EAClC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,iBAAiB,CAAC,CAwC5B"}