@pluno/product-agent-web 0.1.219 → 0.1.221

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/README.md +8 -0
  2. package/dist/activeUsersCounter.d.ts +0 -7
  3. package/dist/adapters/web/activeUsers.d.ts +4 -0
  4. package/dist/adapters/web/backendHttp.d.ts +12 -0
  5. package/dist/adapters/web/backendTransport.d.ts +54 -0
  6. package/dist/adapters/web/directoryAdapters.d.ts +85 -0
  7. package/dist/adapters/web/directoryScope.d.ts +42 -0
  8. package/dist/adapters/web/modelScope.d.ts +3 -0
  9. package/dist/adapters/web/socketIOTransport.d.ts +72 -0
  10. package/dist/chatPresentation.d.ts +2 -0
  11. package/dist/core/active-users/reducer.d.ts +47 -0
  12. package/dist/core/index.d.ts +5 -0
  13. package/dist/core/model-selection/commands.d.ts +22 -0
  14. package/dist/core/model-selection/contracts.d.ts +3 -1
  15. package/dist/core/model-selection/events.d.ts +15 -0
  16. package/dist/core/model-selection/reducer.d.ts +4 -0
  17. package/dist/core/model-selection/selectors.d.ts +10 -0
  18. package/dist/core/model-selection/state.d.ts +22 -0
  19. package/dist/core/protocol/modelRouting.d.ts +2 -0
  20. package/dist/core/session-directory/contracts.d.ts +202 -0
  21. package/dist/core/session-directory/membership.d.ts +4 -0
  22. package/dist/core/session-directory/reducer.d.ts +4 -0
  23. package/dist/core/session-directory/selectors.d.ts +2 -0
  24. package/dist/core/session-directory/state.d.ts +6 -0
  25. package/dist/index.d.ts +28 -16
  26. package/dist/interruptState.d.ts +2 -0
  27. package/dist/product-agent-runtime.cjs +1 -1
  28. package/dist/product-agent-runtime.js +384 -315
  29. package/dist/product-agent-sdk.js +7611 -3447
  30. package/dist/product-agent-widget.js +8805 -4751
  31. package/dist/public/operationRoutes.d.ts +1 -0
  32. package/dist/runtime/composition.d.ts +27 -7
  33. package/dist/runtime/modelSelection.d.ts +14 -0
  34. package/dist/runtimeClient.d.ts +10 -0
  35. package/dist/sessionRecoveryPolling.d.ts +3 -0
  36. package/dist/timelineReconciliation.d.ts +1 -0
  37. package/dist/uiInvariants.d.ts +6 -0
  38. package/dist/widget.d.ts +2 -0
  39. package/package.json +4 -1
