@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.
- package/dist/shared/assistant/capabilities.d.ts +5 -0
- package/dist/shared/assistant/capabilities.d.ts.map +1 -1
- package/dist/shared/assistant/capabilities.js +2 -1
- package/dist/shared/assistant/index.d.ts +2 -0
- package/dist/shared/assistant/index.d.ts.map +1 -1
- package/dist/shared/assistant/operations.d.ts +7 -0
- package/dist/shared/assistant/operations.d.ts.map +1 -1
- package/dist/shared/assistant/operations.js +2 -2
- package/dist/shared/assistant/prewarm.d.ts +32 -4
- package/dist/shared/assistant/prewarm.d.ts.map +1 -1
- package/dist/shared/assistant/prewarm.js +35 -15
- package/dist/shared/assistant/product.d.ts +11 -1
- package/dist/shared/assistant/product.d.ts.map +1 -1
- package/dist/shared/assistant/product.js +8 -6
- package/dist/shared/assistant/turnProgress.d.ts +56 -2
- package/dist/shared/assistant/turnProgress.d.ts.map +1 -1
- package/dist/shared/assistant/turnProgress.js +23 -12
- package/dist/shared/assistant/turnTimeline.d.ts +37 -3
- package/dist/shared/assistant/turnTimeline.d.ts.map +1 -1
- package/dist/shared/assistant/turnTimeline.js +45 -33
- package/dist/shared/assistant/turnTimingReport.d.ts +86 -0
- package/dist/shared/assistant/turnTimingReport.d.ts.map +1 -0
- package/dist/shared/assistant/turnTimingReport.js +123 -0
- package/dist/shared/assistant/turnTimingReporter.d.ts +146 -0
- package/dist/shared/assistant/turnTimingReporter.d.ts.map +1 -0
- package/dist/shared/assistant/turnTimingReporter.js +321 -0
- package/dist/shared/assistant/ui/AssistantChatArea.d.ts.map +1 -1
- package/dist/shared/assistant/ui/AssistantChatArea.js +510 -482
- package/dist/shared/graphql/fetch.d.ts +10 -0
- package/dist/shared/graphql/fetch.d.ts.map +1 -1
- package/dist/shared/graphql/fetch.js +64 -62
- package/dist/shared-assistant.js +133 -131
- 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
|
|
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
|
|
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
|
|
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
|
|
61
|
-
let t =
|
|
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
|
|
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
|
-
|
|
96
|
+
u(o);
|
|
85
97
|
}
|
|
86
|
-
function
|
|
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,
|
|
100
|
+
!r || r.at[t] !== void 0 || (r.at[t] = n, u(r));
|
|
89
101
|
}
|
|
90
|
-
function
|
|
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 &&
|
|
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
|
|
108
|
+
function m(e, n = s()) {
|
|
97
109
|
let r = i.get(e);
|
|
98
110
|
if (!r) return;
|
|
99
|
-
let
|
|
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 && (
|
|
117
|
+
t !== void 0 && (a.at[e] = t, delete r.at[e]);
|
|
106
118
|
}
|
|
107
|
-
r.runtime !== void 0 && (
|
|
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
|
|
121
|
+
function h(e) {
|
|
110
122
|
let t = i.get(e);
|
|
111
|
-
return t ?
|
|
123
|
+
return t ? l(t) : void 0;
|
|
112
124
|
}
|
|
113
|
-
function
|
|
114
|
-
return [...i.values()].map(
|
|
125
|
+
function g() {
|
|
126
|
+
return [...i.values()].map(l);
|
|
115
127
|
}
|
|
116
|
-
function
|
|
128
|
+
function _() {
|
|
117
129
|
i.clear();
|
|
118
130
|
}
|
|
119
|
-
var
|
|
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
|
|
253
|
+
function y(e) {
|
|
242
254
|
let t = {};
|
|
243
|
-
for (let { name: n, from: r, to: i } of
|
|
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
|
|
261
|
+
function b(e, t) {
|
|
250
262
|
return e[Math.max(1, Math.ceil(t * e.length)) - 1];
|
|
251
263
|
}
|
|
252
|
-
function
|
|
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:
|
|
270
|
+
p90: b(t, .9),
|
|
259
271
|
max: t[t.length - 1]
|
|
260
272
|
};
|
|
261
273
|
}
|
|
262
|
-
function
|
|
274
|
+
function S(e) {
|
|
263
275
|
return e.outcome === "answered" && !e.retried;
|
|
264
276
|
}
|
|
265
|
-
function
|
|
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 =
|
|
272
|
-
for (let { name: e } of
|
|
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 =
|
|
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,
|
|
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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"}
|