@pluno/product-agent-web 0.1.230 → 0.1.232

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 (39) hide show
  1. package/dist/adapters/web/backendHttp.d.ts +16 -2
  2. package/dist/adapters/web/backendTransport.d.ts +3 -0
  3. package/dist/adapters/web/conversationAdapters.d.ts +59 -0
  4. package/dist/adapters/web/conversationCheckpoint.d.ts +16 -0
  5. package/dist/adapters/web/conversationInteractionAdapter.d.ts +11 -0
  6. package/dist/adapters/web/conversationPresentation.d.ts +4 -0
  7. package/dist/adapters/web/directoryAdapters.d.ts +2 -2
  8. package/dist/adapters/web/socketIOTransport.d.ts +4 -0
  9. package/dist/chatPresentation.d.ts +7 -0
  10. package/dist/core/conversation/contracts.d.ts +181 -1
  11. package/dist/core/conversation/delivery.d.ts +22 -0
  12. package/dist/core/conversation/deliveryContracts.d.ts +100 -0
  13. package/dist/core/conversation/display.d.ts +134 -0
  14. package/dist/core/conversation/reducer.d.ts +8 -0
  15. package/dist/core/conversation/selectors.d.ts +59 -0
  16. package/dist/core/conversation/state.d.ts +6 -0
  17. package/dist/core/index.d.ts +6 -0
  18. package/dist/core/model-selection/commands.d.ts +1 -1
  19. package/dist/displayedErrors.d.ts +1 -1
  20. package/dist/entrySurface.d.ts +2 -0
  21. package/dist/index.d.ts +48 -115
  22. package/dist/interactionManager.d.ts +3 -0
  23. package/dist/interruptState.d.ts +1 -1
  24. package/dist/operationTiming.d.ts +21 -0
  25. package/dist/product-agent-runtime.cjs +1 -1
  26. package/dist/product-agent-runtime.js +454 -266
  27. package/dist/product-agent-sdk.js +4187 -4645
  28. package/dist/product-agent-widget.js +8711 -9172
  29. package/dist/protocolTrace.d.ts +3 -0
  30. package/dist/public/operationRoutes.d.ts +2 -0
  31. package/dist/renderDiagnostics.d.ts +31 -0
  32. package/dist/responseDiagnostics.d.ts +1 -0
  33. package/dist/runtime/composition.d.ts +13 -5
  34. package/dist/runtime/modelSelection.d.ts +1 -1
  35. package/dist/runtimeClient.d.ts +20 -6
  36. package/dist/shareCard.d.ts +1 -0
  37. package/dist/uiFlightRecorder.d.ts +4 -1
  38. package/dist/uiInvariants.d.ts +1 -0
  39. package/package.json +1 -1
@@ -8,8 +8,8 @@ function f(s) {
8
8
  updatedAt: null
9
9
  };
10
10
  }