@@ -1,6 +1,6 @@
1
- function h(s) {
1
+ function f(i) {
2
2
  return {
3
- key: s,
3
+ key: i,
4
4
  status: "not_requested",
5
5
  data: null,
6
6
  error: null,
@@ -8,9 +8,9 @@ function h(s) {
8
8
  updatedAt: null
9
9
  };
10
10
  }
11
- class A {
12
- constructor(e, t, i = (n, r) => r) {
13
- this.loader = t, this.merge = i, this.state = h(e);
11
+ class w {
12
+ constructor(e, t, s = (n, a) => a) {
13
+ this.loader = t, this.merge = s, this.state = f(e);
14
14
  }
15
15
  loader;
16
16
  merge;
@@ -25,10 +25,10 @@ class A {
25
25
  return this.listeners.add(e), e(this.state), () => this.listeners.delete(e);
26
26
  }
27
27
  setKey(e) {
28
- e !== this.state.key && (this.state = h(e), this.trailingLoad = null, this.publish());
28
+ e !== this.state.key && (this.state = f(e), this.trailingLoad = null, this.publish());
29
29
  }
30
30
  reset() {
31
- this.state = h(this.state.key), this.trailingLoad = null, this.publish();
31
+ this.state = f(this.state.key), this.trailingLoad = null, this.publish();
32
32
  }
33
33
  invalidate() {
34
34
  this.state = {
@@ -52,16 +52,16 @@ class A {
52
52
  for (; this.trailingLoad; ) {
53
53
  const e = this.trailingLoad;
54
54
  this.trailingLoad = null;
55
- const t = this.state.key, i = this.state.requestId + 1;
55
+ const t = this.state.key, s = this.state.requestId + 1;
56
56
  this.state = {
57
57
  ...this.state,
58
58
  status: e.mode === "append" ? "loading_more" : this.state.data === null ? "loading" : "refreshing",
59
59
  error: null,
60
- requestId: i
60
+ requestId: s
61
61
  }, this.publish();
62
62
  try {
63
63
  const n = await this.loader({ key: t, cursor: e.cursor });
64
- if (t !== this.state.key || i !== this.state.requestId) continue;
64
+ if (t !== this.state.key || s !== this.state.requestId) continue;
65
65
  this.state = {
66
66
  ...this.state,
67
67
  status: "ready",
@@ -70,7 +70,7 @@ class A {
70
70
  updatedAt: Date.now()
71
71
  }, this.publish();
72
72
  } catch (n) {
73
- if (t !== this.state.key || i !== this.state.requestId) continue;
73
+ if (t !== this.state.key || s !== this.state.requestId) continue;
74
74
  this.state = {
75
75
  ...this.state,
76
76
  status: "error",
@@ -83,64 +83,64 @@ class A {
83
83
  for (const e of this.listeners) e(this.state);
84
84
  }
85
85
  }
86
- function p(s) {
86
+ function m(i) {
87
87
  const e = {}, t = [];
88
- for (const i of s.entities)
89
- e[i.id] || t.push(i.id), e[i.id] = i;
88
+ for (const s of i.entities)
89
+ e[s.id] || t.push(s.id), e[s.id] = s;
90
90
  return {
91
91
  entitiesById: e,
92
92
  ids: t,
93
- nextCursor: s.nextCursor
93
+ nextCursor: i.nextCursor
94
94
  };
95
95
  }
96
- function P(s, e, t) {
97
- if (t === "replace" || s === null) return e;
98
- const i = { ...s.entitiesById, ...e.entitiesById }, n = [...s.ids];
99
- for (const r of e.ids)
100
- s.entitiesById[r] || n.push(r);
101
- return { entitiesById: i, ids: n, nextCursor: e.nextCursor };
96
+ function O(i, e, t) {
97
+ if (t === "replace" || i === null) return e;
98
+ const s = { ...i.entitiesById, ...e.entitiesById }, n = [...i.ids];
99
+ for (const a of e.ids)
100
+ i.entitiesById[a] || n.push(a);
101
+ return { entitiesById: s, ids: n, nextCursor: e.nextCursor };
102
102
  }
103
- function _(s) {
104
- return s ? s.ids.map((e) => s.entitiesById[e]).filter((e) => !!e) : [];
103
+ function k(i) {
104
+ return i ? i.ids.map((e) => i.entitiesById[e]).filter((e) => !!e) : [];
105
105
  }
106
- function Q(s) {
107
- return s.visible ? s.minimized ? { state: "minimized" } : { state: s.open ? "visible_open" : "visible_closed" } : { state: "hidden" };
106
+ function N(i) {
107
+ return i.visible ? i.minimized ? { state: "minimized" } : { state: i.open ? "visible_open" : "visible_closed" } : { state: "hidden" };
108
108
  }
109
- function $(s, e) {
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: [] };
109
+ function B(i, e) {
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"] } : i ?? { allowed: !0, reason: "allowed", actions: [] };
111
111
  }
112
- function K(s) {
113
- if (!s || typeof s != "object") return !1;
114
- const e = s.paidCreditFallbackModel;
112
+ function j(i) {
113
+ if (!i || typeof i != "object") return !1;
114
+ const e = i.paidCreditFallbackModel;
115
115
  return typeof e == "string" && e.length > 0;
116
116
  }
117
- function z(s) {
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" };
117
+ function F(i) {
118
+ return i ? i.submissionGate?.allowed === !1 ? { state: "action_required", reason: i.submissionGate.reason } : i.usingPaidCreditFallback === !0 ? { state: "paid_credit_fallback" } : i.creditLimit !== null && i.creditLimit > 0 && i.creditsRemaining !== null && i.creditsRemaining > 0 && i.creditsRemaining / i.creditLimit <= 0.2 ? { state: "low_credits" } : i.creditsUsed !== null ? { state: "usage" } : { state: "hidden" } : { state: "hidden" };
119
119
  }
120
- function B(s) {
121
- const e = s.hasDraftMessage || s.hasPreSubmittedAttachment;
122
- return s.hasRunningAssistantTurn && !e ? {
120
+ function z(i) {
121
+ const e = i.hasDraftMessage || i.hasPreSubmittedAttachment;
122
+ return i.hasRunningAssistantTurn && !i.hasDraftMessage ? {
123
123
  action: "stop",
124
- disabled: !s.canStopRunningTurn
124
+ disabled: !i.canStopRunningTurn
125
125
  } : {
126
126
  action: "send",
127
- disabled: !e || !s.canSubmitMessage
127
+ disabled: !e || !i.canSubmitMessage
128
128
  };
129
129
  }
130
- class F {
131
- constructor(e, t, i = 20) {
132
- this.loadPage = t, this.limit = i, this.recentQuery = new A(
130
+ class H {
131
+ constructor(e, t, s = 20) {
132
+ this.loadPage = t, this.limit = s, this.recentQuery = new w(
133
133
  `${e}:recent`,
134
- async ({ cursor: n }) => p(
135
- await this.loadPage({ cursor: n, limit: this.limit, pinned: !1 }).then((r) => ({
136
- entities: r.sessions,
137
- nextCursor: r.nextCursor
134
+ async ({ cursor: n }) => m(
135
+ await this.loadPage({ cursor: n, limit: this.limit, pinned: !1 }).then((a) => ({
136
+ entities: a.sessions,
137
+ nextCursor: a.nextCursor
138
138
  }))
139
139
  ),
140
- P
141
- ), this.pinnedQuery = new A(
140
+ O
141
+ ), this.pinnedQuery = new w(
142
142
  `${e}:pinned`,
143
- async () => p({
143
+ async () => m({
144
144
  entities: await this.loadAllPinned(),
145
145
  nextCursor: null
146
146
  })
@@ -159,19 +159,19 @@ class F {
159
159
  completedRefreshSequence = 0;
160
160
  activityReconciliationScheduled = !1;
161
161
  getState() {
162
- const e = this.recentQuery.getState(), t = this.pinnedQuery.getState(), i = [
163
- ...u(t.data),
164
- ...u(e.data)
165
- ], n = new Map(i.map((o) => [o.id, o])), r = Array.from(n.values()).map(
162
+ const e = this.recentQuery.getState(), t = this.pinnedQuery.getState(), s = [
163
+ ...g(t.data),
164
+ ...g(e.data)
165
+ ], n = new Map(s.map((o) => [o.id, o])), a = Array.from(n.values()).map(
166
166
  (o) => this.applyOverrides(o, this.completedRefreshSequence)
167
- ), a = Array.from(this.optimisticEntities.values()).filter((o) => !n.has(o.id)).reverse(), l = e.data || t.data || a.length > 0 ? p({
168
- entities: [...a, ...r],
167
+ ), l = Array.from(this.optimisticEntities.values()).filter((o) => !n.has(o.id)).reverse(), r = e.data || t.data || l.length > 0 ? m({
168
+ entities: [...l, ...a],
169
169
  nextCursor: e.data?.nextCursor ?? null
170
170
  }) : null;
171
171
  return {
172
172
  key: e.key.slice(0, -7),
173
- status: T(e, t),
174
- data: l,
173
+ status: R(e, t),
174
+ data: r,
175
175
  error: e.error ?? t.error,
176
176
  requestId: Math.max(e.requestId, t.requestId),
177
177
  updatedAt: Math.max(e.updatedAt ?? 0, t.updatedAt ?? 0) || null
@@ -216,56 +216,56 @@ class F {
216
216
  isActive: t,
217
217
  confirmAfterRefresh: this.completedRefreshSequence + 1,
218
218
  releaseAfterRefresh: this.completedRefreshSequence + 2
219
- }), this.updateEntity(e, (i) => ({ ...i, isActive: t }));
219
+ }), this.updateEntity(e, (s) => ({ ...s, isActive: t }));
220
220
  }
221
221
  setPinned(e, t) {
222
- const i = { pinned: t, confirmAfterRefresh: Number.POSITIVE_INFINITY };
223
- return this.pinnedOverrides.set(e, i), this.updateEntity(e, (n) => ({ ...n, isPinned: t })), i;
222
+ const s = { pinned: t, confirmAfterRefresh: Number.POSITIVE_INFINITY };
223
+ return this.pinnedOverrides.set(e, s), this.updateEntity(e, (n) => ({ ...n, isPinned: t })), s;
224
224
  }
225
225
  confirmPinned(e, t) {
226
226
  this.pinnedOverrides.get(e) === t && (t.confirmAfterRefresh = this.completedRefreshSequence + 1);
227
227
  }
228
- rollbackPinned(e, t, i) {
229
- this.pinnedOverrides.get(e) === t && (this.pinnedOverrides.delete(e), this.updateEntity(e, (n) => ({ ...n, isPinned: i })));
228
+ rollbackPinned(e, t, s) {
229
+ this.pinnedOverrides.get(e) === t && (this.pinnedOverrides.delete(e), this.updateEntity(e, (n) => ({ ...n, isPinned: s })));
230
230
  }
231
231
  setTitle(e, t) {
232
- this.titleOverrides.set(e, t), this.updateEntity(e, (i) => ({ ...i, customTitle: t }));
232
+ this.titleOverrides.set(e, t), this.updateEntity(e, (s) => ({ ...s, customTitle: t }));
233
233
  }
234
234
  confirmTitle(e) {
235
235
  this.titleOverrides.delete(e);
236
236
  }
237
237
  reconcileDurableEntities() {
238
238
  const e = [
239
- ...u(this.pinnedQuery.getState().data),
240
- ...u(this.recentQuery.getState().data)
241
- ], t = new Set(e.map((i) => i.id));
242
- for (const i of this.optimisticEntities.keys())
243
- t.has(i) && this.optimisticEntities.delete(i);
244
- for (const i of e) this.applyOverrides(i, this.completedRefreshSequence);
239
+ ...g(this.pinnedQuery.getState().data),
240
+ ...g(this.recentQuery.getState().data)
241
+ ], t = new Set(e.map((s) => s.id));
242
+ for (const s of this.optimisticEntities.keys())
243
+ t.has(s) && this.optimisticEntities.delete(s);
244
+ for (const s of e) this.applyOverrides(s, this.completedRefreshSequence);
245
245
  this.publish();
246
246
  }
247
247
  async loadAllPinned() {
248
248
  const e = [];
249
249
  let t = null;
250
250
  do {
251
- const i = await this.loadPage({ cursor: t, limit: this.limit, pinned: !0 });
252
- e.push(...i.sessions), t = i.nextCursor;
251
+ const s = await this.loadPage({ cursor: t, limit: this.limit, pinned: !0 });
252
+ e.push(...s.sessions), t = s.nextCursor;
253
253
  } while (t);
254
254
  return e;
255
255
  }
256
256
  applyOverrides(e, t) {
257
- let i = e;
257
+ let s = e;
258
258
  const n = this.activityOverrides.get(e.id);
259
- 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 });
260
- const r = this.pinnedOverrides.get(e.id);
261
- 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;
259
+ n && (t >= n.confirmAfterRefresh && e.isActive === n.isActive ? this.activityOverrides.delete(e.id) : t >= n.releaseAfterRefresh ? this.activityOverrides.delete(e.id) : s = { ...s, isActive: n.isActive });
260
+ const a = this.pinnedOverrides.get(e.id);
261
+ return a && (t >= a.confirmAfterRefresh && e.isPinned === !0 === a.pinned ? this.pinnedOverrides.delete(e.id) : s = { ...s, isPinned: a.pinned }), this.titleOverrides.has(e.id) && (s = { ...s, customTitle: this.titleOverrides.get(e.id) ?? null }), s;
262
262
  }
263
263
  updateProjection() {
264
264
  this.publish();
265
265
  }
266
266
  updateEntity(e, t) {
267
- const i = this.optimisticEntities.get(e);
268
- i && this.optimisticEntities.set(e, t(i)), this.publish();
267
+ const s = this.optimisticEntities.get(e);
268
+ s && this.optimisticEntities.set(e, t(s)), this.publish();
269
269
  }
270
270
  hasUnconfirmedActivityOverride() {
271
271
  return Array.from(this.activityOverrides.values()).some(
@@ -276,16 +276,16 @@ class F {
276
276
  for (const e of this.listeners) e(this.getState());
277
277
  }
278
278
  }
279
- function u(s) {
280
- return s ? s.ids.map((e) => s.entitiesById[e]).filter((e) => !!e) : [];
279
+ function g(i) {
280
+ return i ? i.ids.map((e) => i.entitiesById[e]).filter((e) => !!e) : [];
281
281
  }
282
- function T(s, e) {
283
- 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";
282
+ function R(i, e) {
283
+ return i.status === "error" || e.status === "error" ? "error" : i.status === "loading" || e.status === "loading" ? "loading" : i.status === "refreshing" || e.status === "refreshing" ? "refreshing" : i.status === "loading_more" ? "loading_more" : i.status === "ready" || e.status === "ready" ? "ready" : "not_requested";
284
284
  }
285
- class U {
285
+ class G {
286
286
  constructor(e, t = null) {
287
287
  this.storage = e, t && (this.decisions = new Map(
288
- t.filter(v).map((i) => [this.getDecisionKey(i), i])
288
+ t.filter(I).map((s) => [this.getDecisionKey(s), s])
289
289
  ), this.initialized = !0);
290
290
  }
291
291
  storage;
@@ -297,113 +297,113 @@ class U {
297
297
  if (this.initialized) return;
298
298
  const e = await this.storage.load();
299
299
  this.decisions = new Map(
300
- e.filter(v).map((t) => [this.getDecisionKey(t), t])
300
+ e.filter(I).map((t) => [this.getDecisionKey(t), t])
301
301
  ), this.initialized = !0;
302
302
  }
303
303
  isEligible(e, t = Date.now()) {
304
- const i = this.scheduledEligibility.get(this.getExactKey(e));
305
- return i !== void 0 && i > t ? !1 : this.isDecisionEligible(this.decisions.get(this.getExactKey(e)), t) && this.isDecisionEligible(this.decisions.get(this.getCategoryKey(e)), t);
304
+ const s = this.scheduledEligibility.get(this.getExactKey(e));
305
+ return s !== void 0 && s > t ? !1 : this.isDecisionEligible(this.decisions.get(this.getExactKey(e)), t) && this.isDecisionEligible(this.decisions.get(this.getCategoryKey(e)), t);
306
306
  }
307
307
  getDecision(e) {
308
308
  return this.decisions.get(this.getExactKey(e)) ?? this.decisions.get(this.getCategoryKey(e)) ?? null;
309
309
  }
310
310
  getStatus(e, t = Date.now()) {
311
- const i = this.scheduledEligibility.get(this.getExactKey(e));
312
- if (i !== void 0 && i > t) return "scheduled";
311
+ const s = this.scheduledEligibility.get(this.getExactKey(e));
312
+ if (s !== void 0 && s > t) return "scheduled";
313
313
  const n = this.getDecision(e);
314
314
  return n ? n.action === "never" || n.action === "dont_show_again" ? "suppressed" : n.action === "dismiss" ? "resolved" : n.nextEligibleAt && Date.parse(n.nextEligibleAt) > t ? "snoozed" : "presentable" : "presentable";
315
315
  }
316
316
  scheduleEligibility(e, t) {
317
- const i = this.getExactKey(e), n = this.scheduledEligibility.get(i);
318
- return n !== void 0 ? n : (this.scheduledEligibility.set(i, t), t);
317
+ const s = this.getExactKey(e), n = this.scheduledEligibility.get(s);
318
+ return n !== void 0 ? n : (this.scheduledEligibility.set(s, t), t);
319
319
  }
320
320
  getNextEligibilityAt(e = Date.now()) {
321
321
  const t = [
322
- ...Array.from(this.scheduledEligibility.values()).filter((i) => i > e),
323
- ...Array.from(this.decisions.values()).map((i) => i.nextEligibleAt ? Date.parse(i.nextEligibleAt) : Number.NaN).filter((i) => Number.isFinite(i) && i > e)
322
+ ...Array.from(this.scheduledEligibility.values()).filter((s) => s > e),
323
+ ...Array.from(this.decisions.values()).map((s) => s.nextEligibleAt ? Date.parse(s.nextEligibleAt) : Number.NaN).filter((s) => Number.isFinite(s) && s > e)
324
324
  ];
325
325
  return t.length > 0 ? Math.min(...t) : null;
326
326
  }
327
- act(e, t, i = {}) {
328
- const n = this.actionQueue.then(() => this.applyAction(e, t, i));
327
+ act(e, t, s = {}) {
328
+ const n = this.actionQueue.then(() => this.applyAction(e, t, s));
329
329
  return this.actionQueue = n.then(() => {
330
330
  }, () => {
331
331
  }), n;
332
332
  }
333
- async applyAction(e, t, i) {
333
+ async applyAction(e, t, s) {
334
334
  if (!e.allowedActions.includes(t))
335
335
  throw new Error(`Interaction ${e.key} does not allow ${t}.`);
336
- if (!E(t))
336
+ if (!D(t))
337
337
  throw new Error(`Interaction action ${t} is not a persistence decision.`);
338
- const n = i.now ?? /* @__PURE__ */ new Date(), r = {
338
+ const n = s.now ?? /* @__PURE__ */ new Date(), a = {
339
339
  promptKey: e.key,
340
340
  category: e.category,
341
341
  action: t,
342
342
  scope: e.scope,
343
343
  decidedAt: n.toISOString(),
344
- nextEligibleAt: this.getNextEligibleAt(e, t, n, i.snoozeUntil)
345
- }, a = t === "dont_show_again" ? this.getCategoryKey(e) : this.getExactKey(e), l = new Map(this.decisions);
346
- return l.set(a, r), await this.storage.save([...l.values()]), this.decisions = l, r;
344
+ nextEligibleAt: this.getNextEligibleAt(e, t, n, s.snoozeUntil)
345
+ }, l = t === "dont_show_again" ? this.getCategoryKey(e) : this.getExactKey(e), r = new Map(this.decisions);
346
+ return r.set(l, a), await this.storage.save([...r.values()]), this.decisions = r, a;
347
347
  }
348
348
  isDecisionEligible(e, t) {
349
349
  return e ? e.action === "dismiss" || e.action === "never" || e.action === "dont_show_again" ? !1 : !e.nextEligibleAt || Date.parse(e.nextEligibleAt) <= t : !0;
350
350
  }
351
- getNextEligibleAt(e, t, i, n) {
351
+ getNextEligibleAt(e, t, s, n) {
352
352
  if (t === "later")
353
- return new Date(i.getTime() + (e.laterDelayMs ?? 3600 * 1e3)).toISOString();
353
+ return new Date(s.getTime() + (e.laterDelayMs ?? 3600 * 1e3)).toISOString();
354
354
  if (t === "snooze") {
355
- if (!n || n.getTime() <= i.getTime())
355
+ if (!n || n.getTime() <= s.getTime())
356
356
  throw new Error("Snooze requires a future next-eligible time.");
357
357
  return n.toISOString();
358
358
  }
359
359
  return null;
360
360
  }
361
361
  getDecisionKey(e) {
362
- const t = m(e.scope);
362
+ const t = b(e.scope);
363
363
  return e.action === "dont_show_again" ? `${t}:category:${e.category}` : `${t}:interaction:${e.promptKey}`;
364
364
  }
365
365
  getExactKey(e) {
366
- return `${m(e.scope)}:interaction:${e.key}`;
366
+ return `${b(e.scope)}:interaction:${e.key}`;
367
367
  }
368
368
  getCategoryKey(e) {
369
- return `${m(e.scope)}:category:${e.category}`;
369
+ return `${b(e.scope)}:category:${e.category}`;
370
370
  }
371
371
  }
372
- function N(s, e) {
372
+ function V(i, e) {
373
373
  return {
374
- load: async () => M(s, e),
375
- save: async (t) => s.setItem(e, JSON.stringify(t))
374
+ load: async () => x(i, e),
375
+ save: async (t) => i.setItem(e, JSON.stringify(t))
376
376
  };
377
377
  }
378
- function M(s, e) {
379
- const t = s.getItem(e);
378
+ function x(i, e) {
379
+ const t = i.getItem(e);
380
380
  if (!t) return [];
381
- const i = JSON.parse(t);
382
- return Array.isArray(i) ? i.filter(v) : [];
381
+ const s = JSON.parse(t);
382
+ return Array.isArray(s) ? s.filter(I) : [];
383
383
  }
384
- function m(s) {
385
- return `${s.level}:${s.key}`;
384
+ function b(i) {
385
+ return `${i.level}:${i.key}`;
386
386
  }
387
- function E(s) {
388
- return s === "dismiss" || s === "later" || s === "snooze" || s === "never" || s === "dont_show_again";
387
+ function D(i) {
388
+ return i === "dismiss" || i === "later" || i === "snooze" || i === "never" || i === "dont_show_again";
389
389
  }
390
- function v(s) {
391
- if (!s || typeof s != "object") return !1;
392
- const e = s;
393
- return typeof e.promptKey == "string" && typeof e.category == "string" && typeof e.decidedAt == "string" && (e.nextEligibleAt === null || typeof e.nextEligibleAt == "string") && E(e.action) && !!(e.scope && typeof e.scope == "object" && typeof e.scope.level == "string" && typeof e.scope.key == "string");
390
+ function I(i) {
391
+ if (!i || typeof i != "object") return !1;
392
+ const e = i;
393
+ return typeof e.promptKey == "string" && typeof e.category == "string" && typeof e.decidedAt == "string" && (e.nextEligibleAt === null || typeof e.nextEligibleAt == "string") && D(e.action) && !!(e.scope && typeof e.scope == "object" && typeof e.scope.level == "string" && typeof e.scope.key == "string");
394
394
  }
395
- const D = {
395
+ const C = {
396
396
  working: "⏳",
397
397
  completed: "✅",
398
398
  failed: "❗",
399
399
  stopped: "⏹️"
400
- }, O = /^(?:⌛|⏳|✅|❗|⏹️) Pluno(?:: )?/;
401
- function k(s, e) {
402
- if (!e) return g(s);
403
- const t = g(s), i = `${D[e]} Pluno`;
404
- return t ? `${i}: ${t}` : i;
400
+ }, L = /^(?:⌛|⏳|✅|❗|⏹️) Pluno(?:: )?/;
401
+ function q(i, e) {
402
+ if (!e) return y(i);
403
+ const t = y(i), s = `${C[e]} Pluno`;
404
+ return t ? `${s}: ${t}` : s;
405
405
  }
406
- class H {
406
+ class Z {
407
407
  constructor(e) {
408
408
  this.titleDocument = e;
409
409
  }
@@ -420,16 +420,16 @@ class H {
420
420
  this.liveStatusVersion += 1, this.applyClear();
421
421
  }
422
422
  async syncStatus(e) {
423
- const t = this.liveStatusVersion, i = await e();
424
- i === void 0 || t !== this.liveStatusVersion || (i ? this.applyStatus(i) : this.applyClear());
423
+ const t = this.liveStatusVersion, s = await e();
424
+ s === void 0 || t !== this.liveStatusVersion || (s ? this.applyStatus(s) : this.applyClear());
425
425
  }
426
426
  applyStatus(e) {
427
427
  const t = this.titleDocument.getTitle();
428
- t !== this.lastAppliedTitle && (this.baseTitle = g(t)), this.status = e, this.stopObserving || (this.stopObserving = this.titleDocument.observeTitle(() => this.handleTitleChanged())), this.applyTitle();
428
+ t !== this.lastAppliedTitle && (this.baseTitle = y(t)), this.status = e, this.stopObserving || (this.stopObserving = this.titleDocument.observeTitle(() => this.handleTitleChanged())), this.applyTitle();
429
429
  }
430
430
  applyClear() {
431
- const e = this.titleDocument.getTitle(), t = this.lastAppliedTitle !== null && e === this.lastAppliedTitle, i = this.lastAppliedTitle === null ? g(e) : e;
432
- this.status = null, this.lastAppliedTitle = null, this.stopObserving?.(), this.stopObserving = null, t ? this.titleDocument.setTitle(this.baseTitle) : i !== e && this.titleDocument.setTitle(i);
431
+ const e = this.titleDocument.getTitle(), t = this.lastAppliedTitle !== null && e === this.lastAppliedTitle, s = this.lastAppliedTitle === null ? y(e) : e;
432
+ this.status = null, this.lastAppliedTitle = null, this.stopObserving?.(), this.stopObserving = null, t ? this.titleDocument.setTitle(this.baseTitle) : s !== e && this.titleDocument.setTitle(s);
433
433
  }
434
434
  handleTitleChanged() {
435
435
  !this.status || this.titleDocument.getTitle() === this.lastAppliedTitle || this.applyTitle();
@@ -437,19 +437,19 @@ class H {
437
437
  applyTitle() {
438
438
  if (!this.status)
439
439
  return;
440
- const e = k(this.baseTitle, this.status);
440
+ const e = q(this.baseTitle, this.status);
441
441
  this.lastAppliedTitle = e, this.titleDocument.getTitle() !== e && this.titleDocument.setTitle(e);
442
442
  }
443
443
  }
444
- function j(s) {
444
+ function J(i) {
445
445
  return {
446
- getTitle: () => s.title,
446
+ getTitle: () => i.title,
447
447
  setTitle: (e) => {
448
- s.title = e;
448
+ i.title = e;
449
449
  },
450
450
  observeTitle: (e) => {
451
451
  const t = new MutationObserver(e);
452
- return t.observe(s.head, {
452
+ return t.observe(i.head, {
453
453
  childList: !0,
454
454
  subtree: !0,
455
455
  characterData: !0
@@ -457,21 +457,43 @@ function j(s) {
457
457
  }
458
458
  };
459
459
  }
460
- function g(s) {
461
- return s.replace(O, "");
460
+ function y(i) {
461
+ return i.replace(L, "");
462
+ }
463
+ function _(i, e) {
464
+ const t = new Set([
465
+ i.assistantDraftRespondsToUserMessageId,
466
+ i.activeResponseUserMessageId,
467
+ i.messages.filter((n) => n.role === "user").slice(-1)[0]?.id
468
+ ].filter((n) => !!n)), s = i.messages.filter((n) => !(n.dataType === "run_status" && n.loading && t.has(n.respondsToUserMessageId ?? ""))).map((n) => t.has(n.respondsToUserMessageId ?? "") ? { ...n, loading: !1 } : n);
469
+ for (const n of t)
470
+ s.some((a) => a.respondsToUserMessageId === n && (a.dataType === "run_status" || a.dataType === "run_error" || a.role === "assistant" && a.phase !== "commentary")) || s.push({ id: `local-interrupted:${n}`, role: "system", dataType: "run_status", content: "Run stopped by user.", createdAt: e, respondsToUserMessageId: n });
471
+ return {
472
+ ...i,
473
+ messages: s,
474
+ isThinking: !1,
475
+ isRetrying: !1,
476
+ pendingMessageStatus: null,
477
+ turnPhase: null,
478
+ taskStatus: "stopped",
479
+ lastError: null,
480
+ lastErrorCode: null
481
+ };
462
482
  }
463
- const f = (s) => s === null || typeof s == "string" && /^[a-zA-Z0-9:_-]{1,160}$/.test(s);
464
- function R(s) {
465
- if (!s || typeof s != "object") return !1;
466
- const e = s;
467
- return typeof e.observedAt == "string" && e.observedAt.length <= 40 && Number.isFinite(Date.parse(e.observedAt)) && f(e.sessionId) && f(e.responseItemId) && f(e.respondsToUserMessageId) && typeof e.panelVisible == "boolean" && typeof e.documentVisible == "boolean" && typeof e.loading == "boolean";
483
+ const S = (i) => i === null || typeof i == "string" && /^[a-zA-Z0-9:_-]{1,160}$/.test(i);
484
+ function Q(i) {
485
+ if (!i || typeof i != "object") return !1;
486
+ const e = i;
487
+ 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";
468
488
  }
469
- const S = 500;
470
- function x(s) {
471
- 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();
472
- return e.length > S ? `${e.slice(0, S - 1)}…` : e;
489
+ const M = 500;
490
+ function U(i) {
491
+ const e = i.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();
492
+ return e.length > M ? `${e.slice(0, M - 1)}…` : e;
473
493
  }
474
- const C = {
494
+ const $ = {
495
+ "in-progress-stop-unavailable": "An in-progress response has no visible enabled interrupt control.",
496
+ "stop-did-not-interrupt": "The stopped response remained in progress after an interrupt click.",
475
497
  "duplicate-message-item": "A canonical message rendered more than once.",
476
498
  "duplicate-canonical-item": "A canonical session item rendered more than once.",
477
499
  "duplicate-tool-call": "A tool call rendered more than once.",
@@ -484,43 +506,45 @@ const C = {
484
506
  "thinking-groups-without-user-message": "Multiple thinking groups appeared without a user message between them.",
485
507
  "thinking-without-progress": "Thinking remained visible without progress for five minutes."
486
508
  };
487
- function L(s) {
488
- return typeof s == "string" && s.startsWith("ui_invariant:") && Object.prototype.hasOwnProperty.call(C, s.slice(13));
509
+ function K(i) {
510
+ return typeof i == "string" && i.startsWith("ui_invariant:") && Object.prototype.hasOwnProperty.call($, i.slice(13));
489
511
  }
490
- function w(s) {
512
+ function P(i) {
491
513
  return {
492
- ...s.id === void 0 ? {} : { id: s.id },
493
- name: s.name,
494
- mimeType: s.mimeType,
495
- sizeBytes: s.sizeBytes,
496
- ...s.sandboxPath === void 0 ? {} : { sandboxPath: s.sandboxPath },
497
- ...s.storageKey === void 0 ? {} : { storageKey: s.storageKey },
498
- ...s.fileUrl === void 0 ? {} : { fileUrl: s.fileUrl }
514
+ ...i.id === void 0 ? {} : { id: i.id },
515
+ name: i.name,
516
+ mimeType: i.mimeType,
517
+ sizeBytes: i.sizeBytes,
518
+ ...i.sandboxPath === void 0 ? {} : { sandboxPath: i.sandboxPath },
519
+ ...i.storageKey === void 0 ? {} : { storageKey: i.storageKey },
520
+ ...i.fileUrl === void 0 ? {} : { fileUrl: i.fileUrl }
499
521
  };
500
522
  }
501
- function V(s) {
502
- if (!s || typeof s != "object" || !("type" in s)) return !1;
503
- const e = s;
523
+ function Y(i) {
524
+ if (!i || typeof i != "object" || !("type" in i)) return !1;
525
+ const e = i;
504
526
  switch (e.type) {
505
527
  case "runtime.connect":
506
528
  case "session.new":
507
- case "run.stop":
508
529
  case "run.retry":
509
530
  return !0;
531
+ case "run.stop":
532
+ 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);
510
533
  case "runtime.report_response_visibility":
511
- return R(e.observation);
534
+ return Q(e.observation);
512
535
  case "runtime.warmup":
513
536
  return e.reason === "panel_open" || e.reason === "extension_install" || e.reason === "composer_input";
514
537
  case "runtime.report_displayed_error":
515
538
  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);
516
539
  case "runtime.report_invalid_state_transition":
517
- return (e.reason === "submitted_turn_returned_to_welcome_without_new_chat" || e.reason === "new_messages_button_without_user_scroll" || L(e.reason)) && (e.clientMessageId === void 0 || typeof e.clientMessageId == "string");
540
+ 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");
518
541
  case "runtime.widget_lifecycle":
519
542
  return (e.action === "opened" || e.action === "closed" || e.action === "minimized") && typeof e.trigger == "string";
520
543
  case "session.load":
521
544
  return typeof e.sessionId == "string" && e.sessionId.length > 0;
522
545
  case "session.list":
523
546
  return (e.cursor === void 0 || e.cursor === null || typeof e.cursor == "string") && (e.limit === void 0 || typeof e.limit == "number") && (e.pinned === void 0 || typeof e.pinned == "boolean");
547
+ case "composer.select_model":
524
548
  case "session.set_model":
525
549
  return typeof e.model == "string";
526
550
  case "session.pin":
@@ -532,18 +556,18 @@ function V(s) {
532
556
  case "conversation.stage_proactive_suggestion":
533
557
  return typeof e.question == "string" && typeof e.clientMessageId == "string";
534
558
  case "conversation.stage":
535
- return typeof e.content == "string" && typeof e.clientMessageId == "string" && (e.submittedAt === void 0 || typeof e.submittedAt == "number") && (e.attachments === void 0 || Array.isArray(e.attachments));
559
+ return typeof e.content == "string" && typeof e.clientMessageId == "string" && (e.submittedAt === void 0 || typeof e.submittedAt == "number") && (e.requestedModel === void 0 || typeof e.requestedModel == "string") && (e.attachments === void 0 || Array.isArray(e.attachments));
536
560
  case "conversation.fail_staged":
537
561
  return typeof e.clientMessageId == "string" && typeof e.message == "string";
538
562
  case "conversation.send":
539
- return typeof e.content == "string" && typeof e.clientMessageId == "string" && (e.automationOnboarding === void 0 || typeof e.automationOnboarding == "boolean") && (e.attachments === void 0 || Array.isArray(e.attachments));
563
+ return typeof e.content == "string" && typeof e.clientMessageId == "string" && (e.requestedModel === void 0 || typeof e.requestedModel == "string") && (e.automationOnboarding === void 0 || typeof e.automationOnboarding == "boolean") && (e.attachments === void 0 || Array.isArray(e.attachments));
540
564
  default:
541
565
  return !1;
542
566
  }
543
567
  }
544
- class Z {
545
- constructor(e, t, i) {
546
- this.adapter = t, this.state = y(e), this.model = i;
568
+ class W {
569
+ constructor(e, t, s) {
570
+ this.adapter = t, this.state = A(e), this.model = s;
547
571
  }
548
572
  adapter;
549
573
  listeners = {};
@@ -552,56 +576,80 @@ class Z {
552
576
  interactionListeners = /* @__PURE__ */ new Set();
553
577
  accountListeners = /* @__PURE__ */ new Set();
554
578
  state;
555
- sessionHistoryState = h("unavailable");
579
+ sessionHistoryState = f("unavailable");
556
580
  model;
557
581
  interactions = [];
558
582
  account = null;
559
583
  stagedProactiveSuggestionClientMessageId = null;
560
584
  unacknowledgedSubmissions = /* @__PURE__ */ new Map();
585
+ submissionGeneration = 0;
586
+ stoppedProjection = null;
561
587
  operationQueue = Promise.resolve();
562
588
  destroyed = !1;
563
589
  on(e, t) {
564
- const i = this.listeners[e] ?? /* @__PURE__ */ new Set();
565
- return i.add(t), this.listeners[e] = i, () => i.delete(t);
590
+ const s = this.listeners[e] ?? /* @__PURE__ */ new Set();
591
+ return s.add(t), this.listeners[e] = s, () => s.delete(t);
566
592
  }
567
593
  getState() {
568
- return y(this.state);
569
- }
570
- updateProjection(e, t, i, n, r) {
571
- if (!this.destroyed) {
572
- this.state = y(e);
573
- for (const [a, l] of this.unacknowledgedSubmissions) {
574
- if (e.user?.id !== l.userId || l.sessionId !== null && e.sessionId !== l.sessionId) {
575
- this.unacknowledgedSubmissions.delete(a);
576
- continue;
577
- }
578
- const o = this.state.messages.find(
579
- (c) => c.clientMessageId === a
580
- );
581
- if (o) {
582
- o.attachments = q(
583
- l.message.attachments,
584
- o.attachments
585
- ), this.unacknowledgedSubmissions.delete(a);
586
- continue;
587
- }
588
- l.sessionId ??= e.sessionId, this.state.messages.push(l.message), this.state.pendingMessageStatus = "sending", this.state.turnPhase ??= "sending", this.state.taskStatus ??= "working";
594
+ return A(this.state);
595
+ }
596
+ updateProjection(e, t, s, n, a) {
597
+ if (this.destroyed) return;
598
+ const l = this.state;
599
+ if (this.state = A(e), l.user?.id === e.user?.id)
600
+ for (const r of this.state.messages) {
601
+ if (r.role !== "user" || !r.attachments?.length) continue;
602
+ const o = r.clientMessageId, c = l.messages.find((u) => u.role === "user" && (u.id === r.id || o && u.clientMessageId === o));
603
+ l.sessionId !== e.sessionId && !(l.sessionId === null && o && c?.clientMessageId === o) || (r.attachments = T(c?.attachments, r.attachments));
589
604
  }
590
- if (t !== void 0 && (this.model = t), i) {
591
- this.sessionHistoryState = I(i);
592
- for (const a of this.sessionHistoryListeners)
593
- a(this.getSessionHistoryState());
605
+ if (this.stoppedProjection) {
606
+ const r = this.stoppedProjection, o = new Set(r.messages.filter((d) => d.role === "user").map((d) => d.id)), c = e.sessionId === r.sessionId && e.user?.id === r.user?.id, u = e.messages.some((d) => d.role === "user" && !o.has(d.id) && !r.messages.some((h) => h.clientMessageId && h.clientMessageId === d.clientMessageId));
607
+ if (!c || u)
608
+ this.stoppedProjection = null;
609
+ else {
610
+ const d = [
611
+ r.activeResponseUserMessageId,
612
+ r.assistantDraftRespondsToUserMessageId,
613
+ r.messages.filter((v) => v.role === "user").slice(-1)[0]?.id
614
+ ].filter(Boolean), h = d.length > 0 && d.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")));
615
+ this.state = _(h ? this.state : {
616
+ ...this.state,
617
+ messages: r.messages,
618
+ assistantDraft: r.assistantDraft
619
+ }, (/* @__PURE__ */ new Date()).toISOString()), this.stoppedProjection = this.getState();
594
620
  }
595
- if (n) {
596
- this.interactions = n.map((a) => ({ ...a }));
597
- for (const a of this.interactionListeners) a(this.getInteractions());
621
+ }
622
+ for (const [r, o] of this.unacknowledgedSubmissions) {
623
+ if (e.user?.id !== o.userId || o.sessionId !== null && e.sessionId !== o.sessionId) {
624
+ this.unacknowledgedSubmissions.delete(r);
625
+ continue;
598
626
  }
599
- if (r !== void 0) {
600
- this.account = r ? { ...r } : null;
601
- for (const a of this.accountListeners) a(this.getAccount());
627
+ const c = this.state.messages.find(
628
+ (u) => u.clientMessageId === r
629
+ );
630
+ if (c) {
631
+ c.attachments = T(
632
+ o.message.attachments,
633
+ c.attachments
634
+ ), this.unacknowledgedSubmissions.delete(r);
635
+ continue;
602
636
  }
603
- this.emit("state", this.getState());
637
+ o.sessionId ??= e.sessionId, this.state.messages.push(o.message), this.state.pendingMessageStatus = "sending", this.state.turnPhase ??= "sending", this.state.taskStatus ??= "working";
638
+ }
639
+ if (t !== void 0 && (this.model = t), s && JSON.stringify(s) !== JSON.stringify(this.sessionHistoryState)) {
640
+ this.sessionHistoryState = E(s);
641
+ for (const r of this.sessionHistoryListeners)
642
+ r(this.getSessionHistoryState());
643
+ }
644
+ if (n && JSON.stringify(n) !== JSON.stringify(this.interactions)) {
645
+ this.interactions = n.map((r) => ({ ...r }));
646
+ for (const r of this.interactionListeners) r(this.getInteractions());
647
+ }
648
+ if (a !== void 0 && JSON.stringify(a) !== JSON.stringify(this.account)) {
649
+ this.account = a ? { ...a } : null;
650
+ for (const r of this.accountListeners) r(this.getAccount());
604
651
  }
652
+ this.emit("state", this.getState());
605
653
  }
606
654
  async connect() {
607
655
  await this.dispatch({ type: "runtime.connect" });
@@ -632,99 +680,106 @@ class Z {
632
680
  }).catch(() => {
633
681
  });
634
682
  }
635
- reportDisplayedError(e, t, i) {
683
+ reportDisplayedError(e, t, s) {
636
684
  this.adapter.dispatch({
637
685
  type: "runtime.report_displayed_error",
638
686
  reason: e,
639
687
  errorFingerprint: t,
640
- ...i ? { displayedMessage: x(i) } : {}
688
+ ...s ? { displayedMessage: U(s) } : {}
641
689
  }).catch(() => {
642
690
  });
643
691
  }
644
692
  sendMessage(e, t = {}) {
645
- const i = e.trim(), n = t.attachments ?? [];
646
- if (!i && n.length === 0) return Promise.resolve(null);
647
- const r = t.clientMessageId ?? (t.proactiveSuggestionQuestion && this.stagedProactiveSuggestionClientMessageId ? this.stagedProactiveSuggestionClientMessageId : crypto.randomUUID()), a = t.submittedAt ?? Date.now(), l = this.state, o = {
648
- id: `local-${r}`,
693
+ const s = e.trim(), n = t.attachments ?? [];
694
+ if (!s && n.length === 0) return Promise.resolve(null);
695
+ const a = t.clientMessageId ?? (t.proactiveSuggestionQuestion && this.stagedProactiveSuggestionClientMessageId ? this.stagedProactiveSuggestionClientMessageId : crypto.randomUUID()), l = t.submittedAt ?? Date.now(), r = this.state, o = this.submissionGeneration, c = {
696
+ id: `local-${a}`,
649
697
  role: "user",
650
- content: i,
698
+ content: s,
651
699
  createdAt: (/* @__PURE__ */ new Date()).toISOString(),
652
700
  ...n.length > 0 ? { attachments: n } : {},
653
- clientMessageId: r
701
+ clientMessageId: a
654
702
  };
655
- return this.unacknowledgedSubmissions.set(r, {
656
- message: { ...o, attachments: o.attachments?.map((c) => ({ ...c })) },
657
- sessionId: l.sessionId,
658
- userId: l.user?.id
703
+ this.unacknowledgedSubmissions.set(a, {
704
+ message: { ...c, attachments: c.attachments?.map((d) => ({ ...d })) },
705
+ sessionId: r.sessionId,
706
+ userId: r.user?.id
659
707
  }), this.state = {
660
708
  ...this.state,
661
- messages: [...this.state.messages, o],
709
+ messages: [...this.state.messages, c],
662
710
  pendingMessageStatus: "sending",
663
711
  turnPhase: this.state.isThinking ? this.state.turnPhase : "sending",
664
712
  taskStatus: "working",
665
713
  isRetrying: !1,
666
714
  lastError: null
667
- }, this.emit("state", this.getState()), this.enqueueOperation(() => this.sendMessageNow(
668
- i,
669
- { ...t, clientMessageId: r, submittedAt: a },
670
- l
715
+ };
716
+ const u = this.enqueueOperation(() => this.sendMessageNow(
717
+ s,
718
+ { ...t, clientMessageId: a, submittedAt: l },
719
+ r,
720
+ o
671
721
  ));
722
+ return this.emit("state", this.getState()), u;
672
723
  }
673
- async sendMessageNow(e, t, i) {
674
- const n = e, r = t.clientMessageId;
675
- let a = t.attachments ?? [], l = !1;
724
+ async sendMessageNow(e, t, s, n) {
725
+ const a = e, l = t.clientMessageId;
726
+ let r = t.attachments ?? [], o = !1;
727
+ if (n !== this.submissionGeneration) return null;
676
728
  try {
677
729
  if (await this.adapter.dispatch({
678
730
  type: "conversation.stage",
679
- content: n,
680
- clientMessageId: r,
731
+ content: a,
732
+ clientMessageId: l,
681
733
  proactiveSuggestionQuestion: t.proactiveSuggestionQuestion,
682
734
  // Preview URLs belong to the renderer's optimistic snapshot and are not valid runtime-command metadata.
683
- attachments: a.length > 0 ? a.map(w) : void 0,
735
+ attachments: r.length > 0 ? r.map(P) : void 0,
684
736
  submittedAt: t.submittedAt
685
- }), l = !0, a.length > 0) {
737
+ }), n !== this.submissionGeneration) return null;
738
+ if (o = !0, r.length > 0) {
686
739
  if (!this.adapter.uploadAttachment)
687
740
  throw new Error("The runtime does not support attachments.");
688
- const c = [];
689
- for (const d of a) {
741
+ const u = [];
742
+ for (const d of r) {
690
743
  if (d.sandboxPath || d.storageKey) {
691
- c.push(d);
744
+ u.push(d);
692
745
  continue;
693
746
  }
694
- const b = d.id ? this.attachmentFiles.get(d.id) : void 0;
695
- if (!b) throw new Error(`Attachment bytes are unavailable for ${d.name}`);
696
- c.push(await this.adapter.uploadAttachment(b, d, { clientMessageId: r }));
747
+ const h = d.id ? this.attachmentFiles.get(d.id) : void 0;
748
+ if (!h) throw new Error(`Attachment bytes are unavailable for ${d.name}`);
749
+ if (u.push(await this.adapter.uploadAttachment(h, d, { clientMessageId: l })), n !== this.submissionGeneration) return null;
697
750
  }
698
- a = c;
751
+ r = u;
699
752
  }
700
- const o = await this.adapter.dispatch({
753
+ const c = await this.adapter.dispatch({
701
754
  type: "conversation.send",
702
- content: n,
703
- clientMessageId: r,
755
+ content: a,
756
+ clientMessageId: l,
704
757
  initiatedBy: t.initiatedBy,
705
758
  invocation: t.invocation,
706
759
  proactiveSuggestionQuestion: t.proactiveSuggestionQuestion,
707
760
  ...t.automationOnboarding ? { automationOnboarding: !0 } : {},
708
- attachments: a.length > 0 ? a.map(w) : void 0
761
+ attachments: r.length > 0 ? r.map(P) : void 0
709
762
  });
710
- for (const c of t.attachments ?? [])
711
- c.id && this.attachmentFiles.delete(c.id);
712
- return r === this.stagedProactiveSuggestionClientMessageId && (this.stagedProactiveSuggestionClientMessageId = null), o?.clientMessageId ?? r;
713
- } catch (o) {
714
- throw this.unacknowledgedSubmissions.delete(r), this.state = {
763
+ if (n !== this.submissionGeneration) return null;
764
+ for (const u of t.attachments ?? [])
765
+ u.id && this.attachmentFiles.delete(u.id);
766
+ return l === this.stagedProactiveSuggestionClientMessageId && (this.stagedProactiveSuggestionClientMessageId = null), c?.clientMessageId ?? l;
767
+ } catch (c) {
768
+ if (n !== this.submissionGeneration) return null;
769
+ throw this.unacknowledgedSubmissions.delete(l), this.state = {
715
770
  ...this.state,
716
771
  messages: this.state.messages.filter(
717
- (c) => c.id !== `local-${r}` && c.id !== `optimistic-user-message:${r}`
772
+ (u) => u.id !== `local-${l}` && u.id !== `optimistic-user-message:${l}`
718
773
  ),
719
- pendingMessageStatus: i.pendingMessageStatus,
720
- turnPhase: i.turnPhase,
721
- isThinking: i.isThinking,
722
- taskStatus: i.taskStatus
723
- }, this.emit("state", this.getState()), l && await this.adapter.dispatch({
774
+ pendingMessageStatus: s.pendingMessageStatus,
775
+ turnPhase: s.turnPhase,
776
+ isThinking: s.isThinking,
777
+ taskStatus: s.taskStatus
778
+ }, this.emit("state", this.getState()), o && await this.adapter.dispatch({
724
779
  type: "conversation.fail_staged",
725
- clientMessageId: r,
726
- message: o instanceof Error ? o.message : String(o)
727
- }), o;
780
+ clientMessageId: l,
781
+ message: c instanceof Error ? c.message : String(c)
782
+ }), c;
728
783
  }
729
784
  }
730
785
  getModel() {
@@ -735,7 +790,7 @@ class Z {
735
790
  });
736
791
  }
737
792
  retryLastMessage() {
738
- return this.dispatch({ type: "run.retry" }), !0;
793
+ return this.stoppedProjection = null, this.dispatch({ type: "run.retry" }), !0;
739
794
  }
740
795
  createLocalAttachment(e) {
741
796
  const t = crypto.randomUUID();
@@ -747,23 +802,37 @@ class Z {
747
802
  };
748
803
  }
749
804
  stop() {
750
- return this.unacknowledgedSubmissions.clear(), this.dispatch({ type: "run.stop" }).then(() => {
805
+ const e = this.cancelPendingSubmissions();
806
+ this.state = _(this.state, (/* @__PURE__ */ new Date()).toISOString()), this.stoppedProjection = this.getState(), this.emit("state", this.getState());
807
+ const t = this.adapter.dispatch({ type: "run.stop", ...e.length ? { clientMessageIds: e } : {} });
808
+ return this.operationQueue = t.then(() => {
809
+ }, () => {
810
+ }), t.then(() => {
751
811
  });
752
812
  }
813
+ cancelPendingSubmissions() {
814
+ const e = [...this.unacknowledgedSubmissions.keys()];
815
+ this.submissionGeneration++;
816
+ for (const t of this.unacknowledgedSubmissions.values())
817
+ for (const s of t.message.attachments ?? [])
818
+ s.id && this.attachmentFiles.delete(s.id);
819
+ return this.unacknowledgedSubmissions.clear(), this.operationQueue = Promise.resolve(), e;
820
+ }
753
821
  startNewSession(e = {}) {
754
- return this.unacknowledgedSubmissions.clear(), e.notifyTransport === !1 ? Promise.resolve() : this.dispatch({ type: "session.new" }).then(() => {
822
+ return this.cancelPendingSubmissions(), this.stoppedProjection = null, e.notifyTransport === !1 ? Promise.resolve() : this.dispatch({ type: "session.new" }).then(() => {
755
823
  });
756
824
  }
757
825
  async listSessions(e = {}) {
758
- await this.dispatch({ type: "session.list", ...e });
759
- const t = this.sessionHistoryState.data;
760
- return {
761
- sessions: _(t),
762
- nextCursor: t?.nextCursor ?? null
763
- };
826
+ const t = await this.dispatch({ type: "session.list", ...e });
827
+ if (t === void 0) {
828
+ const s = this.getSessionHistoryState().data;
829
+ return { sessions: s ? s.ids.map((n) => s.entitiesById[n]) : [], nextCursor: s?.nextCursor ?? null };
830
+ }
831
+ if (!t?.sessionHistoryPage) throw new Error("Session list command did not return a page.");
832
+ return t.sessionHistoryPage;
764
833
  }
765
834
  getSessionHistoryState() {
766
- return I(this.sessionHistoryState);
835
+ return E(this.sessionHistoryState);
767
836
  }
768
837
  subscribeSessionHistory(e) {
769
838
  return this.sessionHistoryListeners.add(e), e(this.getSessionHistoryState()), () => this.sessionHistoryListeners.delete(e);
@@ -774,7 +843,7 @@ class Z {
774
843
  }
775
844
  loadMoreSessionHistory() {
776
845
  const e = this.sessionHistoryState.data?.nextCursor ?? null;
777
- return e ? this.dispatch({ type: "session.list", cursor: e, limit: 20 }).then(() => {
846
+ return e ? this.dispatch({ type: "session.list", cursor: e }).then(() => {
778
847
  }) : Promise.resolve();
779
848
  }
780
849
  setSessionPinned(e, t) {
@@ -791,12 +860,12 @@ class Z {
791
860
  subscribeInteractions(e) {
792
861
  return this.interactionListeners.add(e), e(this.getInteractions()), () => this.interactionListeners.delete(e);
793
862
  }
794
- actOnInteraction(e, t, i, n = {}) {
863
+ actOnInteraction(e, t, s, n = {}) {
795
864
  return this.dispatch({
796
865
  type: "interaction.act",
797
866
  interactionId: e,
798
867
  action: t,
799
- expectedRevision: i,
868
+ expectedRevision: s,
800
869
  ...n
801
870
  }).then(() => {
802
871
  });
@@ -817,11 +886,11 @@ class Z {
817
886
  stageProactiveSuggestionQuestion(e) {
818
887
  const t = e.trim();
819
888
  if (!t) return Promise.resolve();
820
- const i = this.stagedProactiveSuggestionClientMessageId ?? crypto.randomUUID();
821
- return this.stagedProactiveSuggestionClientMessageId = i, this.dispatch({
889
+ const s = this.stagedProactiveSuggestionClientMessageId ?? crypto.randomUUID();
890
+ return this.stagedProactiveSuggestionClientMessageId = s, this.dispatch({
822
891
  type: "conversation.stage_proactive_suggestion",
823
892
  question: t,
824
- clientMessageId: i
893
+ clientMessageId: s
825
894
  }).then(() => {
826
895
  });
827
896
  }
@@ -838,73 +907,73 @@ class Z {
838
907
  ), t;
839
908
  }
840
909
  emit(e, t) {
841
- const i = this.listeners[e];
842
- for (const n of i ?? []) n(t);
910
+ const s = this.listeners[e];
911
+ for (const n of s ?? []) n(t);
843
912
  }
844
913
  }
845
- function q(s, e) {
846
- if (!e || !s) return e;
914
+ function T(i, e) {
915
+ if (!e || !i) return e;
847
916
  const t = /* @__PURE__ */ new Map();
848
- for (const i of s) {
849
- const n = i.previewUrl;
850
- i.id && n && t.set(i.id, n);
917
+ for (const s of i) {
918
+ const n = s.previewUrl;
919
+ s.id && n && t.set(s.id, n);
851
920
  }
852
- return e.map((i) => {
853
- const n = i.id ? t.get(i.id) : void 0;
854
- return n ? { ...i, previewUrl: n } : i;
921
+ return e.map((s) => {
922
+ const n = s.id ? t.get(s.id) : void 0;
923
+ return n ? { ...s, previewUrl: n } : s;
855
924
  });
856
925
  }
857
- function y(s) {
926
+ function A(i) {
858
927
  return {
859
- ...s,
860
- starterPrompts: [...s.starterPrompts],
861
- appearance: s.appearance ? { ...s.appearance } : null,
862
- messages: s.messages.map((e) => {
928
+ ...i,
929
+ starterPrompts: [...i.starterPrompts],
930
+ appearance: i.appearance ? { ...i.appearance } : null,
931
+ messages: i.messages.map((e) => {
863
932
  const t = {
864
933
  ...e,
865
- attachments: e.attachments?.map((a) => ({ ...a }))
866
- }, i = e.assistantDraftItemId, n = e.clientMessageId, r = e.proactiveSuggestionClientMessageId;
867
- return r && Object.defineProperty(t, "proactiveSuggestionClientMessageId", {
868
- value: r,
934
+ attachments: e.attachments?.map((l) => ({ ...l }))
935
+ }, s = e.assistantDraftItemId, n = e.clientMessageId, a = e.proactiveSuggestionClientMessageId;
936
+ return a && Object.defineProperty(t, "proactiveSuggestionClientMessageId", {
937
+ value: a,
869
938
  enumerable: !1
870
- }), i && Object.defineProperty(t, "assistantDraftItemId", {
871
- value: i,
939
+ }), s && Object.defineProperty(t, "assistantDraftItemId", {
940
+ value: s,
872
941
  enumerable: !1
873
942
  }), n && Object.defineProperty(t, "clientMessageId", {
874
943
  value: n,
875
944
  enumerable: !1
876
945
  }), t;
877
946
  }),
878
- activeScheduledFollowUps: s.activeScheduledFollowUps?.map((e) => ({ ...e })) ?? null
947
+ activeScheduledFollowUps: i.activeScheduledFollowUps?.map((e) => ({ ...e })) ?? null
879
948
  };
880
949
  }
881
- function I(s) {
950
+ function E(i) {
882
951
  return {
883
- ...s,
884
- data: s.data ? p({
885
- entities: _(s.data).map((e) => ({ ...e })),
886
- nextCursor: s.data.nextCursor
952
+ ...i,
953
+ data: i.data ? m({
954
+ entities: k(i.data).map((e) => ({ ...e })),
955
+ nextCursor: i.data.nextCursor
887
956
  }) : null
888
957
  };
889
958
  }
890
959
  export {
891
- U as ProductAgentInteractionManager,
892
- A as ProductAgentQueryController,
893
- Z as ProductAgentRemoteRuntimeClient,
894
- F as ProductAgentSessionHistoryManager,
895
- H as ProductAgentTaskPageTitleController,
896
- N as createLocalStorageInteractionDecisionStorage,
897
- h as createProductAgentQueryState,
898
- j as createProductAgentTaskPageTitleDocument,
899
- k as formatProductAgentTaskPageTitle,
900
- K as hasProductAgentPaidCreditFallback,
901
- V as isProductAgentRuntimeCommand,
902
- P as mergeProductAgentEntityPages,
903
- p as normalizeProductAgentEntityPage,
904
- M as readLocalStorageInteractionDecisions,
905
- $ as reconcileProductAgentSubmissionGate,
906
- z as resolveProductAgentBillingPresentation,
907
- B as resolveProductAgentComposerAction,
908
- Q as resolveProductAgentWidgetPresentation,
909
- _ as selectProductAgentQueryEntities
960
+ G as ProductAgentInteractionManager,
961
+ w as ProductAgentQueryController,
962
+ W as ProductAgentRemoteRuntimeClient,
963
+ H as ProductAgentSessionHistoryManager,
964
+ Z as ProductAgentTaskPageTitleController,
965
+ V as createLocalStorageInteractionDecisionStorage,
966
+ f as createProductAgentQueryState,
967
+ J as createProductAgentTaskPageTitleDocument,
968
+ q as formatProductAgentTaskPageTitle,
969
+ j as hasProductAgentPaidCreditFallback,
970
+ Y as isProductAgentRuntimeCommand,
971
+ O as mergeProductAgentEntityPages,
972
+ m as normalizeProductAgentEntityPage,
973
+ x as readLocalStorageInteractionDecisions,
974
+ B as reconcileProductAgentSubmissionGate,
975
+ F as resolveProductAgentBillingPresentation,
976
+ z as resolveProductAgentComposerAction,
977
+ N as resolveProductAgentWidgetPresentation,
978
+ k as selectProductAgentQueryEntities
910
979
  };