@burdenoff/fe-libs 2026.926.1 → 2026.926.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 (33) hide show
  1. package/dist/shared/assistant/capabilities.d.ts +5 -0
  2. package/dist/shared/assistant/capabilities.d.ts.map +1 -1
  3. package/dist/shared/assistant/capabilities.js +2 -1
  4. package/dist/shared/assistant/index.d.ts +2 -0
  5. package/dist/shared/assistant/index.d.ts.map +1 -1
  6. package/dist/shared/assistant/operations.d.ts +7 -0
  7. package/dist/shared/assistant/operations.d.ts.map +1 -1
  8. package/dist/shared/assistant/operations.js +2 -2
  9. package/dist/shared/assistant/prewarm.d.ts +32 -4
  10. package/dist/shared/assistant/prewarm.d.ts.map +1 -1
  11. package/dist/shared/assistant/prewarm.js +35 -15
  12. package/dist/shared/assistant/product.d.ts +11 -1
  13. package/dist/shared/assistant/product.d.ts.map +1 -1
  14. package/dist/shared/assistant/product.js +8 -6
  15. package/dist/shared/assistant/turnProgress.d.ts +56 -2
  16. package/dist/shared/assistant/turnProgress.d.ts.map +1 -1
  17. package/dist/shared/assistant/turnProgress.js +23 -12
  18. package/dist/shared/assistant/turnTimeline.d.ts +37 -3
  19. package/dist/shared/assistant/turnTimeline.d.ts.map +1 -1
  20. package/dist/shared/assistant/turnTimeline.js +45 -33
  21. package/dist/shared/assistant/turnTimingReport.d.ts +86 -0
  22. package/dist/shared/assistant/turnTimingReport.d.ts.map +1 -0
  23. package/dist/shared/assistant/turnTimingReport.js +123 -0
  24. package/dist/shared/assistant/turnTimingReporter.d.ts +146 -0
  25. package/dist/shared/assistant/turnTimingReporter.d.ts.map +1 -0
  26. package/dist/shared/assistant/turnTimingReporter.js +321 -0
  27. package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
  28. package/dist/shared/assistant/ui/AssistantChatArea.js +510 -482
  29. package/dist/shared/graphql/fetch.d.ts +10 -0
  30. package/dist/shared/graphql/fetch.d.ts.map +1 -1
  31. package/dist/shared/graphql/fetch.js +64 -62
  32. package/dist/shared-assistant.js +133 -131
  33. package/package.json +2 -2