11
- class w {
12
- constructor(e, t, i = (n, a) => a) {
11
+ class P {
12
+ constructor(e, t, i = (n, r) => r) {
13
13
  this.loader = t, this.merge = i, this.state = f(e);
14
14
  }
15
15
  loader;
@@ -93,34 +93,34 @@ function m(s) {
93
93
  nextCursor: s.nextCursor
94
94
  };
95
95
  }
96
- function D(s, e, t) {
96
+ function U(s, e, t) {
97
97
  if (t === "replace" || s === null) return e;
98
98
  const i = { ...s.entitiesById, ...e.entitiesById }, n = [...s.ids];
99
- for (const a of e.ids)
100
- s.entitiesById[a] || n.push(a);
99
+ for (const r of e.ids)
100
+ s.entitiesById[r] || n.push(r);
101
101
  return { entitiesById: i, ids: n, nextCursor: e.nextCursor };
102
102
  }
103
- function R(s) {
103
+ function $(s) {
104
104
  return s ? s.ids.map((e) => s.entitiesById[e]).filter((e) => !!e) : [];
105
105
  }
106
- function F(s) {
106
+ function oe(s) {
107
107
  return s.visible ? s.minimized ? { state: "minimized" } : { state: s.open ? "visible_open" : "visible_closed" } : { state: "hidden" };
108
108
  }
109
- function j(s, e) {
109
+ function ae(s, e) {
110
110
  return e === "limit_exceeded" ? { allowed: !1, reason: "credits_exhausted", actions: ["upgrade", "earn_credits"] } : e === "subscription_required" || e === "subscription_inactive" || e === "payment_issue" || e === "subscription_invalid" || e === "payment_required" ? { allowed: !1, reason: "payment_issue", actions: ["upgrade"] } : s ?? { allowed: !0, reason: "allowed", actions: [] };
111
111
  }
112
- function z(s) {
112
+ function le(s) {
113
113
  if (!s || typeof s != "object") return !1;
114
114
  const e = s.paidCreditFallbackModel;
115
115
  return typeof e == "string" && e.length > 0;
116
116
  }
117
- function H(s) {
117
+ function ce(s) {
118
118
  return s ? s.submissionGate?.allowed === !1 ? { state: "action_required", reason: s.submissionGate.reason } : s.usingPaidCreditFallback === !0 ? { state: "paid_credit_fallback" } : s.creditLimit !== null && s.creditLimit > 0 && s.creditsRemaining !== null && s.creditsRemaining > 0 && s.creditsRemaining / s.creditLimit <= 0.2 ? { state: "low_credits" } : s.creditsUsed !== null ? { state: "usage" } : { state: "hidden" } : { state: "hidden" };
119
119
  }
120
- function G(s) {
120
+ function de(s) {
121
121
  return s.submissionAllowed && s.isAuthenticated && s.hasWorkspace && !s.isWebsiteBlocked && s.isCurrentPageResolved && !s.isSubmitting && !s.hasPendingMessage;
122
122
  }
123
- function V(s) {
123
+ function ue(s) {
124
124
  const e = s.hasDraftMessage || s.hasPreSubmittedAttachment;
125
125
  return s.hasRunningAssistantTurn && !e ? {
126
126
  action: "stop",
@@ -130,22 +130,22 @@ function V(s) {
130
130
  disabled: !e || !s.canSubmitMessage
131
131
  };
132
132
  }
133
- const k = "Pluno is reconnecting. Try again in a moment.";
134
- function C(s) {
135
- return (s instanceof Error ? s.message : s) === k;
133
+ const j = "Pluno is reconnecting. Try again in a moment.";
134
+ function Q(s) {
135
+ return (s instanceof Error ? s.message : s) === j;
136
136
  }
137
- class Z {
137
+ class pe {
138
138
  constructor(e, t, i = 20) {
139
- this.loadPage = t, this.limit = i, this.recentQuery = new w(
139
+ this.loadPage = t, this.limit = i, this.recentQuery = new P(
140
140
  `${e}:recent`,
141
141
  async ({ cursor: n }) => m(
142
- await this.loadPage({ cursor: n, limit: this.limit, pinned: !1 }).then((a) => ({
143
- entities: a.sessions,
144
- nextCursor: a.nextCursor
142
+ await this.loadPage({ cursor: n, limit: this.limit, pinned: !1 }).then((r) => ({
143
+ entities: r.sessions,
144
+ nextCursor: r.nextCursor
145
145
  }))
146
146
  ),
147
- D
148
- ), this.pinnedQuery = new w(
147
+ U
148
+ ), this.pinnedQuery = new P(
149
149
  `${e}:pinned`,
150
150
  async () => m({
151
151
  entities: await this.loadAllPinned(),
@@ -167,18 +167,18 @@ class Z {
167
167
  activityReconciliationScheduled = !1;
168
168
  getState() {
169
169
  const e = this.recentQuery.getState(), t = this.pinnedQuery.getState(), i = [
170
- ...g(t.data),
171
- ...g(e.data)
172
- ], n = new Map(i.map((l) => [l.id, l])), a = Array.from(n.values()).map(
170
+ ...h(t.data),
171
+ ...h(e.data)
172
+ ], n = new Map(i.map((l) => [l.id, l])), r = Array.from(n.values()).map(
173
173
  (l) => this.applyOverrides(l, this.completedRefreshSequence)
174
- ), c = Array.from(this.optimisticEntities.values()).filter((l) => !n.has(l.id)).reverse(), r = e.data || t.data || c.length > 0 ? m({
175
- entities: [...c, ...a],
174
+ ), a = Array.from(this.optimisticEntities.values()).filter((l) => !n.has(l.id)).reverse(), o = e.data || t.data || a.length > 0 ? m({
175
+ entities: [...a, ...r],
176
176
  nextCursor: e.data?.nextCursor ?? null
177
177
  }) : null;
178
178
  return {
179
179
  key: e.key.slice(0, -7),
180
- status: x(e, t),
181
- data: r,
180
+ status: B(e, t),
181
+ data: o,
182
182
  error: e.error ?? t.error,
183
183
  requestId: Math.max(e.requestId, t.requestId),
184
184
  updatedAt: Math.max(e.updatedAt ?? 0, t.updatedAt ?? 0) || null
@@ -243,8 +243,8 @@ class Z {
243
243
  }
244
244
  reconcileDurableEntities() {
245
245
  const e = [
246
- ...g(this.pinnedQuery.getState().data),
247
- ...g(this.recentQuery.getState().data)
246
+ ...h(this.pinnedQuery.getState().data),
247
+ ...h(this.recentQuery.getState().data)
248
248
  ], t = new Set(e.map((i) => i.id));
249
249
  for (const i of this.optimisticEntities.keys())
250
250
  t.has(i) && this.optimisticEntities.delete(i);
@@ -264,8 +264,8 @@ class Z {
264
264
  let i = e;
265
265
  const n = this.activityOverrides.get(e.id);
266
266
  n && (t >= n.confirmAfterRefresh && e.isActive === n.isActive ? this.activityOverrides.delete(e.id) : t >= n.releaseAfterRefresh ? this.activityOverrides.delete(e.id) : i = { ...i, isActive: n.isActive });
267
- const a = this.pinnedOverrides.get(e.id);
268
- return a && (t >= a.confirmAfterRefresh && e.isPinned === !0 === a.pinned ? this.pinnedOverrides.delete(e.id) : i = { ...i, isPinned: a.pinned }), this.titleOverrides.has(e.id) && (i = { ...i, customTitle: this.titleOverrides.get(e.id) ?? null }), i;
267
+ const r = this.pinnedOverrides.get(e.id);
268
+ return r && (t >= r.confirmAfterRefresh && e.isPinned === !0 === r.pinned ? this.pinnedOverrides.delete(e.id) : i = { ...i, isPinned: r.pinned }), this.titleOverrides.has(e.id) && (i = { ...i, customTitle: this.titleOverrides.get(e.id) ?? null }), i;
269
269
  }
270
270
  updateProjection() {
271
271
  this.publish();
@@ -283,19 +283,116 @@ class Z {
283
283
  for (const e of this.listeners) e(this.getState());
284
284
  }
285
285
  }
286
- function g(s) {
286
+ function h(s) {
287
287
  return s ? s.ids.map((e) => s.entitiesById[e]).filter((e) => !!e) : [];
288
288
  }
289
- function x(s, e) {
289
+ function B(s, e) {
290
290
  return s.status === "error" || e.status === "error" ? "error" : s.status === "loading" || e.status === "loading" ? "loading" : s.status === "refreshing" || e.status === "refreshing" ? "refreshing" : s.status === "loading_more" ? "loading_more" : s.status === "ready" || e.status === "ready" ? "ready" : "not_requested";
291
291
  }
292
- class J {
292
+ function M(s) {
293
+ const e = /^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})(?:\.(\d{1,6}))?(?:Z|\+00:00)$/.exec(s);
294
+ if (!e) throw new Error("Display timestamps must retain the backend UTC precision.");
295
+ return `${e[1]}.${(e[2] ?? "").padEnd(6, "0")}`;
296
+ }
297
+ function A(s) {
298
+ if (s === null || typeof s == "string" || typeof s == "boolean") return !0;
299
+ if (typeof s == "number") return Number.isFinite(s);
300
+ if (Array.isArray(s)) return s.every(A);
301
+ if (typeof s != "object") return !1;
302
+ const e = Object.getPrototypeOf(s);
303
+ return e !== Object.prototype && e !== null ? !1 : Object.values(s).every(A);
304
+ }
305
+ function q(s) {
306
+ return s !== null && typeof s == "object" && !Object.isFrozen(s) && (Object.values(s).forEach(q), Object.freeze(s)), s;
307
+ }
308
+ function F(s) {
309
+ if (!A(s)) throw new Error("Conversation inputs must be JSON-safe values.");
310
+ return JSON.parse(JSON.stringify(s));
311
+ }
312
+ function z(s, e) {
313
+ if (!e) return !1;
314
+ const t = s.executionByUserMessage[e];
315
+ if (t) return ["completed", "stopped", "failed"].includes(t.phase);
316
+ const i = Object.values(s.items).sort((r, a) => M(r.created_at).localeCompare(M(a.created_at)) || r.id.localeCompare(a.id));
317
+ let n = !1;
318
+ for (const r of i)
319
+ if (r.type === "user_message" && (n = r.id === e), !!n && (r.type === "stopped" || r.type === "error" || r.type === "final_response" && s.streams[r.id]?.state === "finished" && s.streams[r.id].revision >= r.data.revision))
320
+ return !0;
321
+ return !1;
322
+ }
323
+ class he {
293
324
  constructor(e, t = null) {
294
325
  this.storage = e, t && (this.decisions = new Map(
295
326
  t.filter(I).map((i) => [this.getDecisionKey(i), i])
296
327
  ), this.initialized = !0);
297
328
  }
298
329
  storage;
330
+ conversationReader = null;
331
+ sources = /* @__PURE__ */ new Map();
332
+ invalidateAuth = () => {
333
+ };
334
+ // S6-C installs an input seam on the existing owner. Empty canonical input never falls back to raw tools.
335
+ /** @internal */
336
+ installConversationSources(e, t = () => {
337
+ }) {
338
+ this.sources.clear(), this.conversationReader = e, this.invalidateAuth = t;
339
+ }
340
+ /** @internal */
341
+ receiveConversationSources(e) {
342
+ for (const t of e) {
343
+ if (!Number.isSafeInteger(t.version) || t.version < 0) throw new Error("Invalid interaction source version.");
344
+ const i = JSON.stringify([t.conversation_id, t.id]), n = this.sources.get(i);
345
+ if (n && n.version >= t.version) continue;
346
+ if (n && n.payload.kind !== t.payload.kind) throw new Error("Interaction kind changed.");
347
+ const r = n?.payload.kind === "personal_channel" && n.lifecycle === "completed" ? "completed" : t.lifecycle, a = n?.payload.kind === "sharing" && t.payload.kind === "sharing" ? { ...t.payload, variant: n.payload.variant } : t.payload;
348
+ this.sources.set(i, q(F({ ...t, lifecycle: r, payload: a }))), t.payload.kind === "integration_auth" && this.invalidateAuth(t.payload.request_id);
349
+ }
350
+ }
351
+ /** @internal */
352
+ getIntegrationSource(e) {
353
+ return [...this.sources.values()].find((t) => t.payload.kind === "integration_auth" && t.payload.request_id === e && this.conversationReader?.(t.conversation_id)) ?? null;
354
+ }
355
+ /** @internal */
356
+ getConversationInputs(e) {
357
+ if (!this.conversationReader) return;
358
+ const t = { share: null, integrations: [], channel: null }, i = e ? this.conversationReader(e) : null;
359
+ if (!i) return t;
360
+ const n = [...this.sources.values()].filter((r) => r.conversation_id === e).sort((r, a) => r.version - a.version || r.id.localeCompare(a.id));
361
+ for (const r of n) {
362
+ const a = r.payload;
363
+ if (a.kind === "sharing") {
364
+ if (t.share = null, !a.eligible || r.lifecycle !== "pending" || r.invocation !== "user" || !["main_web_chat", "automation", "extension_sidepanel", "extension_widget"].includes(r.entry_surface ?? "")) continue;
365
+ const o = r.user_message_id ? i.items[r.user_message_id] : null;
366
+ t.share = {
367
+ revision: r.version,
368
+ candidate: {
369
+ id: r.id,
370
+ variant: a.variant,
371
+ userPrompt: o?.type === "user_message" ? o.data.content : "",
372
+ assistantAnswer: ""
373
+ },
374
+ terminal: !a.wait_for_terminal || z(i, r.user_message_id)
375
+ };
376
+ } else a.kind === "integration_auth" ? t.integrations.push({
377
+ revision: r.version,
378
+ request: {
379
+ type: "pipedream_auth_required",
380
+ authRequestId: a.request_id,
381
+ appSlug: a.app_slug,
382
+ appName: a.app_name,
383
+ appLogo: a.app_logo ?? void 0,
384
+ expiresAt: a.expires_at
385
+ },
386
+ lifecycle: r.lifecycle === "pending" && Date.parse(a.expires_at) <= Date.now() ? "expired" : r.lifecycle
387
+ }) : t.channel = { revision: r.version, request: {
388
+ type: "personal_channel_connection_required",
389
+ requestId: a.request_id,
390
+ channel: a.channel,
391
+ managementUrl: a.management_url
392
+ }, lifecycle: r.lifecycle };
393
+ }
394
+ return t;
395
+ }
299
396
  decisions = /* @__PURE__ */ new Map();
300
397
  scheduledEligibility = /* @__PURE__ */ new Map();
301
398
  initialized = !1;
@@ -340,17 +437,17 @@ class J {
340
437
  async applyAction(e, t, i) {
341
438
  if (!e.allowedActions.includes(t))
342
439
  throw new Error(`Interaction ${e.key} does not allow ${t}.`);
343
- if (!O(t))
440
+ if (!L(t))
344
441
  throw new Error(`Interaction action ${t} is not a persistence decision.`);
345
- const n = i.now ?? /* @__PURE__ */ new Date(), a = {
442
+ const n = i.now ?? /* @__PURE__ */ new Date(), r = {
346
443
  promptKey: e.key,
347
444
  category: e.category,
348
445
  action: t,
349
446
  scope: e.scope,
350
447
  decidedAt: n.toISOString(),
351
448
  nextEligibleAt: this.getNextEligibleAt(e, t, n, i.snoozeUntil)
352
- }, c = t === "dont_show_again" ? this.getCategoryKey(e) : this.getExactKey(e), r = new Map(this.decisions);
353
- return r.set(c, a), await this.storage.save([...r.values()]), this.decisions = r, a;
449
+ }, a = t === "dont_show_again" ? this.getCategoryKey(e) : this.getExactKey(e), o = new Map(this.decisions);
450
+ return o.set(a, r), await this.storage.save([...o.values()]), this.decisions = o, r;
354
451
  }
355
452
  isDecisionEligible(e, t) {
356
453
  return e ? e.action === "dismiss" || e.action === "never" || e.action === "dont_show_again" ? !1 : !e.nextEligibleAt || Date.parse(e.nextEligibleAt) <= t : !0;
@@ -376,13 +473,13 @@ class J {
376
473
  return `${b(e.scope)}:category:${e.category}`;
377
474
  }
378
475
  }
379
- function W(s, e) {
476
+ function ge(s, e) {
380
477
  return {
381
- load: async () => L(s, e),
478
+ load: async () => G(s, e),
382
479
  save: async (t) => s.setItem(e, JSON.stringify(t))
383
480
  };
384
481
  }
385
- function L(s, e) {
482
+ function G(s, e) {
386
483
  const t = s.getItem(e);
387
484
  if (!t) return [];
388
485
  const i = JSON.parse(t);
@@ -391,26 +488,26 @@ function L(s, e) {
391
488
  function b(s) {
392
489
  return `${s.level}:${s.key}`;
393
490
  }
394
- function O(s) {
491
+ function L(s) {
395
492
  return s === "dismiss" || s === "later" || s === "snooze" || s === "never" || s === "dont_show_again";
396
493
  }
397
494
  function I(s) {
398
495
  if (!s || typeof s != "object") return !1;
399
496
  const e = s;
400
- return typeof e.promptKey == "string" && typeof e.category == "string" && typeof e.decidedAt == "string" && (e.nextEligibleAt === null || typeof e.nextEligibleAt == "string") && O(e.action) && !!(e.scope && typeof e.scope == "object" && typeof e.scope.level == "string" && typeof e.scope.key == "string");
497
+ return typeof e.promptKey == "string" && typeof e.category == "string" && typeof e.decidedAt == "string" && (e.nextEligibleAt === null || typeof e.nextEligibleAt == "string") && L(e.action) && !!(e.scope && typeof e.scope == "object" && typeof e.scope.level == "string" && typeof e.scope.key == "string");
401
498
  }
402
- const q = {
499
+ const H = {
403
500
  working: "⏳",
404
501
  completed: "✅",
405
502
  failed: "❗",
406
503
  stopped: "⏹️"
407
- }, U = /^(?:⌛|⏳|✅|❗|⏹️) Pluno(?:: )?/;
408
- function Q(s, e) {
409
- if (!e) return y(s);
410
- const t = y(s), i = `${q[e]} Pluno`;
504
+ }, V = /^(?:⌛|⏳|✅|❗|⏹️) Pluno(?:: )?/;
505
+ function Z(s, e) {
506
+ if (!e) return v(s);
507
+ const t = v(s), i = `${H[e]} Pluno`;
411
508
  return t ? `${i}: ${t}` : i;
412
509
  }
413
- class Y {
510
+ class fe {
414
511
  constructor(e) {
415
512
  this.titleDocument = e;
416
513
  }
@@ -432,10 +529,10 @@ class Y {
432
529
  }
433
530
  applyStatus(e) {
434
531
  const t = this.titleDocument.getTitle();
435
- t !== this.lastAppliedTitle && (this.baseTitle = y(t)), this.status = e, this.stopObserving || (this.stopObserving = this.titleDocument.observeTitle(() => this.handleTitleChanged())), this.applyTitle();
532
+ t !== this.lastAppliedTitle && (this.baseTitle = v(t)), this.status = e, this.stopObserving || (this.stopObserving = this.titleDocument.observeTitle(() => this.handleTitleChanged())), this.applyTitle();
436
533
  }
437
534
  applyClear() {
438
- const e = this.titleDocument.getTitle(), t = this.lastAppliedTitle !== null && e === this.lastAppliedTitle, i = this.lastAppliedTitle === null ? y(e) : e;
535
+ const e = this.titleDocument.getTitle(), t = this.lastAppliedTitle !== null && e === this.lastAppliedTitle, i = this.lastAppliedTitle === null ? v(e) : e;
439
536
  this.status = null, this.lastAppliedTitle = null, this.stopObserving?.(), this.stopObserving = null, t ? this.titleDocument.setTitle(this.baseTitle) : i !== e && this.titleDocument.setTitle(i);
440
537
  }
441
538
  handleTitleChanged() {
@@ -444,11 +541,11 @@ class Y {
444
541
  applyTitle() {
445
542
  if (!this.status)
446
543
  return;
447
- const e = Q(this.baseTitle, this.status);
544
+ const e = Z(this.baseTitle, this.status);
448
545
  this.lastAppliedTitle = e, this.titleDocument.getTitle() !== e && this.titleDocument.setTitle(e);
449
546
  }
450
547
  }
451
- function X(s) {
548
+ function me(s) {
452
549
  return {
453
550
  getTitle: () => s.title,
454
551
  setTitle: (e) => {
@@ -464,41 +561,139 @@ function X(s) {
464
561
  }
465
562
  };
466
563
  }
467
- function y(s) {
468
- return s.replace(U, "");
564
+ function v(s) {
565
+ return s.replace(V, "");
566
+ }
567
+ const J = [
568
+ "submit",
569
+ "stop",
570
+ "staging_ipc",
571
+ "send_ipc",
572
+ "stop_ipc",
573
+ "attachment_transfer",
574
+ "tab_lookup",
575
+ "tab_recovery",
576
+ "session_recovery",
577
+ "conversation_scope",
578
+ "local_stage",
579
+ "view_publication",
580
+ "page_access",
581
+ "authentication",
582
+ "community",
583
+ "preferences",
584
+ "page_capture",
585
+ "session_tabs",
586
+ "context_ready",
587
+ "first_frame",
588
+ "checkpoint",
589
+ "command_http",
590
+ "http_authentication",
591
+ "http_request",
592
+ "receipt_http",
593
+ "attachment_upload",
594
+ "runtime_reading",
595
+ "runtime_stopping",
596
+ "runtime_progress",
597
+ "runtime_stopped",
598
+ "message_painted",
599
+ "reading_painted",
600
+ "stopping_painted",
601
+ "progress_painted",
602
+ "stopped_painted"
603
+ ], W = Math.random().toString(36).slice(2);
604
+ let Y = 0;
605
+ const O = () => `timing:${W}:${++Y}`, g = (s) => typeof s == "string" && /^[a-zA-Z0-9:_-]{1,160}$/.test(s);
606
+ function w(s) {
607
+ if (!s || typeof s != "object") return !1;
608
+ const e = s;
609
+ return Object.keys(e).every((t) => ["entrySurface", "operation", "layer", "stage", "status", "spanId", "requestId", "clientMessageId", "sessionId", "occurredAt", "durationMs"].includes(t)) && (e.entrySurface === void 0 || ["extension_sidepanel", "extension_widget", "main_web_chat", "embedded_widget", "embedded_custom_ui", "automation", "mcp", "whatsapp"].includes(e.entrySurface)) && ["send", "stop"].includes(e.operation) && ["renderer", "sdk", "extension", "http"].includes(e.layer) && J.includes(e.stage) && ["started", "completed", "failed", "observed"].includes(e.status) && g(e.spanId) && g(e.requestId) && (e.clientMessageId === null || g(e.clientMessageId)) && (e.sessionId === null || g(e.sessionId)) && typeof e.occurredAt == "string" && e.occurredAt.length <= 40 && Number.isFinite(Date.parse(e.occurredAt)) && Number.isSafeInteger(e.durationMs) && e.durationMs >= 0;
610
+ }
611
+ function R(s, e) {
612
+ if (!s) return {
613
+ mark: (n) => {
614
+ },
615
+ measure: (n, r) => r()
616
+ };
617
+ const t = performance.now(), i = (n, r, a, o) => {
618
+ const l = {
619
+ ...e,
620
+ stage: n,
621
+ status: r,
622
+ spanId: o,
623
+ occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
624
+ durationMs: Math.max(0, Math.round(performance.now() - a))
625
+ };
626
+ s && w(l) && Promise.resolve().then(() => s(l)).catch(() => {
627
+ });
628
+ };
629
+ return {
630
+ mark: (n) => i(n, "observed", t, O()),
631
+ measure(n, r) {
632
+ const a = performance.now(), o = O();
633
+ return i(n, "started", a, o), r().then(
634
+ (l) => (i(n, "completed", a, o), l),
635
+ (l) => {
636
+ throw i(n, "failed", a, o), l;
637
+ }
638
+ );
639
+ }
640
+ };
641
+ }
642
+ const D = ["messageKeys", "canonicalItemKeys", "terminalResponseKeys", "toolCallKeys", "activeResponseKeys"], E = (s) => typeof s == "string" && /^[a-zA-Z0-9:_-]{1,160}$/.test(s), y = (s) => s === null || E(s), X = (s) => typeof s == "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?(?:Z|\+00:00)$/.test(s) && Number.isFinite(Date.parse(s));
643
+ function N(s) {
644
+ if (!s || typeof s != "object") return !1;
645
+ const e = s;
646
+ return Object.keys(s).every((t) => ["sessionId", "itemId", "userMessageId", "createdAt", "runId", "retryable"].includes(t)) && y(e.sessionId) && E(e.itemId) && y(e.userMessageId) && (e.retryable === void 0 || typeof e.retryable == "boolean") && y(e.runId) && (e.createdAt === null || X(e.createdAt));
647
+ }
648
+ function K(s) {
649
+ if (!s || typeof s != "object" || Object.keys(s).some((i) => i !== "before" && i !== "current")) return !1;
650
+ const e = (i) => {
651
+ if (!i || typeof i != "object") return !1;
652
+ const n = i;
653
+ return Object.keys(i).every((r) => [...D, "sessionId", "runtimeItemCount", "welcome", "truncated", "thinkingSequence"].includes(r)) && (n.thinkingSequence === void 0 || Array.isArray(n.thinkingSequence) && n.thinkingSequence.length <= 20 && n.thinkingSequence.every((r) => r === "user" || r === "thinking")) && y(n.sessionId) && Number.isSafeInteger(n.runtimeItemCount) && n.runtimeItemCount >= 0 && typeof n.welcome == "boolean" && typeof n.truncated == "boolean" && D.every((r) => Array.isArray(n[r]) && n[r].length <= 20 && n[r].every(E));
654
+ }, t = s;
655
+ return (t.before === null || e(t.before)) && e(t.current);
656
+ }
657
+ const _ = (s) => s === null || typeof s == "string" && /^[a-zA-Z0-9:_-]{1,160}$/.test(s);
658
+ function ee(s) {
659
+ if (!s || typeof s != "object") return !1;
660
+ const e = s;
661
+ return typeof e.observedAt == "string" && e.observedAt.length <= 40 && Number.isFinite(Date.parse(e.observedAt)) && _(e.sessionId) && _(e.responseItemId) && _(e.respondsToUserMessageId) && typeof e.panelVisible == "boolean" && typeof e.documentVisible == "boolean" && typeof e.loading == "boolean";
469
662
  }
470
- function P(s, e) {
471
- const t = new Set([
663
+ const k = 500;
664
+ function te(s) {
665
+ const e = s.replace(/\n\s*at\s[\s\S]*$/, "").replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?(?:-----END [^-]*PRIVATE KEY-----|$)/g, "[REDACTED]").replace(/\b(?:set-cookie|cookie)\s*[:=]\s*[^\n]+/gi, "cookie=[REDACTED]").replace(/\bdata:[^\s<>"']+/gi, "[DATA]").replace(/\b(?:https?:\/\/|www\.)[^\s<>"']+/gi, "[URL]").replace(/\b(?:Bearer|Basic)\s+[^\s,;"']+/gi, "[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)?/g, "[REDACTED]").replace(/\b(?:sk|pk|ghp|gho|github_pat|xoxb|xoxp)[-_][A-Za-z0-9_-]{8,}/g, "[REDACTED]").replace(/\b((?:access|refresh|id|auth)[_-]?token|api[_-]?key|client[_-]?secret|password|passwd|pwd|secret|token|jwt|authorization|cookie|set-cookie)\b["']?\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;}&]+)/gi, "$1=[REDACTED]").replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, "[EMAIL]").replace(/(?:[A-Z]:[\\/]|\\\\|(?:~|\.\.?)?\/|[\w.-]+[\\/])[^\s<>"']+/gi, "[FILE]").replace(new RegExp("(?<![\\w.])(?:[\\w.-]+\\.[A-Z][A-Z0-9]{0,15}|\\.[A-Z][\\w.-]*)\\b", "gi"), "[FILE]").replace(/\s+/g, " ").trim();
666
+ return e.length > k ? `${e.slice(0, k - 1)}…` : e;
667
+ }
668
+ function se(s, e, t = "stopped", i) {
669
+ const n = new Set(i ?? [
472
670
  s.assistantDraftRespondsToUserMessageId,
473
671
  s.activeResponseUserMessageId,
474
- s.messages.filter((n) => n.role === "user").slice(-1)[0]?.id
475
- ].filter((n) => !!n)), i = s.messages.filter((n) => !(n.dataType === "run_status" && n.loading && t.has(n.respondsToUserMessageId ?? ""))).map((n) => t.has(n.respondsToUserMessageId ?? "") ? { ...n, loading: !1 } : n);
476
- for (const n of t)
477
- i.some((a) => a.respondsToUserMessageId === n && (a.dataType === "run_status" || a.dataType === "run_error" || a.role === "assistant" && a.phase !== "commentary")) || i.push({ id: `local-interrupted:${n}`, role: "system", dataType: "run_status", content: "Run stopped by user.", createdAt: e, respondsToUserMessageId: n });
672
+ s.messages.filter((o) => o.role === "user").slice(-1)[0]?.id
673
+ ].filter((o) => !!o)), r = s.messages.filter((o) => !(o.dataType === "run_status" && o.loading && n.has(o.respondsToUserMessageId ?? ""))).map((o) => n.has(o.respondsToUserMessageId ?? "") ? { ...o, loading: !1 } : o);
674
+ for (const o of n)
675
+ r.some((l) => l.respondsToUserMessageId === o && (l.dataType === "run_status" || l.dataType === "run_error" || l.role === "assistant" && l.phase !== "commentary")) || r.some((l) => l.role === "user" && l.id === o) && r.push({ id: `local-interrupted:${o}`, role: "system", dataType: "run_status", content: t === "stopping" ? "Stopping…" : "Run stopped by user.", createdAt: e, respondsToUserMessageId: o });
676
+ const a = s.segments?.map((o) => ({ ...o, outcomeIds: [
677
+ ...o.outcomeIds,
678
+ ...r.filter((l) => l.id === `local-interrupted:${o.userMessageId}` && !o.outcomeIds.includes(l.id)).map((l) => l.id)
679
+ ] }));
478
680
  return {
479
681
  ...s,
480
- messages: i,
682
+ messages: r,
481
683
  isThinking: !1,
482
684
  isRetrying: !1,
483
685
  pendingMessageStatus: null,
484
686
  turnPhase: null,
485
- taskStatus: "stopped",
687
+ segments: a,
688
+ activity: { phase: t, activeItemId: null },
689
+ isLoadingSession: s.isLoadingSession && r.length === 0,
690
+ taskStatus: t === "stopped" ? "stopped" : null,
486
691
  lastError: null,
487
692
  lastErrorCode: null
488
693
  };
489
694
  }
490
- const S = (s) => s === null || typeof s == "string" && /^[a-zA-Z0-9:_-]{1,160}$/.test(s);
491
- function N(s) {
492
- if (!s || typeof s != "object") return !1;
493
- const e = s;
494
- return typeof e.observedAt == "string" && e.observedAt.length <= 40 && Number.isFinite(Date.parse(e.observedAt)) && S(e.sessionId) && S(e.responseItemId) && S(e.respondsToUserMessageId) && typeof e.panelVisible == "boolean" && typeof e.documentVisible == "boolean" && typeof e.loading == "boolean";
495
- }
496
- const _ = 500;
497
- function $(s) {
498
- const e = s.replace(/\n\s*at\s[\s\S]*$/, "").replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?(?:-----END [^-]*PRIVATE KEY-----|$)/g, "[REDACTED]").replace(/\b(?:set-cookie|cookie)\s*[:=]\s*[^\n]+/gi, "cookie=[REDACTED]").replace(/\bdata:[^\s<>"']+/gi, "[DATA]").replace(/\b(?:https?:\/\/|www\.)[^\s<>"']+/gi, "[URL]").replace(/\b(?:Bearer|Basic)\s+[^\s,;"']+/gi, "[REDACTED]").replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)?/g, "[REDACTED]").replace(/\b(?:sk|pk|ghp|gho|github_pat|xoxb|xoxp)[-_][A-Za-z0-9_-]{8,}/g, "[REDACTED]").replace(/\b((?:access|refresh|id|auth)[_-]?token|api[_-]?key|client[_-]?secret|password|passwd|pwd|secret|token|jwt|authorization|cookie|set-cookie)\b["']?\s*[:=]\s*(?:"[^"]*"|'[^']*'|[^\s,;}&]+)/gi, "$1=[REDACTED]").replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, "[EMAIL]").replace(/(?:[A-Z]:[\\/]|\\\\|(?:~|\.\.?)?\/|[\w.-]+[\\/])[^\s<>"']+/gi, "[FILE]").replace(new RegExp("(?<![\\w.])(?:[\\w.-]+\\.[A-Z][A-Z0-9]{0,15}|\\.[A-Z][\\w.-]*)\\b", "gi"), "[FILE]").replace(/\s+/g, " ").trim();
499
- return e.length > _ ? `${e.slice(0, _ - 1)}…` : e;
500
- }
501
- const B = {
695
+ const ie = {
696
+ "stop-without-rendered-message": "Stop is enabled while no message is rendered or the welcome screen is still visible.",
502
697
  "in-progress-stop-unavailable": "An in-progress response has no visible enabled interrupt control.",
503
698
  "stop-did-not-interrupt": "The stopped response remained in progress after an interrupt click.",
504
699
  "duplicate-message-item": "A canonical message rendered more than once.",
@@ -513,10 +708,10 @@ const B = {
513
708
  "thinking-groups-without-user-message": "Multiple thinking groups appeared without a user message between them.",
514
709
  "thinking-without-progress": "Thinking remained visible without progress for five minutes."
515
710
  };
516
- function K(s) {
517
- return typeof s == "string" && s.startsWith("ui_invariant:") && Object.prototype.hasOwnProperty.call(B, s.slice(13));
711
+ function ne(s) {
712
+ return typeof s == "string" && s.startsWith("ui_invariant:") && Object.prototype.hasOwnProperty.call(ie, s.slice(13));
518
713
  }
519
- function E(s) {
714
+ function C(s) {
520
715
  return {
521
716
  ...s.id === void 0 ? {} : { id: s.id },
522
717
  name: s.name,
@@ -527,7 +722,7 @@ function E(s) {
527
722
  ...s.fileUrl === void 0 ? {} : { fileUrl: s.fileUrl }
528
723
  };
529
724
  }
530
- function ee(s) {
725
+ function ye(s) {
531
726
  if (!s || typeof s != "object" || !("type" in s)) return !1;
532
727
  const e = s;
533
728
  switch (e.type) {
@@ -538,13 +733,15 @@ function ee(s) {
538
733
  case "run.stop":
539
734
  return e.clientMessageIds === void 0 || Array.isArray(e.clientMessageIds) && e.clientMessageIds.length <= 100 && e.clientMessageIds.every((t) => typeof t == "string" && t.length > 0 && t.length <= 160);
540
735
  case "runtime.report_response_visibility":
541
- return N(e.observation);
736
+ return ee(e.observation);
542
737
  case "runtime.warmup":
543
738
  return e.reason === "panel_open" || e.reason === "extension_install" || e.reason === "composer_input";
739
+ case "runtime.report_operation_timing":
740
+ return w(e.timing);
544
741
  case "runtime.report_displayed_error":
545
- return (e.reason === "conversation_error" || e.reason === "attachment_error" || e.reason === "history_error" || e.reason === "action_error") && typeof e.errorFingerprint == "string" && /^fnv1a-[0-9a-f]{8}$/.test(e.errorFingerprint) && (e.displayedMessage === void 0 || typeof e.displayedMessage == "string" && e.displayedMessage.length <= 500);
742
+ return (e.renderedError === void 0 || N(e.renderedError)) && (e.reason === "conversation_error" || e.reason === "attachment_error" || e.reason === "history_error" || e.reason === "action_error") && typeof e.errorFingerprint == "string" && /^fnv1a-[0-9a-f]{8}$/.test(e.errorFingerprint) && (e.displayedMessage === void 0 || typeof e.displayedMessage == "string" && e.displayedMessage.length <= 500);
546
743
  case "runtime.report_invalid_state_transition":
547
- return (e.reason === "submitted_turn_returned_to_welcome_without_new_chat" || e.reason === "new_messages_button_without_user_scroll" || K(e.reason)) && (e.clientMessageId === void 0 || typeof e.clientMessageId == "string");
744
+ return (e.uiInvariant === void 0 || K(e.uiInvariant)) && (e.reason === "submitted_turn_returned_to_welcome_without_new_chat" || e.reason === "new_messages_button_without_user_scroll" || ne(e.reason)) && (e.clientMessageId === void 0 || typeof e.clientMessageId == "string");
548
745
  case "runtime.widget_lifecycle":
549
746
  return (e.action === "opened" || e.action === "closed" || e.action === "minimized") && typeof e.trigger == "string";
550
747
  case "session.load":
@@ -572,9 +769,9 @@ function ee(s) {
572
769
  return !1;
573
770
  }
574
771
  }
575
- class te {
772
+ class ve {
576
773
  constructor(e, t, i) {
577
- this.adapter = t, this.state = A(e), this.model = i;
774
+ this.adapter = t, this.state = S(e), this.model = i;
578
775
  }
579
776
  adapter;
580
777
  listeners = {};
@@ -588,9 +785,12 @@ class te {
588
785
  interactions = [];
589
786
  account = null;
590
787
  stagedProactiveSuggestionClientMessageId = null;
591
- unacknowledgedSubmissions = /* @__PURE__ */ new Map();
788
+ pendingTransfers = /* @__PURE__ */ new Map();
789
+ // Presentation of commands in transit only; the background remains the submission/delivery owner.
790
+ submissionPreviews = /* @__PURE__ */ new Map();
592
791
  submissionGeneration = 0;
593
- stoppedProjection = null;
792
+ pendingStop = null;
793
+ stopError = null;
594
794
  operationQueue = Promise.resolve();
595
795
  destroyed = !1;
596
796
  on(e, t) {
@@ -598,63 +798,35 @@ class te {
598
798
  return i.add(t), this.listeners[e] = i, () => i.delete(t);
599
799
  }
600
800
  getState() {
601
- return A(this.state);
801
+ const e = S(this.state);
802
+ for (const [t, i] of this.submissionPreviews)
803
+ e.messages.some((n) => n.id === t) || (e.messages.push({ ...i.message, attachments: i.message.attachments?.map((n) => ({ ...n })) }), e.segments && (e.segments = [...e.segments, { id: t, userMessageId: t, activityIds: [], outcomeIds: [], collapsed: !1 }]), e.isLoadingSession = !1, i.pending && (e.activeResponseUserMessageId = t, e.pendingMessageStatus = "sending", e.turnPhase = "sending", e.activity = { phase: "submitting", activeItemId: null }), i.error && (e.lastError = i.error, e.lastErrorCode = "message_delivery_failed"));
804
+ return this.stopError && (e.lastError = this.stopError, e.lastErrorCode = "stop_failed"), this.pendingStop ? se(e, "", "stopping", this.pendingStop.userMessageIds) : e;
602
805
  }
603
- updateProjection(e, t, i, n, a) {
806
+ updateProjection(e, t, i, n, r) {
604
807
  if (this.destroyed) return;
605
- const c = this.state;
606
- if (this.state = A(e), c.user?.id === e.user?.id)
607
- for (const r of this.state.messages) {
608
- if (r.role !== "user" || !r.attachments?.length) continue;
609
- const l = r.clientMessageId, d = c.messages.find((u) => u.role === "user" && (u.id === r.id || l && u.clientMessageId === l));
610
- c.sessionId !== e.sessionId && !(c.sessionId === null && l && d?.clientMessageId === l) || (r.attachments = M(d?.attachments, r.attachments));
611
- }
612
- if (this.stoppedProjection) {
613
- const r = this.stoppedProjection, l = new Set(r.messages.filter((o) => o.role === "user").map((o) => o.id)), d = e.sessionId === r.sessionId && e.user?.id === r.user?.id, u = e.messages.some((o) => o.role === "user" && !l.has(o.id) && !r.messages.some((h) => h.clientMessageId && h.clientMessageId === o.clientMessageId));
614
- if (!d || u)
615
- this.stoppedProjection = null;
616
- else {
617
- const o = [
618
- r.activeResponseUserMessageId,
619
- r.assistantDraftRespondsToUserMessageId,
620
- r.messages.filter((v) => v.role === "user").slice(-1)[0]?.id
621
- ].filter(Boolean), h = o.length > 0 && o.every((v) => e.messages.some((p) => p.respondsToUserMessageId === v && !p.loading && (p.dataType === "run_status" || p.dataType === "run_error" || p.role === "assistant" && p.phase !== "commentary")));
622
- this.state = P(h ? this.state : {
623
- ...this.state,
624
- messages: r.messages,
625
- assistantDraft: r.assistantDraft
626
- }, (/* @__PURE__ */ new Date()).toISOString()), this.stoppedProjection = this.getState();
808
+ const a = this.getState();
809
+ (a.user?.id !== e.user?.id || a.selectionKey !== void 0 && a.selectionKey !== e.selectionKey || a.selectionKey === void 0 && a.sessionId !== null && a.sessionId !== e.sessionId) && (this.cancelPendingSubmissions(), this.submissionPreviews.clear());
810
+ for (const o of e.messages)
811
+ o.role === "user" && this.submissionPreviews.delete(o.id);
812
+ if (this.state = S(e), a.user?.id === e.user?.id)
813
+ for (const o of this.state.messages) {
814
+ if (o.role !== "user" || !o.attachments?.length) continue;
815
+ const l = a.messages.find((c) => c.role === "user" && c.id === o.id);
816
+ a.sessionId !== e.sessionId && !(a.sessionId === null && l) || (o.attachments = re(l?.attachments, o.attachments));
627
817
  }
628
- }
629
- for (const [r, l] of this.unacknowledgedSubmissions) {
630
- if (e.user?.id !== l.userId || l.sessionId !== null && e.sessionId !== l.sessionId) {
631
- this.unacknowledgedSubmissions.delete(r);
632
- continue;
633
- }
634
- const d = this.state.messages.find(
635
- (u) => u.clientMessageId === r
636
- );
637
- if (d) {
638
- d.attachments = M(
639
- l.message.attachments,
640
- d.attachments
641
- ), this.unacknowledgedSubmissions.delete(r);
642
- continue;
643
- }
644
- l.sessionId ??= e.sessionId, this.state.messages.push(l.message), this.state.pendingMessageStatus = "sending", this.state.turnPhase ??= "sending", this.state.taskStatus ??= "working";
645
- }
646
818
  if (t !== void 0 && (this.model = t), i && JSON.stringify(i) !== JSON.stringify(this.sessionHistoryState)) {
647
- this.sessionHistoryState = T(i);
648
- for (const r of this.sessionHistoryListeners)
649
- r(this.getSessionHistoryState());
819
+ this.sessionHistoryState = x(i);
820
+ for (const o of this.sessionHistoryListeners)
821
+ o(this.getSessionHistoryState());
650
822
  }
651
823
  if (n && JSON.stringify(n) !== JSON.stringify(this.interactions)) {
652
- this.interactions = n.map((r) => ({ ...r }));
653
- for (const r of this.interactionListeners) r(this.getInteractions());
824
+ this.interactions = n.map((o) => ({ ...o }));
825
+ for (const o of this.interactionListeners) o(this.getInteractions());
654
826
  }
655
- if (a !== void 0 && JSON.stringify(a) !== JSON.stringify(this.account)) {
656
- this.account = a ? { ...a } : null;
657
- for (const r of this.accountListeners) r(this.getAccount());
827
+ if (r !== void 0 && JSON.stringify(r) !== JSON.stringify(this.account)) {
828
+ this.account = r ? { ...r } : null;
829
+ for (const o of this.accountListeners) o(this.getAccount());
658
830
  }
659
831
  this.emit("state", this.getState());
660
832
  }
@@ -663,7 +835,7 @@ class te {
663
835
  }
664
836
  destroy() {
665
837
  if (!this.destroyed) {
666
- this.destroyed = !0, this.unacknowledgedSubmissions.clear(), this.attachmentFiles.clear(), this.sessionHistoryListeners.clear(), this.interactionListeners.clear(), this.accountListeners.clear();
838
+ this.destroyed = !0, this.pendingStop = null, this.pendingTransfers.clear(), this.submissionPreviews.clear(), this.attachmentFiles.clear(), this.sessionHistoryListeners.clear(), this.interactionListeners.clear(), this.accountListeners.clear();
667
839
  for (const e of Object.values(this.listeners)) e?.clear();
668
840
  this.adapter.onDisconnect?.();
669
841
  }
@@ -675,123 +847,119 @@ class te {
675
847
  recordWidgetLifecycle(e, t) {
676
848
  this.dispatch({ type: "runtime.widget_lifecycle", action: e, trigger: t });
677
849
  }
850
+ reportOperationTiming(e) {
851
+ !this.destroyed && w(e) && this.adapter.dispatch({ type: "runtime.report_operation_timing", timing: e }).catch(() => {
852
+ });
853
+ }
678
854
  reportResponseVisibility(e) {
679
855
  this.adapter.dispatch({ type: "runtime.report_response_visibility", observation: e }).catch(() => {
680
856
  });
681
857
  }
682
- reportInvalidStateTransition(e, t) {
683
- this.adapter.dispatch({
858
+ reportInvalidStateTransition(e, t, i) {
859
+ i !== void 0 && !K(i) || this.adapter.dispatch({
684
860
  type: "runtime.report_invalid_state_transition",
685
861
  reason: e,
686
- clientMessageId: t
862
+ clientMessageId: t,
863
+ ...i ? { uiInvariant: i } : {}
687
864
  }).catch(() => {
688
865
  });
689
866
  }
690
- reportDisplayedError(e, t, i) {
691
- this.adapter.dispatch({
867
+ reportDisplayedError(e, t, i, n) {
868
+ n !== void 0 && !N(n) || this.adapter.dispatch({
692
869
  type: "runtime.report_displayed_error",
693
870
  reason: e,
694
871
  errorFingerprint: t,
695
- ...i ? { displayedMessage: $(i) } : {}
872
+ ...n ? { renderedError: n } : {},
873
+ ...i ? { displayedMessage: te(i) } : {}
696
874
  }).catch(() => {
697
875
  });
698
876
  }
699
877
  sendMessage(e, t = {}) {
700
878
  const i = e.trim(), n = t.attachments ?? [];
701
879
  if (!i && n.length === 0) return Promise.resolve(null);
702
- const a = t.clientMessageId ?? (t.proactiveSuggestionQuestion && this.stagedProactiveSuggestionClientMessageId ? this.stagedProactiveSuggestionClientMessageId : crypto.randomUUID()), c = t.submittedAt ?? Date.now(), r = this.state, l = this.submissionGeneration, d = {
703
- id: `local-${a}`,
880
+ this.pendingStop = null, this.stopError = null;
881
+ const r = t.clientMessageId ?? (t.proactiveSuggestionQuestion && this.stagedProactiveSuggestionClientMessageId ? this.stagedProactiveSuggestionClientMessageId : crypto.randomUUID()), a = t.submittedAt ?? Date.now(), o = this.submissionGeneration;
882
+ this.pendingTransfers.set(r, n.flatMap((c) => c.id ? [c.id] : [])), this.submissionPreviews.set(r, { pending: !0, message: {
883
+ id: r,
704
884
  role: "user",
705
885
  content: i,
706
- createdAt: (/* @__PURE__ */ new Date()).toISOString(),
707
- ...n.length > 0 ? { attachments: n } : {},
708
- clientMessageId: a
709
- };
710
- this.unacknowledgedSubmissions.set(a, {
711
- message: { ...d, attachments: d.attachments?.map((o) => ({ ...o })) },
712
- sessionId: r.sessionId,
713
- userId: r.user?.id
714
- }), this.state = {
715
- ...this.state,
716
- messages: [...this.state.messages, d],
717
- pendingMessageStatus: "sending",
718
- turnPhase: this.state.isThinking ? this.state.turnPhase : "sending",
719
- taskStatus: "working",
720
- isRetrying: !1,
721
- lastError: null
722
- };
723
- const u = this.enqueueOperation(() => this.sendMessageNow(
724
- i,
725
- { ...t, clientMessageId: a, submittedAt: c },
726
- r,
727
- l
728
- ));
729
- return this.emit("state", this.getState()), u;
730
- }
731
- async sendMessageNow(e, t, i, n) {
732
- const a = e, c = t.clientMessageId;
733
- let r = t.attachments ?? [], l = !1;
734
- if (n !== this.submissionGeneration) return null;
886
+ createdAt: "",
887
+ attachments: n.map((c) => ({ ...c }))
888
+ } });
889
+ const l = this.sendMessageNow(i, { ...t, clientMessageId: r, submittedAt: a }, o);
890
+ return this.emit("state", this.getState()), l.finally(() => {
891
+ this.pendingTransfers.delete(r);
892
+ });
893
+ }
894
+ async sendMessageNow(e, t, i) {
895
+ const n = e, r = t.clientMessageId, a = R((c) => {
896
+ i === this.submissionGeneration && this.reportOperationTiming(c);
897
+ }, {
898
+ operation: "send",
899
+ layer: "renderer",
900
+ requestId: r,
901
+ clientMessageId: r,
902
+ sessionId: this.state.sessionId
903
+ });
904
+ a.mark("submit");
905
+ let o = t.attachments ?? [], l = !1;
906
+ if (i !== this.submissionGeneration) return null;
735
907
  try {
736
- if (await this.adapter.dispatch({
737
- type: "conversation.stage",
738
- content: a,
739
- clientMessageId: c,
740
- proactiveSuggestionQuestion: t.proactiveSuggestionQuestion,
741
- // Preview URLs belong to the renderer's optimistic snapshot and are not valid runtime-command metadata.
742
- attachments: r.length > 0 ? r.map(E) : void 0,
743
- submittedAt: t.submittedAt
744
- }), n !== this.submissionGeneration) return null;
745
- if (l = !0, r.length > 0) {
908
+ if (!await a.measure("staging_ipc", async () => {
909
+ const d = await this.enqueueOperation(async () => this.destroyed || i !== this.submissionGeneration ? null : { result: this.adapter.dispatch({
910
+ type: "conversation.stage",
911
+ initiatedBy: t.initiatedBy,
912
+ invocation: t.invocation,
913
+ automationOnboarding: t.automationOnboarding,
914
+ content: n,
915
+ clientMessageId: r,
916
+ proactiveSuggestionQuestion: t.proactiveSuggestionQuestion,
917
+ // Preview URLs belong to the renderer's optimistic snapshot and are not valid runtime-command metadata.
918
+ attachments: o.length > 0 ? o.map(C) : void 0,
919
+ submittedAt: t.submittedAt
920
+ }) });
921
+ return d ? (await d.result, d) : null;
922
+ }) || i !== this.submissionGeneration) return null;
923
+ if (l = !0, o.length > 0) {
746
924
  if (!this.adapter.uploadAttachment)
747
925
  throw new Error("The runtime does not support attachments.");
748
- const u = [];
749
- for (const o of r) {
750
- if (o.sandboxPath || o.storageKey) {
751
- u.push(o);
926
+ const d = [];
927
+ for (const u of o) {
928
+ if (u.sandboxPath || u.storageKey) {
929
+ d.push(u);
752
930
  continue;
753
931
  }
754
- const h = o.id ? this.attachmentFiles.get(o.id) : void 0;
755
- if (!h) throw new Error(`Attachment bytes are unavailable for ${o.name}`);
756
- if (u.push(await this.adapter.uploadAttachment(h, o, { clientMessageId: c })), n !== this.submissionGeneration) return null;
932
+ const T = u.id ? this.attachmentFiles.get(u.id) : void 0;
933
+ if (!T) throw new Error(`Attachment bytes are unavailable for ${u.name}`);
934
+ if (d.push(await a.measure("attachment_transfer", () => this.adapter.uploadAttachment(T, u, { clientMessageId: r }))), i !== this.submissionGeneration) return null;
757
935
  }
758
- r = u;
936
+ o = d;
759
937
  }
760
- const d = await this.adapter.dispatch({
938
+ const p = await a.measure("send_ipc", () => this.adapter.dispatch({
761
939
  type: "conversation.send",
762
- content: a,
763
- clientMessageId: c,
940
+ content: n,
941
+ clientMessageId: r,
764
942
  initiatedBy: t.initiatedBy,
765
943
  invocation: t.invocation,
766
944
  proactiveSuggestionQuestion: t.proactiveSuggestionQuestion,
767
945
  ...t.automationOnboarding ? { automationOnboarding: !0 } : {},
768
- attachments: r.length > 0 ? r.map(E) : void 0
769
- });
770
- if (n !== this.submissionGeneration) return null;
771
- for (const u of t.attachments ?? [])
772
- u.id && this.attachmentFiles.delete(u.id);
773
- return c === this.stagedProactiveSuggestionClientMessageId && (this.stagedProactiveSuggestionClientMessageId = null), d?.clientMessageId ?? c;
774
- } catch (d) {
775
- if (n !== this.submissionGeneration) return null;
776
- const u = C(d);
777
- if (u)
778
- for (const o of t.attachments ?? [])
779
- o.id && this.attachmentFiles.delete(o.id);
780
- throw this.unacknowledgedSubmissions.delete(c), this.state = {
781
- ...this.state,
782
- messages: u ? this.state.messages : this.state.messages.filter(
783
- (o) => o.id !== `local-${c}` && o.id !== `optimistic-user-message:${c}`
784
- ),
785
- pendingMessageStatus: i.pendingMessageStatus,
786
- turnPhase: i.turnPhase,
787
- isThinking: i.isThinking,
788
- taskStatus: u ? "failed" : i.taskStatus,
789
- ...u ? { lastError: d instanceof Error ? d.message : String(d), lastErrorCode: "auth_reconnecting" } : {}
790
- }, this.emit("state", this.getState()), l && await this.adapter.dispatch({
946
+ attachments: o.length > 0 ? o.map(C) : void 0
947
+ }));
948
+ if (i !== this.submissionGeneration) return null;
949
+ for (const d of t.attachments ?? [])
950
+ d.id && this.attachmentFiles.delete(d.id);
951
+ return r === this.stagedProactiveSuggestionClientMessageId && (this.stagedProactiveSuggestionClientMessageId = null), p?.clientMessageId ?? r;
952
+ } catch (c) {
953
+ if (i !== this.submissionGeneration) return null;
954
+ if (Q(c))
955
+ for (const d of t.attachments ?? [])
956
+ d.id && this.attachmentFiles.delete(d.id);
957
+ const p = this.submissionPreviews.get(r);
958
+ throw p && (p.pending = !1, p.error = c instanceof Error ? c.message : String(c), this.emit("state", this.getState())), l && await this.adapter.dispatch({
791
959
  type: "conversation.fail_staged",
792
- clientMessageId: c,
793
- message: d instanceof Error ? d.message : String(d)
794
- }), d;
960
+ clientMessageId: r,
961
+ message: c instanceof Error ? c.message : String(c)
962
+ }), c;
795
963
  }
796
964
  }
797
965
  getModel() {
@@ -802,7 +970,7 @@ class te {
802
970
  });
803
971
  }
804
972
  retryLastMessage() {
805
- return this.stoppedProjection = null, this.dispatch({ type: "run.retry" }), !0;
973
+ return this.dispatch({ type: "run.retry" }), !0;
806
974
  }
807
975
  createLocalAttachment(e) {
808
976
  const t = crypto.randomUUID();
@@ -814,24 +982,44 @@ class te {
814
982
  };
815
983
  }
816
984
  stop() {
817
- const e = this.cancelPendingSubmissions();
818
- this.state = P(this.state, (/* @__PURE__ */ new Date()).toISOString()), this.stoppedProjection = this.getState(), this.emit("state", this.getState());
819
- const t = this.adapter.dispatch({ type: "run.stop", ...e.length ? { clientMessageIds: e } : {} });
820
- return this.operationQueue = t.then(() => {
985
+ if (this.pendingStop) return this.pendingStop.promise;
986
+ const e = this.getState(), t = this.cancelPendingSubmissions(), i = [...new Set([
987
+ ...t,
988
+ e.activeResponseUserMessageId,
989
+ e.messages.filter((o) => o.role === "user").slice(-1)[0]?.id
990
+ ].filter((o) => !!o))], n = R((o) => this.reportOperationTiming(o), {
991
+ operation: "stop",
992
+ layer: "renderer",
993
+ requestId: crypto.randomUUID(),
994
+ clientMessageId: i[0] ?? null,
995
+ sessionId: e.sessionId
996
+ });
997
+ n.mark("stop");
998
+ const r = { userMessageIds: i, promise: Promise.resolve() };
999
+ this.pendingStop = r, r.promise = n.measure("stop_ipc", () => this.adapter.dispatch({ type: "run.stop", ...t.length ? { clientMessageIds: t } : {} })).then(() => {
1000
+ }, (o) => {
1001
+ this.pendingStop === r && (this.stopError = o instanceof Error ? o.message : String(o));
1002
+ }).finally(() => {
1003
+ this.pendingStop === r && (this.pendingStop = null, this.emit("state", this.getState()));
1004
+ }), this.emit("state", this.getState());
1005
+ const a = r.promise;
1006
+ return this.operationQueue = a.then(() => {
821
1007
  }, () => {
822
- }), t.then(() => {
1008
+ }), a.then(() => {
823
1009
  });
824
1010
  }
825
1011
  cancelPendingSubmissions() {
826
- const e = [...this.unacknowledgedSubmissions.keys()];
1012
+ this.pendingStop = null, this.stopError = null;
1013
+ const e = [...this.pendingTransfers.keys()];
827
1014
  this.submissionGeneration++;
828
- for (const t of this.unacknowledgedSubmissions.values())
829
- for (const i of t.message.attachments ?? [])
830
- i.id && this.attachmentFiles.delete(i.id);
831
- return this.unacknowledgedSubmissions.clear(), this.operationQueue = Promise.resolve(), e;
1015
+ for (const t of this.pendingTransfers.values())
1016
+ for (const i of t) this.attachmentFiles.delete(i);
1017
+ this.pendingTransfers.clear();
1018
+ for (const t of this.submissionPreviews.values()) t.pending = !1;
1019
+ return this.operationQueue = Promise.resolve(), e;
832
1020
  }
833
1021
  startNewSession(e = {}) {
834
- return this.cancelPendingSubmissions(), this.stoppedProjection = null, e.notifyTransport === !1 ? Promise.resolve() : this.dispatch({ type: "session.new" }).then(() => {
1022
+ return this.cancelPendingSubmissions(), this.submissionPreviews.clear(), this.emit("state", this.getState()), e.notifyTransport === !1 ? Promise.resolve() : this.dispatch({ type: "session.new" }).then(() => {
835
1023
  });
836
1024
  }
837
1025
  async listSessions(e = {}) {
@@ -844,7 +1032,7 @@ class te {
844
1032
  return t.sessionHistoryPage;
845
1033
  }
846
1034
  getSessionHistoryState() {
847
- return T(this.sessionHistoryState);
1035
+ return x(this.sessionHistoryState);
848
1036
  }
849
1037
  subscribeSessionHistory(e) {
850
1038
  return this.sessionHistoryListeners.add(e), e(this.getSessionHistoryState()), () => this.sessionHistoryListeners.delete(e);
@@ -892,7 +1080,7 @@ class te {
892
1080
  return Promise.resolve();
893
1081
  }
894
1082
  loadSession(e) {
895
- return this.unacknowledgedSubmissions.clear(), this.dispatch({ type: "session.load", sessionId: e }).then(() => {
1083
+ return this.cancelPendingSubmissions(), this.submissionPreviews.clear(), this.emit("state", this.getState()), this.dispatch({ type: "session.load", sessionId: e }).then(() => {
896
1084
  });
897
1085
  }
898
1086
  stageProactiveSuggestionQuestion(e) {
@@ -907,7 +1095,7 @@ class te {
907
1095
  });
908
1096
  }
909
1097
  dispatch(e) {
910
- return this.enqueueOperation(() => this.adapter.dispatch(e));
1098
+ return e.type === "session.list" ? this.adapter.dispatch(e) : this.enqueueOperation(() => this.adapter.dispatch(e));
911
1099
  }
912
1100
  enqueueOperation(e) {
913
1101
  const t = this.operationQueue.then(e);
@@ -923,7 +1111,7 @@ class te {
923
1111
  for (const n of i ?? []) n(t);
924
1112
  }
925
1113
  }
926
- function M(s, e) {
1114
+ function re(s, e) {
927
1115
  if (!e || !s) return e;
928
1116
  const t = /* @__PURE__ */ new Map();
929
1117
  for (const i of s) {
@@ -935,7 +1123,7 @@ function M(s, e) {
935
1123
  return n ? { ...i, previewUrl: n } : i;
936
1124
  });
937
1125
  }
938
- function A(s) {
1126
+ function S(s) {
939
1127
  return {
940
1128
  ...s,
941
1129
  starterPrompts: [...s.starterPrompts],
@@ -943,10 +1131,10 @@ function A(s) {
943
1131
  messages: s.messages.map((e) => {
944
1132
  const t = {
945
1133
  ...e,
946
- attachments: e.attachments?.map((c) => ({ ...c }))
947
- }, i = e.assistantDraftItemId, n = e.clientMessageId, a = e.proactiveSuggestionClientMessageId;
948
- return a && Object.defineProperty(t, "proactiveSuggestionClientMessageId", {
949
- value: a,
1134
+ attachments: e.attachments?.map((a) => ({ ...a }))
1135
+ }, i = e.assistantDraftItemId, n = e.clientMessageId, r = e.proactiveSuggestionClientMessageId;
1136
+ return r && Object.defineProperty(t, "proactiveSuggestionClientMessageId", {
1137
+ value: r,
950
1138
  enumerable: !1
951
1139
  }), i && Object.defineProperty(t, "assistantDraftItemId", {
952
1140
  value: i,
@@ -959,36 +1147,36 @@ function A(s) {
959
1147
  activeScheduledFollowUps: s.activeScheduledFollowUps?.map((e) => ({ ...e })) ?? null
960
1148
  };
961
1149
  }
962
- function T(s) {
1150
+ function x(s) {
963
1151
  return {
964
1152
  ...s,
965
1153
  data: s.data ? m({
966
- entities: R(s.data).map((e) => ({ ...e })),
1154
+ entities: $(s.data).map((e) => ({ ...e })),
967
1155
  nextCursor: s.data.nextCursor
968
1156
  }) : null
969
1157
  };
970
1158
  }
971
1159
  export {
972
- k as PRODUCT_AGENT_AUTH_RECONNECTING_ERROR_MESSAGE,
973
- J as ProductAgentInteractionManager,
974
- w as ProductAgentQueryController,
975
- te as ProductAgentRemoteRuntimeClient,
976
- Z as ProductAgentSessionHistoryManager,
977
- Y as ProductAgentTaskPageTitleController,
978
- G as canSubmitPersonalProductAgentMessage,
979
- W as createLocalStorageInteractionDecisionStorage,
1160
+ j as PRODUCT_AGENT_AUTH_RECONNECTING_ERROR_MESSAGE,
1161
+ he as ProductAgentInteractionManager,
1162
+ P as ProductAgentQueryController,
1163
+ ve as ProductAgentRemoteRuntimeClient,
1164
+ pe as ProductAgentSessionHistoryManager,
1165
+ fe as ProductAgentTaskPageTitleController,
1166
+ de as canSubmitPersonalProductAgentMessage,
1167
+ ge as createLocalStorageInteractionDecisionStorage,
980
1168
  f as createProductAgentQueryState,
981
- X as createProductAgentTaskPageTitleDocument,
982
- Q as formatProductAgentTaskPageTitle,
983
- z as hasProductAgentPaidCreditFallback,
984
- C as isProductAgentAuthReconnectError,
985
- ee as isProductAgentRuntimeCommand,
986
- D as mergeProductAgentEntityPages,
1169
+ me as createProductAgentTaskPageTitleDocument,
1170
+ Z as formatProductAgentTaskPageTitle,
1171
+ le as hasProductAgentPaidCreditFallback,
1172
+ Q as isProductAgentAuthReconnectError,
1173
+ ye as isProductAgentRuntimeCommand,
1174
+ U as mergeProductAgentEntityPages,
987
1175
  m as normalizeProductAgentEntityPage,
988
- L as readLocalStorageInteractionDecisions,
989
- j as reconcileProductAgentSubmissionGate,
990
- H as resolveProductAgentBillingPresentation,
991
- V as resolveProductAgentComposerAction,
992
- F as resolveProductAgentWidgetPresentation,
993
- R as selectProductAgentQueryEntities
1176
+ G as readLocalStorageInteractionDecisions,
1177
+ ae as reconcileProductAgentSubmissionGate,
1178
+ ce as resolveProductAgentBillingPresentation,
1179
+ ue as resolveProductAgentComposerAction,
1180
+ oe as resolveProductAgentWidgetPresentation,
1181
+ $ as selectProductAgentQueryEntities
994
1182
  };