@@ -7,6 +7,8 @@ var e = [
7
7
  "accepted",
8
8
  "cleared",
9
9
  "attemptStarted",
10
+ "prewarmJoined",
11
+ "bootAdopted",
10
12
  "provisionStarted",
11
13
  "createRequested",
12
14
  "sandboxRunning",
@@ -22,6 +24,8 @@ var e = [
22
24
  "firstAudio"
23
25
  ], t = [
24
26
  "attemptStarted",
27
+ "prewarmJoined",
28
+ "bootAdopted",
25
29
  "provisionStarted",
26
30
  "createRequested",
27
31
  "sandboxRunning",
@@ -32,14 +36,19 @@ var e = [
32
36
  "firstOutput",
33
37
  "firstText",
34
38
  "answerDone"
35
- ], n = "burdenoff:assistant-turn-timeline", r = 50, i = /* @__PURE__ */ new Map();
36
- function a() {
39
+ ], n = "burdenoff:assistant-turn-timeline", r = 50, i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set();
40
+ function o(e) {
41
+ return a.add(e), () => {
42
+ a.delete(e);
43
+ };
44
+ }
45
+ function s() {
37
46
  try {
38
47
  if (typeof performance < "u" && typeof performance?.now == "function") return performance.now();
39
48
  } catch {}
40
49
  return Date.now();
41
50
  }
42
- function o() {
51
+ function c() {
43
52
  try {
44
53
  let e = typeof window > "u" ? null : window;
45
54
  return !e || typeof e.matchMedia != "function" ? "unknown" : e.matchMedia("(pointer: coarse)").matches ? "touch" : "pointer";
@@ -47,7 +56,7 @@ function o() {
47
56
  return "unknown";
48
57
  }
49
58
  }
50
- function s(e) {
59
+ function l(e) {
51
60
  return {
52
61
  ...e,
53
62
  at: { ...e.at },
@@ -57,8 +66,11 @@ function s(e) {
57
66
  })) } : {}
58
67
  };
59
68
  }
60
- function c(e) {
61
- let t = s(e), r = () => {
69
+ function u(e) {
70
+ let t = l(e), r = () => {
71
+ for (let e of [...a]) try {
72
+ e(l(t));
73
+ } catch {}
62
74
  try {
63
75
  let e = typeof window > "u" ? null : window;
64
76
  if (!e || typeof e.dispatchEvent != "function" || typeof CustomEvent != "function") return;
@@ -67,7 +79,7 @@ function c(e) {
67
79
  };
68
80
  typeof queueMicrotask == "function" ? queueMicrotask(r) : r();
69
81
  }
70
- function l(e, t, n) {
82
+ function d(e, t, n) {
71
83
  if (i.has(e)) return;
72
84
  let a = {};
73
85
  n?.speechEnded !== void 0 && (a.speechEnded = n.speechEnded), n?.graceStarted !== void 0 && (a.graceStarted = n.graceStarted), n?.graceEnded !== void 0 && (a.graceEnded = n.graceEnded), n?.handedOver !== void 0 && (a.handedOver = n.handedOver);
@@ -81,42 +93,42 @@ function l(e, t, n) {
81
93
  if (e === void 0) break;
82
94
  i.delete(e);
83
95
  }
84
- c(o);
96
+ u(o);
85
97
  }
86
- function u(e, t, n = a()) {
98
+ function f(e, t, n = s()) {
87
99
  let r = i.get(e);
88
- !r || r.at[t] !== void 0 || (r.at[t] = n, c(r));
100
+ !r || r.at[t] !== void 0 || (r.at[t] = n, u(r));
89
101
  }
90
- function d(e, t) {
102
+ function p(e, t) {
91
103
  let n = i.get(e);
92
104
  if (!n) return;
93
105
  let r = !1;
94
- t.runtime !== void 0 && n.runtime === void 0 && (n.runtime = t.runtime, r = !0), t.usedTools !== void 0 && n.usedTools === void 0 && (n.usedTools = t.usedTools, r = !0), t.deadSandboxProbe !== void 0 && n.deadSandboxProbe === void 0 && (n.deadSandboxProbe = t.deadSandboxProbe, r = !0), t.cacheProofFailed !== void 0 && n.cacheProofFailed === void 0 && (n.cacheProofFailed = t.cacheProofFailed, r = !0), t.prewarm !== void 0 && n.prewarm === void 0 && (n.prewarm = t.prewarm, r = !0), t.outcome !== void 0 && n.outcome === void 0 && (n.outcome = t.outcome, r = !0), r && c(n);
106
+ t.runtime !== void 0 && n.runtime === void 0 && (n.runtime = t.runtime, r = !0), t.usedTools !== void 0 && n.usedTools === void 0 && (n.usedTools = t.usedTools, r = !0), t.deadSandboxProbe !== void 0 && n.deadSandboxProbe === void 0 && (n.deadSandboxProbe = t.deadSandboxProbe, r = !0), t.cacheProofFailed !== void 0 && n.cacheProofFailed === void 0 && (n.cacheProofFailed = t.cacheProofFailed, r = !0), t.prewarm !== void 0 && n.prewarm === void 0 && (n.prewarm = t.prewarm, r = !0), t.outcome !== void 0 && n.outcome === void 0 && (n.outcome = t.outcome, r = !0), r && u(n);
95
107
  }
96
- function f(e, n = a()) {
108
+ function m(e, n = s()) {
97
109
  let r = i.get(e);
98
110
  if (!r) return;
99
- let o = {
111
+ let a = {
100
112
  at: {},
101
113
  endedAt: n
102
114
  };
103
115
  for (let e of t) {
104
116
  let t = r.at[e];
105
- t !== void 0 && (o.at[e] = t, delete r.at[e]);
117
+ t !== void 0 && (a.at[e] = t, delete r.at[e]);
106
118
  }
107
- r.runtime !== void 0 && (o.runtime = r.runtime), r.usedTools !== void 0 && (o.usedTools = r.usedTools), r.deadSandboxProbe !== void 0 && (o.deadSandboxProbe = r.deadSandboxProbe), r.cacheProofFailed !== void 0 && (o.cacheProofFailed = r.cacheProofFailed), r.prewarm !== void 0 && (o.prewarm = r.prewarm), delete r.runtime, delete r.usedTools, delete r.deadSandboxProbe, delete r.cacheProofFailed, delete r.prewarm, r.attempts = [...r.attempts ?? [], o], r.retried = !0, c(r);
119
+ r.runtime !== void 0 && (a.runtime = r.runtime), r.usedTools !== void 0 && (a.usedTools = r.usedTools), r.deadSandboxProbe !== void 0 && (a.deadSandboxProbe = r.deadSandboxProbe), r.cacheProofFailed !== void 0 && (a.cacheProofFailed = r.cacheProofFailed), r.prewarm !== void 0 && (a.prewarm = r.prewarm), delete r.runtime, delete r.usedTools, delete r.deadSandboxProbe, delete r.cacheProofFailed, delete r.prewarm, r.attempts = [...r.attempts ?? [], a], r.retried = !0, u(r);
108
120
  }
109
- function p(e) {
121
+ function h(e) {
110
122
  let t = i.get(e);
111
- return t ? s(t) : void 0;
123
+ return t ? l(t) : void 0;
112
124
  }
113
- function m() {
114
- return [...i.values()].map(s);
125
+ function g() {
126
+ return [...i.values()].map(l);
115
127
  }
116
- function h() {
128
+ function _() {
117
129
  i.clear();
118
130
  }
119
- var g = [
131
+ var v = [
120
132
  {
121
133
  name: "endpointing",
122
134
  from: "speechEnded",
@@ -238,38 +250,38 @@ var g = [
238
250
  to: "firstAudio"
239
251
  }
240
252
  ];
241
- function _(e) {
253
+ function y(e) {
242
254
  let t = {};
243
- for (let { name: n, from: r, to: i } of g) {
255
+ for (let { name: n, from: r, to: i } of v) {
244
256
  let a = e.at[r], o = e.at[i];
245
257
  a !== void 0 && o !== void 0 && o >= a && (t[n] = o - a);
246
258
  }
247
259
  return t;
248
260
  }
249
- function v(e, t) {
261
+ function b(e, t) {
250
262
  return e[Math.max(1, Math.ceil(t * e.length)) - 1];
251
263
  }
252
- function y(e) {
264
+ function x(e) {
253
265
  if (!e.length) return;
254
266
  let t = [...e].sort((e, t) => e - t), n = Math.floor(t.length / 2), r = t.length % 2 ? t[n] : (t[n - 1] + t[n]) / 2;
255
267
  return {
256
268
  n: t.length,
257
269
  median: r,
258
- p90: v(t, .9),
270
+ p90: b(t, .9),
259
271
  max: t[t.length - 1]
260
272
  };
261
273
  }
262
- function b(e) {
274
+ function S(e) {
263
275
  return e.outcome === "answered" && !e.retried;
264
276
  }
265
- function x(e, t, n = b) {
277
+ function C(e, t, n = S) {
266
278
  let r = /* @__PURE__ */ new Map();
267
279
  for (let i of e) {
268
280
  if (!n(i)) continue;
269
281
  let e = t(i), a = r.get(e) ?? /* @__PURE__ */ new Map();
270
282
  r.set(e, a);
271
- let o = _(i);
272
- for (let { name: e } of g) {
283
+ let o = y(i);
284
+ for (let { name: e } of v) {
273
285
  let t = o[e];
274
286
  if (t === void 0) continue;
275
287
  let n = a.get(e) ?? [];
@@ -280,7 +292,7 @@ function x(e, t, n = b) {
280
292
  for (let [e, t] of r) {
281
293
  let n = {};
282
294
  for (let [e, r] of t) {
283
- let t = y(r);
295
+ let t = x(r);
284
296
  t && (n[e] = t);
285
297
  }
286
298
  i[e] = n;
@@ -288,4 +300,4 @@ function x(e, t, n = b) {
288
300
  return i;
289
301
  }
290
302
  //#endregion
291
- export { e as TURN_MILESTONES, g as TURN_SEGMENTS, n as TURN_TIMELINE_EVENT, l as beginTurn, d as describeTurn, o as detectTurnDevice, b as isComparableTurn, u as markTurn, m as recentTurnTimelines, h as resetTurnTimelines, f as restartAttempt, y as segmentStats, x as summariseTurnTimelines, a as turnClockMs, _ as turnSegments, p as turnTimeline };
303
+ export { e as TURN_MILESTONES, v as TURN_SEGMENTS, n as TURN_TIMELINE_EVENT, d as beginTurn, p as describeTurn, c as detectTurnDevice, S as isComparableTurn, f as markTurn, g as recentTurnTimelines, _ as resetTurnTimelines, m as restartAttempt, x as segmentStats, o as subscribeTurnTimelines, C as summariseTurnTimelines, s as turnClockMs, y as turnSegments, h as turnTimeline };
@@ -0,0 +1,86 @@
1
+ import { TurnTimeline } from './turnTimeline';
2
+ /**
3
+ * One finished turn as `reportMyAssistantTurnTimings` takes it
4
+ * (`AssistantTurnTimingInput`). Dimensions are plain strings: the service maps
5
+ * anything it does not know to `other` rather than failing the report.
6
+ */
7
+ export interface AssistantTurnTimingReport {
8
+ product: string;
9
+ channel: string;
10
+ mode: string;
11
+ /** Raw, as the timeline recorded it; the service derives cold/warm. */
12
+ runtime?: string;
13
+ prewarm?: string;
14
+ outcome: string;
15
+ retried: boolean;
16
+ runtimeReadyMs?: number;
17
+ modelStartMs?: number;
18
+ firstVisibleOutputMs?: number;
19
+ firstUsefulOutputMs?: number;
20
+ firstAudioMs?: number;
21
+ completeMs: number;
22
+ }
23
+ /**
24
+ * How a RETRIED turn reads a stage (see the header):
25
+ * - `earliest`: the first time any attempt reached it — what the person saw;
26
+ * - `final`: from the attempt that finished the turn;
27
+ * - `omit`: not reported — it describes one attempt's runtime, not the turn's.
28
+ */
29
+ export type TurnTimingRetryRule = "earliest" | "final" | "omit";
30
+ /** Each operator stage, the timeline mark it is read from, and its retry rule. */
31
+ export declare const TURN_TIMING_STAGES: readonly [{
32
+ readonly field: "runtimeReadyMs";
33
+ readonly milestone: "runtimeReady";
34
+ readonly onRetry: "omit";
35
+ }, {
36
+ readonly field: "modelStartMs";
37
+ readonly milestone: "promptSent";
38
+ readonly onRetry: "omit";
39
+ }, {
40
+ readonly field: "firstVisibleOutputMs";
41
+ readonly milestone: "firstOutput";
42
+ readonly onRetry: "earliest";
43
+ }, {
44
+ readonly field: "firstUsefulOutputMs";
45
+ readonly milestone: "firstText";
46
+ readonly onRetry: "final";
47
+ }, {
48
+ readonly field: "firstAudioMs";
49
+ readonly milestone: "firstAudio";
50
+ readonly onRetry: "final";
51
+ }, {
52
+ readonly field: "completeMs";
53
+ readonly milestone: "complete";
54
+ readonly onRetry: "final";
55
+ }];
56
+ /**
57
+ * The outcome of a turn the page was left during (see the header). A report
58
+ * outcome only — a timeline never carries it.
59
+ */
60
+ export declare const ABANDONED_TURN_OUTCOME = "abandoned";
61
+ /**
62
+ * The longest turn the service accepts (its `maxStageMs`, two hours). An
63
+ * "abandoned" turn older than that was stuck, not waited on.
64
+ */
65
+ export declare const MAX_REPORTED_TURN_MS: number;
66
+ /** Every key a report may carry — the privacy allowlist, stated once. */
67
+ export declare const TURN_TIMING_REPORT_FIELDS: readonly ["product", "channel", "mode", "runtime", "prewarm", "outcome", "retried", ...("runtimeReadyMs" | "modelStartMs" | "firstVisibleOutputMs" | "firstUsefulOutputMs" | "firstAudioMs" | "completeMs")[]];
68
+ /**
69
+ * Finished: it has an outcome and it ended. Every exit path marks `complete`
70
+ * in a `finally`, and every one of them sets an outcome.
71
+ */
72
+ export declare function isFinishedTurn(timeline: TurnTimeline): boolean;
73
+ /**
74
+ * The report for a finished turn, or null when it cannot be reported (not
75
+ * finished, no product, or an end that came before its start).
76
+ */
77
+ export declare function buildTurnTimingReport(timeline: TurnTimeline): AssistantTurnTimingReport | null;
78
+ /**
79
+ * The report for a turn that was still running when the page was left at
80
+ * `leftAt` (a `turnClockMs` time): outcome {@link ABANDONED_TURN_OUTCOME},
81
+ * `completeMs` the time to leaving, and the stages it reached by then. Null
82
+ * when it is finished (it reports itself), was never accepted, has no
83
+ * product, or would be older than any turn the service accepts.
84
+ */
85
+ export declare function buildAbandonedTurnReport(timeline: TurnTimeline, leftAt: number): AssistantTurnTimingReport | null;
86
+ //# sourceMappingURL=turnTimingReport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turnTimingReport.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/turnTimingReport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwFG;AAEH,OAAO,KAAK,EAKV,YAAY,EACb,MAAM,gBAAgB,CAAC;AAExB;;;;GAIG;AACH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAUD;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhE,kFAAkF;AAClF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;EAW5B,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,sBAAsB,cAAc,CAAC;AAElD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,QAAqB,CAAC;AAEvD,yEAAyE;AACzE,eAAO,MAAM,yBAAyB,gNAS5B,CAAC;AAEX;;;GAGG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAM9D;AAmJD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,YAAY,GACrB,yBAAyB,GAAG,IAAI,CAMlC;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,GACb,yBAAyB,GAAG,IAAI,CAQlC"}
@@ -0,0 +1,123 @@
1
+ //#region src/shared/assistant/turnTimingReport.ts
2
+ var e = [
3
+ {
4
+ field: "runtimeReadyMs",
5
+ milestone: "runtimeReady",
6
+ onRetry: "omit"
7
+ },
8
+ {
9
+ field: "modelStartMs",
10
+ milestone: "promptSent",
11
+ onRetry: "omit"
12
+ },
13
+ {
14
+ field: "firstVisibleOutputMs",
15
+ milestone: "firstOutput",
16
+ onRetry: "earliest"
17
+ },
18
+ {
19
+ field: "firstUsefulOutputMs",
20
+ milestone: "firstText",
21
+ onRetry: "final"
22
+ },
23
+ {
24
+ field: "firstAudioMs",
25
+ milestone: "firstAudio",
26
+ onRetry: "final"
27
+ },
28
+ {
29
+ field: "completeMs",
30
+ milestone: "complete",
31
+ onRetry: "final"
32
+ }
33
+ ], t = "abandoned", n = 7200 * 1e3, r = [
34
+ "product",
35
+ "channel",
36
+ "mode",
37
+ "runtime",
38
+ "prewarm",
39
+ "outcome",
40
+ "retried",
41
+ ...e.map((e) => e.field)
42
+ ];
43
+ function i(e) {
44
+ return e.outcome !== void 0 && e.at.accepted !== void 0 && e.at.complete !== void 0;
45
+ }
46
+ function a(e, t) {
47
+ let n = Math.ceil(t - e);
48
+ return Number.isSafeInteger(n) ? n : void 0;
49
+ }
50
+ function o(e, t, n = !1) {
51
+ let r = e.at.accepted;
52
+ if (r === void 0) return;
53
+ let i = n ? [...(e.attempts ?? []).map((e) => e.at[t]), e.at[t]] : [e.at[t]], o;
54
+ for (let e of i) e === void 0 || e < r || (o === void 0 || e < o) && (o = e);
55
+ return o === void 0 ? void 0 : a(r, o);
56
+ }
57
+ var s = {
58
+ warm: 0,
59
+ "new-session": 1,
60
+ probed: 2,
61
+ adopted: 3,
62
+ cold: 4
63
+ }, c = [
64
+ "createRequested",
65
+ "sandboxRunning",
66
+ "serviceReady"
67
+ ];
68
+ function l(e) {
69
+ return e.runtime === void 0 ? c.some((t) => e.at[t] !== void 0) ? "cold" : e.at.bootAdopted === void 0 ? void 0 : "adopted" : e.runtime;
70
+ }
71
+ function u(e) {
72
+ return e.prewarm === void 0 ? e.runtime === void 0 && e.at.prewarmJoined !== void 0 ? "joined" : void 0 : e.prewarm;
73
+ }
74
+ var d = {
75
+ hit: 0,
76
+ joined: 1,
77
+ joinedFailed: 2
78
+ };
79
+ function f(e, t) {
80
+ let n;
81
+ for (let r of e) r !== void 0 && (n === void 0 || t[r] > t[n]) && (n = r);
82
+ return n;
83
+ }
84
+ function p(e) {
85
+ let t = [...e.attempts ?? [], e];
86
+ return {
87
+ runtime: f(t.map(l), s),
88
+ prewarm: f(t.map(u), d)
89
+ };
90
+ }
91
+ function m(e, t, n) {
92
+ return e === "firstUsefulOutputMs" ? t === "answered" : e === "firstAudioMs" ? t === "answered" && n === "voice" : !0;
93
+ }
94
+ function h(t, n, r) {
95
+ let i = t.retried === !0, { runtime: a, prewarm: s } = p(t), c = {
96
+ product: t.product,
97
+ channel: t.channel,
98
+ mode: t.mode,
99
+ outcome: n,
100
+ retried: i,
101
+ completeMs: r
102
+ };
103
+ a !== void 0 && (c.runtime = a), s !== void 0 && (c.prewarm = s);
104
+ for (let { field: r, milestone: a, onRetry: s } of e) {
105
+ if (r === "completeMs" || !m(r, n, t.channel) || i && s === "omit") continue;
106
+ let e = o(t, a, i && s === "earliest");
107
+ e !== void 0 && (c[r] = e);
108
+ }
109
+ return c;
110
+ }
111
+ function g(e) {
112
+ if (!i(e) || !e.outcome || !e.product) return null;
113
+ let t = o(e, "complete");
114
+ return t === void 0 ? null : h(e, e.outcome, t);
115
+ }
116
+ function _(e, n) {
117
+ let r = e.at.accepted;
118
+ if (i(e) || r === void 0 || !e.product || !Number.isFinite(n) || n < r) return null;
119
+ let o = a(r, n);
120
+ return o === void 0 || o > 72e5 ? null : h(e, t, o);
121
+ }
122
+ //#endregion
123
+ export { t as ABANDONED_TURN_OUTCOME, n as MAX_REPORTED_TURN_MS, r as TURN_TIMING_REPORT_FIELDS, e as TURN_TIMING_STAGES, _ as buildAbandonedTurnReport, g as buildTurnTimingReport, i as isFinishedTurn };
@@ -0,0 +1,146 @@
1
+ import { GraphQLFetchOptions, GraphQLResponse } from '../graphql';
2
+ import { AssistantTurnTimingReport } from './turnTimingReport';
3
+ import { TurnTimeline } from './turnTimeline';
4
+ import { AssistantSandboxAuthContext } from './types';
5
+ /** What the service did with a batch (`AssistantTurnTimingsReceipt`). */
6
+ export interface AssistantTurnTimingsReceipt {
7
+ enabled: boolean;
8
+ accepted: number;
9
+ rejected: number;
10
+ duplicate: boolean;
11
+ rateLimited: boolean;
12
+ }
13
+ /** One request's worth of finished turns. */
14
+ export interface TurnTimingBatch {
15
+ /** Random, per request — only so the service can ignore a repeat. */
16
+ nonce: string;
17
+ turns: AssistantTurnTimingReport[];
18
+ /** The page may be going away: send with fetch `keepalive`. */
19
+ keepalive: boolean;
20
+ }
21
+ /**
22
+ * What became of a batch, as far as the reporter needs to know:
23
+ * - `receipt`: the service answered;
24
+ * - `unsupported`: the supergraph does not know the mutation, or refused it in
25
+ * a way the next batch would be refused too — stop for the page;
26
+ * - `dropped`: anything else (offline, a 5xx, an expired session). The batch
27
+ * is gone; it is never re-sent.
28
+ */
29
+ export type TurnTimingSendOutcome = {
30
+ kind: "receipt";
31
+ receipt: AssistantTurnTimingsReceipt;
32
+ } | {
33
+ kind: "unsupported";
34
+ } | {
35
+ kind: "dropped";
36
+ };
37
+ export type TurnTimingSender = (batch: TurnTimingBatch) => Promise<TurnTimingSendOutcome>;
38
+ export declare const TURN_TIMING_REPORTING: {
39
+ /** Send once this many turns are queued. */
40
+ readonly flushAt: 5;
41
+ /** …or this long after the first one was. */
42
+ readonly flushAfterMs: 15000;
43
+ /** The queue's bound; the oldest turn is dropped past it. */
44
+ readonly maxQueued: 50;
45
+ /** The service's per-request limit. */
46
+ readonly maxTurnsPerRequest: 20;
47
+ /** How long a finished voice turn waits for its first audio. */
48
+ readonly voiceAudioWaitMs: 30000;
49
+ /** How long sending pauses after the service says `rateLimited`. */
50
+ readonly rateLimitPauseMs: 60000;
51
+ /** Turn ids remembered as already handled (the recorder keeps 50 turns). */
52
+ readonly rememberedTurns: 200;
53
+ /** Unfinished turns held for an `abandoned` report; the oldest is dropped past it. */
54
+ readonly maxRunningTurns: 20;
55
+ };
56
+ /** A fresh random UUID, or null when the page has no source of randomness. */
57
+ export declare function createTurnTimingNonce(): string | null;
58
+ /** Runs `callback` after `ms`; returns a cancel. */
59
+ export type TurnTimingSchedule = (callback: () => void, ms: number) => () => void;
60
+ export interface TurnTimingReporterOptions {
61
+ send: TurnTimingSender;
62
+ /** Timers — injectable for tests. */
63
+ schedule?: TurnTimingSchedule;
64
+ /** Wall clock in ms, for the rate-limit pause. */
65
+ now?: () => number;
66
+ nonce?: () => string | null;
67
+ /** The service answered: the mutation exists and collection is on. */
68
+ onSupported?: () => void;
69
+ /** Reporting stopped for the page (unknown mutation, or switched off). */
70
+ onUnsupported?: () => void;
71
+ /** The page is hidden: a queued turn is sent at once, with `keepalive`. */
72
+ isPageHidden?: () => boolean;
73
+ /**
74
+ * The turn clock (`turnClockMs`), for an abandoned turn's time to leaving —
75
+ * the clock its marks were taken on.
76
+ */
77
+ turnClock?: () => number;
78
+ }
79
+ export interface TurnTimingFlushOptions {
80
+ /**
81
+ * The page may be going away: send EVERYTHING now, not one request at a
82
+ * time, and (unless `keepAwaitingAudio`) release the voice turns still
83
+ * waiting for audio first.
84
+ */
85
+ final?: boolean;
86
+ /** Send with fetch `keepalive` (only meaningful with `final`). */
87
+ keepalive?: boolean;
88
+ /**
89
+ * With `final`: leave the voice turns waiting for their audio where they
90
+ * are — the page is hidden, not gone (see the header).
91
+ */
92
+ keepAwaitingAudio?: boolean;
93
+ /**
94
+ * With `final`: the page is being LEFT (`pagehide`, `freeze`) — report every
95
+ * turn still running as `abandoned`, at the time it was left.
96
+ */
97
+ abandonRunning?: boolean;
98
+ }
99
+ export interface TurnTimingReporter {
100
+ /** Every timeline change goes here. Never throws. */
101
+ observe(timeline: TurnTimeline): void;
102
+ /** Send what is queued. Never throws. */
103
+ flush(options?: TurnTimingFlushOptions): void;
104
+ /** A final flush, then nothing more is observed or sent. */
105
+ dispose(): void;
106
+ /** For tests and a console. */
107
+ stats(): {
108
+ queued: number;
109
+ awaitingAudio: number;
110
+ running: number;
111
+ stopped: boolean;
112
+ };
113
+ }
114
+ /**
115
+ * One reporter. The page-wide one is made by
116
+ * {@link startTurnTimingReporting}; tests build their own.
117
+ */
118
+ export declare function createTurnTimingReporter(options: TurnTimingReporterOptions): TurnTimingReporter;
119
+ /** Where a batch is sent from — read at SEND time, not when the turn ran. */
120
+ export interface TurnTimingSendContext {
121
+ workspaceId: string;
122
+ authContext?: AssistantSandboxAuthContext;
123
+ }
124
+ export type TurnTimingFetcher = (options: GraphQLFetchOptions) => Promise<GraphQLResponse<unknown>>;
125
+ /**
126
+ * Send one batch, ONCE (see the header) — `graphqlFetch` directly, not the
127
+ * retrying `executeSandboxGraphQL`. Never throws.
128
+ */
129
+ export declare function sendAssistantTurnTimings(batch: TurnTimingBatch, context: TurnTimingSendContext, fetcher?: TurnTimingFetcher): Promise<TurnTimingSendOutcome>;
130
+ export interface TurnTimingReportingOptions {
131
+ /** How this panel sends a batch — reading workspace and credentials when it does. */
132
+ send: TurnTimingSender;
133
+ }
134
+ /**
135
+ * Report this page's finished turns. The first call starts the page-wide
136
+ * reporter, which runs for the page load (see the header); each panel lends it
137
+ * a sender for as long as it is mounted.
138
+ *
139
+ * Does nothing once the `turnTimings` capability is `unsupported` for the page.
140
+ *
141
+ * @returns Withdraw this panel's sender.
142
+ */
143
+ export declare function startTurnTimingReporting(options: TurnTimingReportingOptions): () => void;
144
+ /** Tests only: stop the page-wide reporter and forget every sender. */
145
+ export declare function resetTurnTimingReporting(): void;
146
+ //# sourceMappingURL=turnTimingReporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turnTimingReporter.d.ts","sourceRoot":"","sources":["../../../src/shared/assistant/turnTimingReporter.ts"],"names":[],"mappings":"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"}